日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

ViewStub延迟加载

發布時間:2023/12/20 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ViewStub延迟加载 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在項目中,難免會遇到這種需求,在程序運行時需要動態根據條件來決定顯示哪個View或某個布局,最通常的想法就是把需要動態顯示的View都先寫在布局中,然后把它們的可見性設為View.GONE,最后在代碼中通過控制View.VISIABLE動態的更改它的可見性。這樣的做法的優點是邏輯簡單而且控制起來比較靈活。但是它的缺點就是,耗費資源,雖然把View的初始可見View.GONE但是在Inflate布局的時候View仍然會被Inflate,也就是說仍然會創建對象,會被實例化,會被設置屬性。也就是說,會耗費內存等資源。

推薦的做法是使用android.view.ViewStub,ViewStub是一個輕量級的View,使用非常簡單:

mViewStub = (ViewStub) this.findViewById(R.id.viewstub);

mViewStub.inflate();

它一個不可見的,不占布局位置,占用資源非常小的控件,相當于一個“占位控件”。使用時可以為ViewStub指定一個布局,在Inflate布局的時候,只有ViewStub會被初始化,然后當ViewStub被設置為可見的時或調用了ViewStub.inflate()的時候,ViewStub所指向的布局就會被inflate實例化,且此布局文件直接將當前ViewStub替換掉,然后ViewStub的布局屬性(layout_margin***、layout_width等)都會傳給它所指向的布局。這樣,就可以使用ViewStub在運行時動態顯示布局,節約內存資源。

下面我們從ViewStub源碼來看下inflate()方法的實現原理:

public View inflate() {final ViewParent viewParent = getParent();if (viewParent != null && viewParent instanceof ViewGroup) {if (mLayoutResource != 0) {final ViewGroup parent = (ViewGroup) viewParent;final LayoutInflater factory;if (mInflater != null) {factory = mInflater;} else {factory = LayoutInflater.from(mContext);}final View view = factory.inflate(mLayoutResource, parent,false);if (mInflatedId != NO_ID) {view.setId(mInflatedId);}final int index = parent.indexOfChild(this);parent.removeViewInLayout(this);final ViewGroup.LayoutParams layoutParams = getLayoutParams();if (layoutParams != null) {parent.addView(view, index, layoutParams);} else {parent.addView(view, index);}mInflatedViewRef = new WeakReference<View>(view);if (mInflateListener != null) {mInflateListener.onInflate(this, view);}return view;} else {throw new IllegalArgumentException("ViewStub must have a valid layoutResource");}} else {throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");}}

我們先從方法的入口開始看:
1、在第2行,首先是得到ViewStub它的父視圖對象。

2、然后在第4行一開始肯定是能進入判斷的,mLayoutResource就是需要inflate的布局資源,然后在第13行填充這個布局資源。

3、然后在第21行,重要的來了,parent.removeViewInLayout(this);這段代碼是什么意思呢?看方法名字就知道了,this是代表ViewStub對象,意思就是把當前ViewStub對象從父視圖中移除了。

4、然后第23~28行,就是得到ViewStub的LayoutParams布局參數對象,如果存在就把它賦給被inflate的布局對象,然后把inflate的布局對象添加到父視圖中。
5、最后返回inflate的布局對象。

好了,源碼解析完畢!!!

從上述可知,當我們第二次調用ViewStub.inflate()方法的時候,因為已經移除了ViewStub對象,在第2、4行,得到的viewParent就為null,此時判斷時候就會走else拋出一個IllegalStateException異常:ViewStub must have a non-null ViewGroup viewParent。

需要注意的幾點:
1.ViewStub之所以常稱之為“延遲化加載”,是因為在教多數情況下,程序無需顯示ViewStub所指向的布局文件,只有在特定的某些較少條件下,此時ViewStub所指向的布局文件才需要被inflate,且此布局文件直接將當前ViewStub替換掉,具體是通過viewStub.infalte()或viewStub.setVisibility(View.VISIBLE)來完成。

2.正確把握住ViewStub的應用場景非常重要,因為使用ViewStub可以優化布局,一般應用在當前布局或控件在用戶使用較少情況下,這樣可以提高性能,節約內存,加快界面渲染。

3.對ViewStub的inflate操作只能進行一次,因為inflate的時候是將它指向的布局實例化并替換掉當前ViewStub本身(由此體現出了ViewStub“占位”性質),一旦替換后,此時原來的布局文件中就沒有ViewStub控件了,因此,如果多次對ViewStub進行infalte,會出現錯誤信息:ViewStub must have a non-null ViewGroup viewParent。

4.3中所講到的ViewStub指向的布局文件解析inflate并替換掉當前ViewStub本身,并不是完全意義上的替換(與include標簽不太一樣),替換時,布局文件的layout params是以ViewStub為準,其他布局屬性是以布局文件自身為準。

5.ViewStub本身是不可見的,對ViewStub.setVisibility(int visibility)與其他View控件不一樣,我們可以從源碼角度來看一下ViewStub.setVisibility()方法的作用:

這個方法意思就是ViewStub的setVisibility()設置成View.VISIBLE或INVISIBLE如果是首次使用,都會自動inflate其指向的布局文件,并替換ViewStub本身,再次使用則是相當于對其指向的布局文件設置可見性。

好了,原理講了那么多,來看看代碼怎么實現吧:
使用了ViewStub的activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.example.viewstub.MainActivity" ><Switchandroid:id="@+id/switch1"android:layout_width="wrap_content"android:layout_height="wrap_content" /><ViewStubandroid:id="@+id/viewstub"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginBottom="10dp"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"android:layout="@layout/hide_layout" /></LinearLayout>

hide_layout.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#00ffff"android:orientation="vertical" ><Buttonandroid:id="@+id/hide_layout_btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="Click me" /> </LinearLayout>

代碼文件:

public class MainActivity extends ActionBarActivity {private ViewStub mViewStub;private Switch mSwitch;private boolean flag = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mViewStub = (ViewStub) this.findViewById(R.id.viewstub);//實例化ViewStubmSwitch = (Switch) findViewById(R.id.switch1);mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {if (isChecked) {if(!flag){mViewStub.inflate();//ViewStub只能被inflate一次,會返回一個填充資源的View對象//mViewStub.setVisibility(View.VISIBLE);)flag = true;}else{mViewStub.setVisibility(View.VISIBLE);}Button mBtn = (Button) findViewById(R.id.hide_layout_btn);//ViewStub被替換的布局內的控件mBtn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(getApplicationContext(), "Click me!",Toast.LENGTH_SHORT).show();}});} else {mViewStub.setVisibility(View.GONE);}}});} }

注:使用ViewStub被替換的布局中的控件,直接findViewById即可。

減少視圖層級merge

<merge />標簽在UI的結構優化中起著非常重要的作用,它可以刪減多余的層級,優化UI。<merge />多用于替換FrameLayout(因為所有的 Activity視圖的根結點都是FrameLayout,如果當前的布局根結點是Framelayout,那么可以用merge替代,減少多余的層級)或者當一個布局 包含另一個時,<merge />標簽消除視圖層次結構中多余的視圖組。例如你的主布局文件是垂直布局,又include引入了一個垂直布局,這是 如果include布局使用的LinearLayout就沒意義了,使用的話反而減慢你的UI渲染。這時可以使用<merge />標簽進行優化。<merge xmlns:android="http://schemas.android.com/apk/res/android"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text=""/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text=""/> </merge>

總結

以上是生活随笔為你收集整理的ViewStub延迟加载的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。