啓動模式javascript
- standard:默認的啓動模式,每次建立都會產生新的實例,誰啓動了該模式的Activity,該Activity就屬於啓動它的Activity的任務棧中
- singleTop:棧頂複用模式,若是新的activity已經位於棧頂,那麼這個Activity不會被重寫建立,同時它的onNewIntent(Intent intent)方法會被調用,經過此方法的參數咱們能夠去除當前請求的信息,該 Activity的實例不在該棧或者不在棧頂 時,其行爲同standard啓動模式
- singleTask:棧內複用模式,若是棧中存在這個Activity的實例就會複用這個Activity,無論它是否位於棧頂,複用時,會將它上面的Activity所有出棧,而且會回調該實例的onNewIntent方法。
- singleInstance:全局惟一模式,具有singleTask模式的全部特性外,與它的區別就是,這種模式下的Activity會單獨佔用一個Task棧,具備全局惟一性,即整個系統中就這麼一個實例,因爲棧內複用的特性,後續的請求均不會建立新的Activity實例,除非這個特殊的任務棧被銷燬了,當複用該實例 會回調onNewIntent方法
Activity的啓動過程 必須掌握的Activity啓動過程html
分別調用onSaveInstanceState(Bundle outState)和
onRestoreInstanceState(Bundle outState) 2個方法保存和恢復狀態。
複製代碼
按Home鍵,再開啓activity. java
- 使用這種start方式啓動的Service的生命週期以下: onCreate()--->onStartCommand()(onStart()方法已過期) ---> onDestory()
- 若是服務已經開啓,不會重複的執行onCreate(), 而是會調用onStart()和onStartCommand()
- 服務中止的時候調用 onDestory()。服務只會被中止一次。
- 特色:一旦服務開啓跟調用者(開啓者)就沒有任何關係了。 開啓者退出了,開啓者掛了,服務還在後臺長期的運行。 開啓者不能調用服務裏面的方法。
- 使用這種start方式啓動的Service的生命週期以下:onCreate() --->onBind()--->onunbind()--->onDestory()
- bind的方式開啓服務,綁定服務,調用者掛了,服務也會跟着掛掉。 綁定者能夠調用服務裏面的方法
一種是使用broadcast,另外一種是使用bindService。android
//new出上邊定義好的BroadcastReceiver
MyBroadCastReceiver yBroadCastReceiver = new MyBroadCastReceiver();
//實例化過濾器並設置要過濾的廣播
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
//註冊廣播
myContext.registerReceiver(smsBroadCastReceiver,intentFilter,
"android.permission.RECEIVE_SMS", null);
複製代碼
直接在Manifest.xml文件的節點中配置廣播接收者web
<receiver android:name=".MyBroadCastReceiver">
<!-- android:priority屬性是設置此接收者的優先級(從-1000到1000) -->
<intent-filter android:priority="20">
<actionandroid:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
複製代碼
- 第一種不是常駐型廣播,也就是說廣播跟隨程序的生命週期。
- 第二種是常駐型,也就是說當應用程序關閉後,若是有信息廣播來,程序也會被系統調用自動運行。
- 無序廣播:全部的接收者都會接收事件,不能夠被攔截,不能夠被修改。
- 有序廣播:按照優先級,一級一級的向下傳遞,接收者能夠修改廣播數據,也能夠終止廣播事件。
ContentProvider的基本使用方法和做用。ContentValue的使用方法,他和HashMap的區別是什麼?數據庫
ContentProvider 是Android系統中提供的專門用戶不一樣應用間進行數據共享的組件,提供了一套標準的接口用來獲取以及操做數據,准許開發者把本身的應用數據根據需求開放給其餘應用進行增刪改查,而無須擔憂直接開放數據庫權限而帶來的安全問題。數組
ContentValue: 存儲數據封裝的HashMap,提供 put、get等方法瀏覽器
2.性能上:
3.選用:
HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全爲目標的HTTP通道,簡單講是HTTP的安全版。
即HTTP下加入SSL (Secure Socket Layer)層,HTTPS的安全基礎是SSL,所以加密的詳細內容就須要SSL。
Android使用OkHttp請求自簽名的https網站 Android Https相關徹底解析 當OkHttp遇到Https HTTPS和HTTP的區別
- public boolean dispatchTouchEvent(MotionEvent ev); //用來分派event
- public boolean onInterceptTouchEvent(MotionEvent ev); //用來攔截event
- public boolean onTouchEvent(MotionEvent ev); //用來處理event
方 法 | 解析 |
---|---|
dispatchTouchEvent() | 用來分派事件。其中調用了onInterceptTouchEvent()和onTouchEvent(),通常不重寫該方法,返回true則表示該事件被消費 |
onInterceptTouchEvent() | 用來攔截事件。ViewGroup類中的源碼實現就是{return false;}表示不攔截該事件,事件將向下傳遞(傳遞給其子View);若手動重寫該方法,使其返回true則表示攔截,事件將終止向下傳遞,事件由當前ViewGroup類來處理,就是調用該類的onTouchEvent()方法 |
onTouchEvent() | 用來處理事件。返回true則表示該View能處理該事件,事件將終止向上傳遞(傳遞給其父View);返回false表示不能處理,則把事件傳遞給其父View的onTouchEvent()方法來處理 |
Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()
Android3.0以前有2種,3.0後有3種。
複製代碼
注1:AnimationSet 繼承自Animation,是上面四種的組合容器管理類,沒有本身特有的屬性,他的屬性繼承自Animation,因此特別注意,當咱們對set標籤使用Animation的屬性時會對該標籤下的全部子控件都產生影響。
注2:補間動畫執行以後並未改變View的真實佈局屬性值。切記這一點,譬如咱們在Activity中有一個Button在屏幕上方,咱們設置了平移動畫移動到屏幕下方而後保持動畫最後執行狀態呆在屏幕下方,這時若是點擊屏幕下方動畫執行以後的Button是沒有任何反應的,而點擊原來屏幕上方沒有Button的地方卻響應的是點擊Button的事件。
ObjectAnimator mObjectAnimator= ObjectAnimator.ofInt(view, "customerDefineAnyThingName", 0, 1).setDuration(2000);
mObjectAnimator.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
//int value = animation.getAnimatedValue(); 能夠獲取當前屬性值
//view.postInvalidate(); 能夠主動刷新
//view.setXXX(value);
//view.setXXX(value);
//......能夠批量修改屬性
}
});
複製代碼
ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f).setDuration(1000).start();
複製代碼
PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start();
複製代碼
ValueAnimator animator = ValueAnimator.ofFloat(0, mContentHeight); //定義動畫
animator.setTarget(view); //設置做用目標
animator.setDuration(5000).start();
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation){
float value = (float) animation.getAnimatedValue();
view.setXXX(value); //必須經過這裏設置屬性值纔有效
view.mXXX = value; //不須要setXXX屬性方法
}
});
複製代碼
特別注意:ValueAnimator只是動畫計算管理驅動,設置了做用目標,但沒有設置屬性,須要經過updateListener裏設置屬性纔會生效。
android系統中應用程序之間不能共享內存。 所以,在不一樣應用程序之間交互數據(跨進程通信)就稍微麻煩一些
如調用系統通話應用
Intent callIntent=new Intent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
startActivity(callIntent);
複製代碼
Content Provider提供了一種在多個應用程序之間數據共享的方式(跨進程共享數據)。應用程序能夠利用Content Provider完成下面的工做
雖然Content Provider也能夠在同一個應用程序中被訪問,但這麼作並無什麼意義。Content Provider存在的目的向其餘應用程序共享數據和容許其餘應用程序對數據進行增、刪、改操做。 Android系統自己提供了不少Content Provider,例如,音頻、視頻、聯繫人信息等等。咱們能夠經過這些Content Provider得到相關信息的列表。這些列表數據將以Cursor對象返回。所以,從Content Provider返回的數據是二維表的形式。
如訪問系統相冊
複製代碼
廣播是一種被動跨進程通信的方式。當某個程序向系統發送廣播時,其餘的應用程序只能被動地接收廣播數據。這就象電臺進行廣播同樣,聽衆只能被動地收聽,而不能主動與電臺進行溝通。例如獲取手機電量信息
複製代碼
一、定義:Android系統中的進程之間不能共享內存,所以,須要提供一些機制在不一樣進程之間進行數據通訊。 爲了使其餘的應用程序也能夠訪問本應用程序提供的服務,Android系統採用了遠程過程調用(Remote Procedure Call,RPC)方式來實現。與不少其餘的基於RPC的解決方案同樣,Android使用一種接口定義語言(Interface Definition Language,IDL)來公開服務的接口。咱們知道4個Android應用程序組件中的3個(Activity、BroadcastReceiver和ContentProvider)均可以進行跨進程訪問,另一個Android應用程序組件Service一樣能夠。所以,能夠將這種能夠跨進程訪問的服務稱爲AIDL(Android Interface Definition Language)服務。
Binder是Android實現 跨進程通信(IPC)的方式,是一種虛擬的物理設備驅動,實現了IBindler 接口。
區別:
- 進程間,用戶空間的數據不可共享,因此用戶空間 = 不可共享空間
- 進程間,內核空間的數據可共享,因此內核空間 = 可共享空間
對比 Linux (Android基於Linux)上的其餘進程通訊方式(管道、消息隊列、共享內存、 信號量、Socket),Binder 機制的優勢有:
做用:Handle 進行消息傳遞
思路:Andorid APP默認的類加載是PathClassLoader,這個只能加載本身APK的dex文件,因此咱們須要使用DexClassLoader。咱們用DexClassLoader加載外部的APK以後,經過反射獲取對應的資源。
緩存層分爲三層:內存層,磁盤層,網絡層
public class AppSettings {
private static AppSettings sInstance;
private Context mContext;
private AppSettings(Context context) {
this.mContext = context;
//this.mContext = context.getApplicationContext();
}
public static AppSettings getInstance(Context context) {
if (sInstance == null) {
sInstance = new AppSettings(context);
}
return sInstance;
}
}
複製代碼
二、靜態變量致使內存泄露
public class MainActivity extends AppCompatActivity {
private static Info sInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (sInfo != null) {
sInfo = new Info(this);
}
}
}
class Info {
public Info(Activity activity) {
}
}
複製代碼
Info做爲Activity的靜態成員,而且持有Activity的引用,可是sInfo做爲靜態變量,生命週期確定比Activity長。因此當Activity退出後,sInfo仍然引用了Activity,Activity不能被回收,這就致使了內存泄露。
三、非靜態內部類致使內存泄露
非靜態內部類(包括匿名內部類)默認就會持有外部類的引用,當非靜態內部類對象的生命週期比外部類對象的生命週期長時,就會致使內存泄露。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start();
}
private void start() {
Message msg = Message.obtain();
msg.what = 1;
mHandler.sendMessage(msg);
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
// 作相應邏輯
}
}
};
}
複製代碼
熟悉Handler消息機制的都知道,mHandler會做爲成員變量保存在發送的消息msg中,即msg持有mHandler的引用,而mHandler是Activity的非靜態內部類實例,即mHandler持有Activity的引用,那麼咱們就能夠理解爲msg間接持有Activity的引用。msg被髮送後先放到消息隊列MessageQueue中,而後等待Looper的輪詢處理(MessageQueue和Looper都是與線程相關聯的,MessageQueue是Looper引用的成員變量,而Looper是保存在ThreadLocal中的)。那麼當Activity退出後,msg可能仍然存在於消息對列MessageQueue中未處理或者正在處理,那麼這樣就會致使Activity沒法被回收,以至發生Activity的內存泄露。
一般在Android開發中若是要使用內部類,但又要規避內存泄露,通常都會採用靜態內部類+弱引用的方式。
public class MainActivity extends AppCompatActivity {
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new MyHandler(this);
start();
}
private void start() {
Message msg = Message.obtain();
msg.what = 1;
mHandler.sendMessage(msg);
}
private static class MyHandler extends Handler {
private WeakReference<MainActivity> activityWeakReference;
public MyHandler(MainActivity activity) {
activityWeakReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = activityWeakReference.get();
if (activity != null) {
if (msg.what == 1) {
// 作相應邏輯
}
}
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
複製代碼
非靜態內部類形成內存泄露還有一種狀況就是使用Thread或者AsyncTask
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
// 模擬相應耗時邏輯
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
複製代碼
這種方式新建的子線程Thread和AsyncTask都是匿名內部類對象,默認就隱式的持有外部Activity的引用,致使Activity內存泄露。
四、未取消註冊或回調致使內存泄露
五、Timer和TimerTask致使內存泄露
六、集合中的對象未清理形成內存泄露
若是一個對象放入到ArrayList、HashMap等集合中,這個集合就會持有該對象的引用。當咱們再也不須要這個對象時,也並無將它從集合中移除,這樣只要集合還在使用(而此對象已經無用了),這個對象就形成了內存泄露。而且若是集合被靜態引用的話,集合裏面那些沒有用的對象更會形成內存泄露了。因此在使用集合時要及時將不用的對象從集合remove,或者clear集合,以免內存泄漏。
七、資源未關閉或釋放致使內存泄露
在使用IO、File流或者Sqlite、Cursor等資源時要及時關閉。這些資源在進行讀寫操做時一般都使用了緩衝,若是及時不關閉,這些緩衝對象就會一直被佔用而得不到釋放,以至發生內存泄露。所以咱們在不須要使用它們的時候就及時關閉,以便緩衝能及時獲得釋放,從而避免內存泄露。
八、屬性動畫形成內存泄露
動畫一樣是一個耗時任務,好比在Activity中啓動了屬性動畫(ObjectAnimator),可是在銷燬的時候,沒有調用cancle方法,雖然咱們看不到動畫了,可是這個動畫依然會不斷地播放下去,動畫引用所在的控件,所在的控件引用Activity,這就形成Activity沒法正常釋放。所以一樣要在Activity銷燬的時候cancel掉屬性動畫,避免發生內存泄漏。
@Override
protected void onDestroy() {
super.onDestroy();
mAnimator.cancel();
}
複製代碼
九、WebView形成內存泄露
關於WebView的內存泄露,由於WebView在加載網頁後會長期佔用內存而不能被釋放,所以咱們在Activity銷燬後要調用它的destory()方法來銷燬它以釋放內存。
@Override
protected void onDestroy() {
super.onDestroy();
// 先從父控件中移除WebView
mWebViewContainer.removeView(mWebView);
mWebView.stopLoading();
mWebView.getSettings().setJavaScriptEnabled(false);
mWebView.clearHistory();
mWebView.removeAllViews();
mWebView.destroy();
}
複製代碼
十、總結
1).資源對象沒關閉形成的內存泄漏 2).構造Adapter時,沒有使用緩存的convertView 3).Bitmap對象不在使用時調用recycle()釋放內存 4).試着使用關於application的context來替代和activity相關的context 5).註冊沒取消形成的內存泄漏 6).集合中對象沒清理形成的內存泄漏
查找內存泄漏可使用Android Stdio 自帶的Android Profiler工具,也可使用Square產品的LeadCanary.
webView.loadUrl("javascript:javacalljs()");
複製代碼
二、Html
**注意:**考慮有返回值狀況;Android在4.4以前並無提供直接調用js函數並獲取值的方法,因此在此以前,經常使用的思路是 java調用js方法,js方法執行完畢,再次調用java代碼將值返回。
// 4.4以後 java代碼時用evaluateJavascript方法調用
private void testEvaluateJavascript(WebView webView) {
webView.evaluateJavascript("getGreetings()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.i(LOGTAG, "onReceiveValue value=" + value);
}});
}
複製代碼
webView.addJavascriptInterface(MainActivity.this,"android");
複製代碼
二、html
<body>
HTML 內容顯示 <br/>
<h1><div id="content">內容顯示</div></h1><br/>
<input type="button" value="點擊調用java代碼" onclick="window.android.startFunction()" /><br/>
<input type="button" value="點擊調用java代碼並傳遞參數" onclick="window.android.startFunction('http://blog.csdn.net/Leejizhou')" />
</body>
複製代碼
//懶漢式
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static synchronized Singleton getSingleton() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
複製代碼
//餓漢式
public class Singleton {
private static final Singleton singleton = new Singleton();
private Singleton () {
}
public static Singleton getSingleton() {
return singleton;
}
}
複製代碼
//double-lock
public class Singleton {
private volatile static Singleton singleton;
private Singleton() {
}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized(Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
複製代碼
在Android上,若是你的應用程序有一段時間響應不夠靈敏,系統會向用戶顯示一個對話框,這個對話框稱做應用程序無響應(ANR:Application Not Responding)對話框。
ANR產生的根本緣由是APP阻塞了UI線程
1:UI線程儘可能只作跟UI相關的工做,但一些複雜的UI操做,仍是須要一些技巧來處理,不如你讓一個Button去setText一個10M的文本,UI確定崩掉了,不過對於此類問題,分段加載貌似是最好的方法了。 2:讓耗時的工做(好比數據庫操做,I/O,鏈接網絡或者別的有可能阻礙UI線程的操做)把它放入單獨的線程處理。 3:儘可能用Handler來處理UIthread和別的thread之間的交互。
一、 Activity類中的getPreferences(int mode)文件自動命名爲當前活動的類名。
二、 Context類中getSharedPreferences("fileName", int mode) 此方法能夠指定文件名,mode同上。
三、PreferenceManager類中的getDefaultSharedPreferences(Context context)它只接收一個context參數。
文件用當前應用程序的包名和PreferenceActivity一塊兒來命名。屬於整個應用程序
複製代碼
用戶當前正在作的事情須要這個進程。若是知足下面的條件之一,一個進程就被認爲是前臺進程: 1).這個進程擁有一個正在與用戶交互的Activity(這個Activity的onResume()方法被調用)。 2).這個進程擁有一個綁定到正在與用戶交互的activity上的Service。 3).這個進程擁有一個前臺運行的Service(service調用了方法startForeground()). 4).這個進程擁有一個正在執行其任何一個生命週期回調方法(onCreate(),onStart(),或onDestroy())的Service。 5).這個進程擁有正在執行其onReceive()方法的BroadcastReceiver。 一般,在任什麼時候間點,只有不多的前臺進程存在。它們只有在達到沒法調合的矛盾時纔會被殺--如內存過小而不能繼續運行時。一般,到了這時,設備就達到了一個內存分頁調度狀態,因此須要殺一些前臺進程來保證用戶界面的反應.
一個進程不擁有運行於前臺的組件,可是依然能影響用戶所見。知足下列條件時,進程即爲可見: 這個進程擁有一個不在前臺但仍可見的Activity(它的onPause()方法被調用)。當一個前臺activity啓動一個對話框時,就出了這種狀況。
一個可見進程被認爲是極其重要的。而且,除非只有殺掉它才能夠保證全部前臺進程的運行,不然是不能動它的。 這個進程擁有一個綁定到可見activity的Service。 一個進程不在上述兩種以內,但它運行着一個被startService()所啓動的service。 儘管一個服務進程不直接影響用戶所見,可是它們一般作一些用戶關心的事情(好比播放音樂或下載數據),因此係統不到前臺進程和可見進程活不下去時不會殺它。
一個進程擁有一個當前不可見的activity(activity的onStop()方法被調用)。
一個進程不擁有任何active組件。
Android中的線程池都是之間或間接經過配置ThreadPoolExecutor來實現不一樣特性的線程池.Android中最多見的四類具備不一樣特性的線程池分別爲FixThreadPool、CachedThreadPool、SingleThreadPool、ScheduleThreadExecutor.
**FixThreadPool: **只有核心線程,而且數量固定的,也不會被回收,全部線程都活動時,由於隊列沒有限制大小,新任務會等待執行. 優勢:更快的響應外界請求.
**SingleThreadPool:**只有一個核心線程,確保全部的任務都在同一線程中按順序完成.所以不須要處理線程同步的問題.
**CachedThreadPool:**只有非核心線程,最大線程數很是大,全部線程都活動時,會爲新任務建立新線程,不然會利用空閒線程(60s空閒時間,過了就會被回收,因此線程池中有0個線程的可能)處理任務. 優勢:任何任務都會被當即執行(任務隊列SynchronousQueue至關於一個空集合);比較適合執行大量的耗時較少的任務.
**ScheduleThreadExecutor:**核心線程數固定,非核心線程(閒着沒活幹會被當即回收)數沒有限制. 優勢:執行定時任務以及有固定週期的重複任務
一、計算一張圖片的大小
圖片佔用內存的計算公式:圖片高度 * 圖片寬度 * 一個像素佔用的內存大小.因此,計算圖片佔用內存大小的時候,要考慮圖片所在的目錄跟設備密度,這兩個因素其實影響的是圖片的高寬,android會對圖片進行拉昇跟壓縮。
二、加載bitmap過程(怎樣保證不產生內存溢出)
因爲Android對圖片使用內存有限制,如果加載幾兆的大圖片便內存溢出。
Bitmap會將圖片的全部像素(即長x寬)加載到內存中,若是圖片分辨率過大,會直接致使內存OOM,只有在BitmapFactory加載圖片時使用BitmapFactory.Options對相關參數進行配置來減小加載的像素。
三、BitmapFactory.Options相關參數詳解
(1).Options.inPreferredConfig值來下降內存消耗。
好比:默認值ARGB_8888改成RGB_565,節約一半內存。
(2).設置Options.inSampleSize 縮放比例,對大圖片進行壓縮 。
(3).設置Options.inPurgeable和inInputShareable:讓系統能及時回 收內存。
A:inPurgeable:設置爲True時,表示系統內存不足時能夠被回 收,設置爲False時,表示不能被回收。
B:inInputShareable:設置是否深拷貝,與inPurgeable結合使用,inPurgeable爲false時,該參數無心義。
(4).使用decodeStream代替其餘方法。
decodeResource,setImageResource,setImageBitmap等方法
複製代碼
**LRUCache算法:**內部存在一個LinkedHashMap和maxSize,把最近使用的對象用強引用存儲在 LinkedHashMap中,給出來put和get方法,每次put圖片時計算緩存中全部圖片總大小,跟maxSize進行比較,大於maxSize,就將最久添加的圖片移除;反之小於maxSize就添加進來。(400行代碼不到...)
六、layout、Merge、ViewStub的做用。
merge: 它能夠刪減多餘的層級,優化UI。例如你的主佈局文件是垂直佈局,引入了一個垂直佈局的include,這是若是include佈局使用的LinearLayout就沒意義了,使用的話反而減慢你的UI表現。這時可使用標籤優化。
ViewStub: 標籤最大的優勢是當你須要時纔會加載,使用他並不會影響UI初始化時的性能。各類不經常使用的佈局想進度條、顯示錯誤消息等可使用標籤,以減小內存使用量,加快渲染速度。是一個不可見的,大小爲0的View。