精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Android后臺殺死系列之一:FragmentActivity及PhoneWindow后臺殺死處理機制

移動開發(fā) Android
本篇是Android后臺殺死系列的第一篇,主要講解在開發(fā)過程中,由于后臺殺死涉及的一些崩潰,以及如何避免這些崩潰,還有就是簡單的介紹一下onSaveInstanceState與onRestoreInstanceState執(zhí)行時機與原理,這兩個函數(shù)也是Android面試時常問的兩個點,是比簡單的啟動模式Activity聲明周期稍微更深入細致一些的地方,也通過這個點引入后臺殺死及恢復原理。

  

App在后臺久置后,再次從桌面或最近的任務列表喚醒時經(jīng)常會發(fā)生崩潰,這往往是App在后臺被系統(tǒng)殺死,再次恢復的時候遇到了問題,而在使用FragmentActivity+Fragment的時候會更加頻繁。比如,如果Fragment沒有提供默認構造方法,就會在重建的時候因為反射創(chuàng)建Fragment失敗而崩潰,再比如,在onCreate里面new 一個FragmentDialog,并且show,被后臺殺死后,再次喚醒的時候,就會show兩個對話框,這是為什么?其實這就涉及了后臺殺死及恢復的機制,其中涉及的知識點主要是FragmentActivity、ActivityManagerService、LowMemoryKiller機制、ActivityStack、Binder等一系列知識點。放在一篇文章里面可能會有些長,因此,Android后臺殺死系列寫了三篇:

  • 開篇:FragmentActivity及PhoneWindow后臺殺死處理機制
  • 原理篇1:后臺殺死與LowmemoryKiller(主要講述App被后臺殺死的原理)
  • 原理篇2:后臺殺死與App現(xiàn)場恢復(主要講述AMS如何為App恢復現(xiàn)場的原理)

本篇是Android后臺殺死系列的第一篇,主要講解在開發(fā)過程中,由于后臺殺死涉及的一些崩潰,以及如何避免這些崩潰,還有就是簡單的介紹一下onSaveInstanceState與onRestoreInstanceState執(zhí)行時機與原理,這兩個函數(shù)也是Android面試時常問的兩個點,是比簡單的啟動模式Activity聲明周期稍微更深入細致一些的地方,也通過這個點引入后臺殺死及恢復原理。

FragmentActivity被后臺殺死后恢復邏輯

當App被后臺異常殺死后,再次點擊icon,或者從最近任務列表進入的時候,系統(tǒng)會幫助恢復當時的場景,重新創(chuàng)建Activity,對于FragmentActivity,由于其中有Framgent,邏輯會相對再復雜一些,系統(tǒng)會首先重建被銷毀的Fragment。

舉個栗子

我們創(chuàng)建一個Activity,并且在onCreate函數(shù)中新建并show一個DialogFragment,之后通過某種方式將APP異常殺死(RogueKiller模擬后臺殺死工具),再次從最近的任務喚起App的時候,會發(fā)現(xiàn)顯示了兩個DialogFragment,代碼如下:

  1. public class DialogFragmentActivity extends AppCompatActivity { 
  2.  
  3.     @Override 
  4.     protected void onCreate(Bundle savedInstanceState) { 
  5.         super.onCreate(savedInstanceState); 
  6.         DialogFragment dialogFragment = new FragmentDlg(); 
  7.         dialogFragment.show(getSupportFragmentManager(), ""); 
  8.     }  

這不僅讓我們奇怪,為什么呢?雖然被殺死了,但是onCreate函數(shù)在執(zhí)行的時候還是只執(zhí)行了一次啊,為什么會出現(xiàn)兩個DialogFragment,這里其實就有一個DialogFragment是通過Android自身的恢復重建機制重建出來,在異常殺死的情況下onCreate(Bundle savedInstanceState)函數(shù)的savedInstanceState參數(shù)也不是null,而是包含了被殺死時所保存的場景信息。再來看個崩潰的例子,新建一個CrashFragment,并且丟棄默認無參構造方法:

  1. public class CrashFragment extends Fragment { 
  2.  
  3.     public CrashFragment(String tag) { 
  4.         super(); 
  5.     } 
  6.  

之后再Activity中Add或replace添加這個CrashFragment,在CrashFragment顯示后,通過RogueKiller模擬后臺殺死工具模擬后臺殺死,再次從最近任務列表里喚起App的時候,就會遇到崩潰,

  1. Caused by: android.support.v4.app.Fragment$InstantiationException:  
  2.   Unable to instantiate fragment xxx.CrashFragment:  
  3.   make sure class name exists, is publicand has an empty constructor that is public 
  4.         at android.support.v4.app.Fragment.instantiate(Fragment.java:431) 
  5.         at android.support.v4.app.FragmentState.instantiate(Fragment.java:102) 
  6.         at android.support.v4.app.FragmentManagerImpl.restoreAllState(FragmentManager.java:1952) 
  7.         at android.support.v4.app.FragmentController.restoreAllState(FragmentController.java:144) 
  8.         at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:307) 
  9.         at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:81)  

上面的這兩個問題主要涉及后臺殺死后FragmentActivity自身的恢復機制,其實super.onCreate(savedInstanceState)在恢復時做了很多我們沒有看到的事情,先看一下崩潰:

為什么Fragment沒有無參構造方法會引發(fā)崩潰

看一下support-V4中FragmentActivity中onCreate代碼如下: 

  1. protected void onCreate(@Nullable Bundle savedInstanceState) { 
  2.     mFragments.attachHost(null /*parent*/); 
  3.  
  4.     super.onCreate(savedInstanceState); 
  5.                     ... 
  6.     if (savedInstanceState != null) { 
  7.         Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG); 
  8.         mFragments.restoreAllState(p, nc != null ? nc.fragments : null); 
  9.     } 
  10.     mFragments.dispatchCreate(); 
  11.  

可以看到如果savedInstanceState != null,就會執(zhí)行mFragments.restoreAllState邏輯,其實這里就牽扯到恢復時重建邏輯,再被后臺異常殺死前,或者說在Activity的onStop執(zhí)行前,Activity的現(xiàn)場以及Fragment的現(xiàn)場都是已經(jīng)被保存過的,其實是被保存早ActivityManagerService中,保存的格式FragmentState,重建的時候,會采用反射機制重新創(chuàng)Fragment

  1. void restoreAllState(Parcelable state, List<Fragment> nonConfig) { 
  2.   
  3.       ... 
  4.          for (int i=0; i<fms.mActive.length; i++) { 
  5.         FragmentState fs = fms.mActive[i]; 
  6.         if (fs != null) { 
  7.             Fragment f = fs.instantiate(mHost, mParent); 
  8.             mActive.add(f); 
  9.     ...  

其實就是調用FragmentState的instantiate,進而調用Fragment的instantiate,最后通過反射,構建Fragment,也就是,被加到FragmentActivity的Fragment在恢復的時候,會被自動創(chuàng)建,并且采用Fragment的默認無參構造方法,如果沒喲這個方法,就會拋出InstantiationException異常,這也是為什么第二個例子中會出現(xiàn)崩潰的原因。

  1. public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) { 
  2.     try { 
  3.         Class<?> clazz = sClassMap.get(fname); 
  4.         if (clazz == null) { 
  5.             // Class not found in the cache, see if it's realand try to add it 
  6.             clazz = context.getClassLoader().loadClass(fname); 
  7.             sClassMap.put(fname, clazz); 
  8.         } 
  9.         Fragment f = (Fragment)clazz.newInstance(); 
  10.         if (args != null) { 
  11.             args.setClassLoader(f.getClass().getClassLoader()); 
  12.             f.mArguments = args; 
  13.         } 
  14.         return f; 
  15.     } catch (ClassNotFoundException e) { 
  16.         throw new InstantiationException("Unable to instantiate fragment " + fname 
  17.                 + ": make sure class name exists, is public, and has an" 
  18.                 + " empty constructor that is public", e); 
  19.     } catch (java.lang.InstantiationException e) { 
  20.         throw new InstantiationException("Unable to instantiate fragment " + fname 
  21.                 + ": make sure class name exists, is public, and has an" 
  22.                 + " empty constructor that is public", e); 
  23.     } catch (IllegalAccessException e) { 
  24.         throw new InstantiationException("Unable to instantiate fragment " + fname 
  25.                 + ": make sure class name exists, is public, and has an" 
  26.                 + " empty constructor that is public", e); 
  27.     } 
  28.  

可以看到場景二提示的errormsg跟拋出的異常是可以對應上的,其實Fragment源碼里面也說得很清楚:

  1.  /** 
  2.  * Default constructor.  <strong>Every</strong> fragment must have an 
  3.  * empty constructor, so it can be instantiated when restoring its 
  4.  * activity's state.  It is strongly recommended that subclasses do not 
  5.  * have other constructors with parameters, since these constructors 
  6.  * will not be called when the fragment is re-instantiated; instead
  7.  * arguments can be supplied by the caller with {@link #setArguments} 
  8.  * and later retrieved by the Fragment with {@link #getArguments}. 
  9.  *  
  10.  * <p>Applications should generally not implement a constructor.  The 
  11.  * first place application code an run where the fragment is ready to 
  12.  * be used is in {@link #onAttach(Activity)}, the point where the fragment 
  13.  * is actually associated with its activity.  Some applications may also 
  14.  * want to implement {@link #onInflate} to retrieve attributes from a 
  15.  * layout resource, though should take care here because this happens for 
  16.  * the fragment is attached to its activity. 
  17.  */ 
  18.   
  19. public Fragment() { 
  20.  

大意就是,F(xiàn)ragment必須有一個空構造方法,這樣才能保證重建流程,并且,F(xiàn)ragment的子類也不推薦有帶參數(shù)的構造方法,最好采用setArguments來保存參數(shù)。下面再來看下為什么會出現(xiàn)兩個DialogFragment。

為什么出現(xiàn)兩個DialogFragment

Fragment在被創(chuàng)建之后,如果不通過add或者replace添加到Activity的布局中是不會顯示的,在保存現(xiàn)場的時候,也是保存了add的這個狀態(tài)的,來看一下Fragment的add邏輯:此時被后臺殺死,或旋轉屏幕,被恢復的DialogFragmentActivity時會出現(xiàn)兩個FragmentDialog,一個被系統(tǒng)恢復的,一個新建的。

Add一個Fragment,并顯示的原理--所謂Fragment生命周期

通常我們FragmentActivity使用Fragment的方法如下:假設是在oncreate函數(shù)中:

  1. @Override 
  2. protected void onCreate(Bundle savedInstanceState) { 
  3.         super.onCreate(savedInstanceState); 
  4.         Fragment fr = Fragment.instance(""
  5.         getSupportFragmentManager().beginTransaction() 
  6.         .add(R.id.container,fr).commit();  

其中getSupportFragmentManager返回的是FragmentManager的子類FragmentManagerImpl,F(xiàn)ragmentManagerImpl是FragmentActivity的一個內(nèi)部類,其Fragment的管理邏輯都是由FragmentManagerImpl來處理的,本文是基于4.3,后面的高版本引入了FragmentController其實也只是多了一層封裝,原理差別不是太大,有興趣可以自己分析:

  1. public class FragmentActivity extends Activity{ 
  2.     ... 
  3.     final FragmentManagerImpl mFragments = new FragmentManagerImpl(); 
  4.    ... 
  5.     final FragmentContainer mContainer = new FragmentContainer() { 
  6.         @Override 
  7.         @Nullable 
  8.         public View findViewById(int id) { 
  9.             return FragmentActivity.this.findViewById(id); 
  10.         } 
  11.  
  12.         @Override 
  13.         public boolean hasView() { 
  14.             Window window = FragmentActivity.this.getWindow(); 
  15.             return (window != null && window.peekDecorView() != null); 
  16.         } 
  17.     };  

FragmentManagerImpl的beginTransaction()函數(shù)返回的是一個BackStackRecord()

  1. @Override 
  2. public FragmentTransaction beginTransaction() { 
  3.     return new (this); 

從名字就可以看出,beginTransaction是為FragmentActivity生成一條Transaction(事務),可以執(zhí)行,也可以反向,作為退棧的一個依據(jù),F(xiàn)ragmentTransaction的add函數(shù)實現(xiàn)如下,

  1. public FragmentTransaction add(Fragment fragment, String tag) { 
  2.     doAddOp(0, fragment, tag, OP_ADD);//異步操作的,跟Hander類似 
  3.     return this; 
  4.  
  1. private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) { 
  2.     fragment.mFragmentManager = mManager; 
  3.      ... 
  4.     Op op = new Op(); 
  5.     op.cmd = opcmd; 
  6.     op.fragment = fragment; 
  7.     addOp(op); 
  8.  

之后commit這個Transaction, 將Transaction插入到Transaction隊列中去,最終會回調FragmentManager的addFragment方法,將Fragment添加FragmentManagerImpl到維護Fragment列表中去,并且根據(jù)當前的Activity狀態(tài),將Fragment調整到合適的狀態(tài),代碼如下:

  1. public void addFragment(Fragment fragment, boolean moveToStateNow) { 
  2.  
  3.     if (mAdded == null) { 
  4.         mAdded = new ArrayList<Fragment>(); 
  5.     } 
  6.  
  7.     makeActive(fragment); 
  8.      
  9.     if (!fragment.mDetached) { 
  10.         if (mAdded.contains(fragment)) { 
  11.             throw new IllegalStateException("Fragment already added: " + fragment); 
  12.         } 
  13.         mAdded.add(fragment); 
  14.         fragment.mAdded = true
  15.         fragment.mRemoving = false
  16.         if (fragment.mHasMenu && fragment.mMenuVisible) { 
  17.             mNeedMenuInvalidate = true
  18.         } 
  19.         if (moveToStateNow) { 
  20.             moveToState(fragment); 
  21.         } 
  22.     } 
  23. }    

為什么說FragmentManager是FragmentActivity管理Fragment的核心呢,請看下面:

  1. final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory { 
  2.     ... 
  3.      
  4.     ArrayList<Runnable> mPendingActions; 
  5.     Runnable[] mTmpActions; 
  6.     boolean mExecutingActions; 
  7.      
  8.     ArrayList<Fragment> mActive; 
  9.     ArrayList<Fragment> mAdded; 
  10.     ArrayList<Integer> mAvailIndices; 
  11.     ArrayList<BackStackRecord> mBackStack; 
  12.    

可以看出FragmentManagerImpl幫FragmentActivity維護著所有管理Fragment的列表,F(xiàn)ragmentManagerImpl的State是和Activity的State一致的,這是管理Fragment的關鍵。其實Fragment自身是沒有什么生命周期的,它只是一個View的封裝,完全依靠FragmentManagerImpl來進行同步模擬生命周期,比如在onCreate函數(shù)中創(chuàng)建Fragment,add后,在執(zhí)行的到Activity自身的onCreateView之前,F(xiàn)ragment的onCreateView是不會執(zhí)行的,也就是Fragment是被動式的跟FragmentActivity保持一致。既然Fragment只是個View的封裝,那么它是如何轉換成View,并添加到Container中去的呢?關鍵是moveToState函數(shù),這個函數(shù)強制將新add的Fragment的生命周期與Activity同步:

  1. void moveToState(Fragment f, int newState, int transit, int transitionStyle, 
  2.         boolean keepActive) { 
  3.         ...         
  4.      if (f.mState < newState) { //低于當前Activity的狀態(tài) 
  5.         switch (f.mState) { 
  6.             case Fragment.INITIALIZING: 
  7.                     ... 
  8.                 f.mActivity = mActivity; 
  9.                 f.mParentFragment = mParent; 
  10.                 f.mFragmentManager = mParent != null 
  11.                         ? mParent.mChildFragmentManager : mActivity.mFragments; 
  12.                 f.mCalled = false
  13.                 f.onAttach(mActivity); 
  14.                ... 
  15.                 if (!f.mRetaining) { 
  16.                     f.performCreate(f.mSavedFragmentState); 
  17.                 }  
  18.             case Fragment.CREATED: 
  19.                 if (newState > Fragment.CREATED) { 
  20.              
  21.                       f.mView = f.performCreateView(f.getLayoutInflater( 
  22.                       f.mSavedFragmentState), container, f.mSavedFragmentState); 
  23.                       f.onViewCreated(f.mView, f.mSavedFragmentState); 
  24.                   
  25.                     f.performActivityCreated(f.mSavedFragmentState); 
  26.                     if (f.mView != null) { 
  27.                         f.restoreViewState(f.mSavedFragmentState); 
  28.                     } 
  29.                     f.mSavedFragmentState = null
  30.                 } 
  31.             case Fragment.ACTIVITY_CREATED: 
  32.             case Fragment.STOPPED: 
  33.                     if (newState > Fragment.STOPPED) { 
  34.                         f.performStart(); 
  35.                     } 
  36.             case Fragment.STARTED: 
  37.                 if (newState > Fragment.STARTED) { 
  38.                       f.mResumed = true
  39.                     f.performResume();  

可以看出,add Fragment之后,需要讓Fragment跟當前Activity的State保持一致。現(xiàn)在回歸正題,對于后臺殺死狀態(tài)下,為什么會show兩個DialogFragment呢,我們需要接著看就要Fragment的異常處理的流程,在Fragment沒有無參構造方法會引發(fā)崩潰里面,分析只是走到了Fragment的構建,現(xiàn)在接著往下走。提供無參構造函數(shù)后,F(xiàn)ragment可以正確的新建出來,之后呢?之后就是一些恢復邏輯,接著看restoreAllState

  1. void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) { 
  2.  
  3.     if (state == nullreturn
  4.     FragmentManagerState fms = (FragmentManagerState)state; 
  5.     mActive = new ArrayList<Fragment>(fms.mActive.length); 
  6.      for (int i=0; i<fms.mActive.length; i++) { 
  7.         FragmentState fs = fms.mActive[i]; 
  8.         if (fs != null) { 
  9.             Fragment f = fs.instantiate(mActivity, mParent); 
  10.  
  11.             mActive.add(f); 
  12.             fs.mInstance = null
  13.  
  14.     // Build the list of currently added fragments. 
  15.     if (fms.mAdded != null) { 
  16.         mAdded = new ArrayList<Fragment>(fms.mAdded.length); 
  17.         for (int i=0; i<fms.mAdded.length; i++) { 
  18.             Fragment f = mActive.get(fms.mAdded[i]); 
  19.             if (f == null) { 
  20.                 throwException(new IllegalStateException( 
  21.                         "No instantiated fragment for index #" + fms.mAdded[i])); 
  22.             } 
  23.             f.mAdded = true
  24.             if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f); 
  25.             if (mAdded.contains(f)) { 
  26.                 throw new IllegalStateException("Already added!"); 
  27.             } 
  28.             mAdded.add(f); 
  29.         } 
  30.      
  31.     // Build the back stack. 
  32.     if (fms.mBackStack != null) { 
  33.         mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length); 
  34.         for (int i=0; i<fms.mBackStack.length; i++) { 
  35.             BackStackRecord bse = fms.mBackStack[i].instantiate(this); 
  36.  
  37.             mBackStack.add(bse); 
  38.             if (bse.mIndex >= 0) { 
  39.                 setBackStackIndex(bse.mIndex, bse); 
  40.  

其實到現(xiàn)在現(xiàn)在Fragment相關的信息已經(jīng)恢復成功了,之后隨著FragmentActivity周期顯示或者更新了,這些都是被殺死后,在FragmentActiivyt的onCreate函數(shù)處理的,也就是默認已經(jīng)將之前的Fragment添加到mAdded列表中去了,但是,在場景一,我們有手動新建了一個Fragment,并添加進去,所以,mAdded函數(shù)中就有連個兩個Fragment。這樣,在FragmentActivity調用onStart函數(shù)之后,會新建mAdded列表中Fragment的視圖,將其添加到相應的container中去,并在Activity調用onReusume的時候,顯示出來做的,這個時候,就會顯示兩份,其實如果,在這個時候,你再殺死一次,恢復,就會顯示三分,在殺死,重啟,就是四份。。。。

  1. @Override 
  2. protected void onStart() { 
  3.     super.onStart(); 
  4.  
  5.     mStopped = false
  6.     mReallyStopped = false
  7.     mHandler.removeMessages(MSG_REALLY_STOPPED); 
  8.  
  9.     if (!mCreated) { 
  10.         mCreated = true
  11.         mFragments.dispatchActivityCreated(); 
  12.     } 
  13.  
  14.     mFragments.noteStateNotSaved(); 
  15.     mFragments.execPendingActions(); 
  16.  
  17.     mFragments.doLoaderStart(); 
  18.  
  19.     // NOTE: HC onStart goes here. 
  20.  
  21.     mFragments.dispatchStart(); 
  22.     mFragments.reportLoaderStart(); 
  23.  

以上就是針對兩個場景,對FramgentActivity的一些分析,主要是回復時候,對于Framgent的一些處理。

onSaveInstanceState與OnRestoreInstance的調用時機

在在點擊home鍵,或者跳轉其他界面的時候,都會回調用onSaveInstanceState,但是再次喚醒卻不一定調用OnRestoreInstance,這是為什么呢?onSaveInstanceState與OnRestoreInstance難道不是配對使用的?在Android中,onSaveInstanceState是為了預防Activity被后臺殺死的情況做的預處理,如果Activity沒有被后臺殺死,那么自然也就不需要進行現(xiàn)場的恢復,也就不會調用OnRestoreInstance,而大多數(shù)情況下,Activity不會那么快被殺死。

onSaveInstanceState的調用時機

onSaveInstanceState函數(shù)是Android針對可能被后臺殺死的Activity做的一種預防,它的執(zhí)行時機在2.3之前是在onPause之前,2.3之后,放在了onStop函數(shù)之前,也就說Activity失去焦點后,可能會由于內(nèi)存不足,被回收的情況下,都會去執(zhí)行onSaveInstanceState。對于startActivity函數(shù)的調用很多文章都有介紹,可以簡單參考下老羅的博客Android應用程序內(nèi)部啟動Activity過程(startActivity)的源代碼分析,比如在Activity A 調用startActivity啟動Activity B的時候,會首先通過AMS pause Activity A,之后喚起B(yǎng),在B顯示,再stop A,在stop A的時候,需要保存A的現(xiàn)場,因為不可見的Activity都是可能被后臺殺死的,比如,在開發(fā)者選項中打開不保留活動,就會達到這種效果,在啟動另一個Activity時,上一個Activity的保存流程大概如下,這里先簡單描述,在下一篇原理篇的時候,會詳細講解下流程: 

 

 

 

在2.3之后,onSaveInstanceState的時機都放在了onStop之前,看一下FragmentActivity的onSaveInstanceState源碼:

  1. @Override 
  2. protected void onSaveInstanceState(Bundle outState) { 
  3.     super.onSaveInstanceState(outState); 
  4.     Parcelable p = mFragments.saveAllState(); 
  5.     if (p != null) { 
  6.         outState.putParcelable(FRAGMENTS_TAG, p); 
  7.     } 
  8.  

可以看出,首先就是父類的onSaveInstanceState,主要是保存一些窗口及View的信息,比如ViewPager當前顯示的是第幾個View等。之后,就是就是通過FragmentManager的saveAllState,來保存FragmentActivity自身的現(xiàn)場-Fragment的一些狀態(tài),這些數(shù)據(jù)是FragmentActivity恢復Framgent所必須的數(shù)據(jù),處理不好就會出現(xiàn)上面的那種異常。

OnRestoreInstanceState的調用時機

之前已經(jīng)說過,OnRestoreInstanceState雖然與onSaveInstanceState是配對實現(xiàn)的,但是其調用卻并非完全成對的,在Activity跳轉或者返回主界面時,onSaveInstanceState是一定會調用的,但是OnRestoreInstanceState卻不會,它只有Activity或者App被異常殺死,走恢復流程的時候才會被調用。如果沒有被異常殺死,不走Activity的恢復新建流程,也就不會回調OnRestoreInstanceState,簡單看一下Activity的加載流程圖: 

 

 

 

可以看出,OnRestoreInstanceState的調用時機是在onStart之后,在onPostCreate之前。那么正常的創(chuàng)建為什么沒調用呢?看一下ActivityThread中啟動Activity的源碼:

  1. private Activity performLaunchActivity(Activi 
  2.          
  3.         ... 
  4.          mInstrumentation.callActivityOnCreate(activity, r.state); 
  5.                  
  6.               r.activity = activity; 
  7.               r.stopped = true
  8.               if (!r.activity.mFinished) { 
  9.                   activity.performStart(); 
  10.                   r.stopped = false
  11.               } 
  12.               if (!r.activity.mFinished) { 
  13.                   if (r.state != null) { 
  14.                       mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); 
  15.                   } 
  16.               } 
  17.               if (!r.activity.mFinished) { 
  18.                   activity.mCalled = false
  19.                   mInstrumentation.callActivityOnPostCreate(activity, r.state); 
  20.             
  21.               } 
  22.     }  

可以看出,只有r.state != null的時候,才通過mInstrumentation.callActivityOnRestoreInstanceState回調OnRestoreInstanceState,r.state就是ActivityManagerService通過Binder傳給ActivityThread數(shù)據(jù),主要用來做場景恢復。以上就是onSaveInstanceState與OnRestoreInstance執(zhí)行時機的一些分析。下面結合具體的系統(tǒng)View控件來分析一下這兩個函數(shù)的具體應用:比如ViewPager與FragmentTabHost,這兩個空間是主界面最常用的控件,內(nèi)部對后臺殺死做了兼容,這也是為什么被殺死后,Viewpager在恢復后,能自動定位到上次瀏覽的位置。

ViewPager應對后臺殺死做的兼容

首先看一下ViewPager做的兼容,ViewPager在后臺殺死的情況下,仍然能恢復到上次關閉的位置,這也是對體驗的一種優(yōu)化,這其中的原理是什么?之前分析onSaveInstanceState與onRestoreInstanceState的時候,只關注了Fragment的處理,其實還有一些針對Window窗口及Vie的處理,先看一下onSaveInstanceState針對窗口保存了什么:

  1. protected void onSaveInstanceState(Bundle outState) { 
  2.     outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState()); 
  3.   }  

PhonwWinow.java

  1. @Override 
  2. public Bundle saveHierarchyState() { 
  3.     Bundle outState = new Bundle(); 
  4.     if (mContentParent == null) { 
  5.         return outState; 
  6.     } 
  7.      
  8.     SparseArray<Parcelable> states = new SparseArray<Parcelable>(); 
  9.     mContentParent.saveHierarchyState(states); 
  10.     outState.putSparseParcelableArray(VIEWS_TAG, states); 
  11.  
  12.     // save the focused view id 
  13.       View focusedView = mContentParent.findFocus(); 
  14.       ... 
  15.       outState.putInt(FOCUSED_ID_TAG, focusedView.getId()); 
  16.     // save the panels 
  17.     if (panelStates.size() > 0) { 
  18.         outState.putSparseParcelableArray(PANELS_TAG, panelStates); 
  19.     } 
  20.     if (mActionBar != null) { 
  21.         outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates); 
  22.     } 
  23.  
  24.     return outState; 
  25.  

Window其實就是PhonwWinow,saveHierarchyState其實就是針對當前窗口中的View保存一些場景信息 ,比如:當前獲取焦點的View的id、ActionBar、View的一些狀態(tài),當然saveHierarchyState遞歸遍歷所有子View,保存所有需要保存的狀態(tài):

ViewGroup.java

  1. @Override 
  2. protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 
  3.     super.dispatchSaveInstanceState(container); 
  4.     final int count = mChildrenCount; 
  5.     final View[] children = mChildren; 
  6.     for (int i = 0; i < count; i++) { 
  7.         View c = children[i]; 
  8.         if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) { 
  9.             c.dispatchSaveInstanceState(container); 
  10.         } 
  11.     } 
  12.  

可見,該函數(shù)首先通過super.dispatchSaveInstanceState保存自身的狀態(tài),再遞歸傳遞給子View。onSaveInstanceState主要用于獲取View需要保存的State,并將自身的ID作為Key,存儲到SparseArray<Parcelable> states列表中,其實就PhoneWindow的一個列表,這些數(shù)據(jù)最后會通過Binder保存到ActivityManagerService中去

View.java

  1. protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 
  2.     if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 
  3.         mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 
  4.         Parcelable state = onSaveInstanceState(); 
  5.         if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 
  6.             throw new IllegalStateException( 
  7.                     "Derived class did not call super.onSaveInstanceState()"); 
  8.         } 
  9.         if (state != null) { 
  10.             container.put(mID, state); 
  11.         } 
  12.     } 
  13.  

那么針對ViewPager到底存儲了什么信息?通過下面的代碼很容易看出,其實就是新建個了一個SavedState場景數(shù)據(jù),并且將當前的位置mCurItem存進去。

  1. @Override 
  2. ublic Parcelable onSaveInstanceState() { 
  3.    Parcelable superState = super.onSaveInstanceState(); 
  4.    SavedState ss = new SavedState(superState); 
  5.    ss.position = mCurItem; 
  6.    if (mAdapter != null) { 
  7.        ss.adapterState = mAdapter.saveState(); 
  8.    } 
  9.    return ss;  

到這里存儲的事情基本就完成了。接下來看一下ViewPager的恢復以及onRestoreInstanceState到底做了什么,

  1. protected void onRestoreInstanceState(Bundle savedInstanceState) { 
  2.     if (mWindow != null) { 
  3.         Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG); 
  4.         if (windowState != null) { 
  5.             mWindow.restoreHierarchyState(windowState); 
  6.         } 
  7.     } 
  8.  

從代碼可以看出,其實就是獲取當時保存的窗口信息,之后通過mWindow.restoreHierarchyState做數(shù)據(jù)恢復,

  1. @Override 
  2. public void restoreHierarchyState(Bundle savedInstanceState) { 
  3.     if (mContentParent == null) { 
  4.         return
  5.     } 
  6.  
  7.     SparseArray<Parcelable> savedStates 
  8.             = savedInstanceState.getSparseParcelableArray(VIEWS_TAG); 
  9.     if (savedStates != null) { 
  10.         mContentParent.restoreHierarchyState(savedStates); 
  11.     } 
  12.     ... 
  13.      
  14.     if (mActionBar != null) { 
  15.         ... 
  16.           mActionBar.restoreHierarchyState(actionBarStates); 
  17.       } 
  18.  

對于ViewPager會發(fā)生什么?從源碼很容易看出,其實就是取出SavedState,并獲取到異常殺死的時候的位置,以便后續(xù)的恢復,

ViewPager.java

  1. @Override 
  2. public void onRestoreInstanceState(Parcelable state) { 
  3.     if (!(state instanceof SavedState)) { 
  4.         super.onRestoreInstanceState(state); 
  5.         return
  6.     } 
  7.  
  8.     SavedState ss = (SavedState)state; 
  9.     super.onRestoreInstanceState(ss.getSuperState()); 
  10.  
  11.     if (mAdapter != null) { 
  12.         mAdapter.restoreState(ss.adapterState, ss.loader); 
  13.         setCurrentItemInternal(ss.position, falsetrue); 
  14.     } else { 
  15.         mRestoredCurItem = ss.position; 
  16.         mRestoredAdapterState = ss.adapterState; 
  17.         mRestoredClassLoader = ss.loader; 
  18.     } 
  19. }   

以上就解釋了ViewPager是如何通過onSaveInstanceState與onRestoreInstanceState保存、恢復現(xiàn)場的。如果是ViewPager+FragmentAdapter的使用方式,就同時涉及FragmentActivity的恢復、也牽扯到Viewpager的恢復,其實FragmentAdapter也同樣針對后臺殺死做了一些兼容,防止重復新建Fragment,看一下FragmentAdapter的源碼:

FragmentPagerAdapter.java

  1. @Override 
  2. public Object instantiateItem(ViewGroup container, int position) { 
  3.     if (mCurTransaction == null) { 
  4.         mCurTransaction = mFragmentManager.beginTransaction(); 
  5.     } 
  6.  
  7.     final long itemId = getItemId(position); 
  8.  
  9.     // Do we already have this fragment? 
  10.     <!--是否已經(jīng)新建了Fragment??--> 
  11.      
  12.     String name = makeFragmentName(container.getId(), itemId); 
  13.     Fragment fragment = mFragmentManager.findFragmentByTag(name); 
  14.      
  15.     1 如果Activity中存在相應Tag的Fragment,就不要通過getItem新建 
  16.      
  17.     if (fragment != null) { 
  18.         mCurTransaction.attach(fragment); 
  19.     } else { 
  20.     2 如果Activity中不存在相應Tag的Fragment,就需要通過getItem新建 
  21.         fragment = getItem(position); 
  22.         mCurTransaction.add(container.getId(), fragment, 
  23.                 makeFragmentName(container.getId(), itemId)); 
  24.     } 
  25.     if (fragment != mCurrentPrimaryItem) { 
  26.         FragmentCompat.setMenuVisibility(fragment, false); 
  27.         FragmentCompat.setUserVisibleHint(fragment, false); 
  28.     } 
  29.  
  30.     return fragment; 
  31.  

從1與2 可以看出,通過后臺恢復,在FragmentActivity的onCreate函數(shù)中,會重建Fragment列表,那些被重建的Fragment不會再次通過getItem再次創(chuàng)建,再來看一下相似的控件FragmentTabHost,F(xiàn)ragmentTabHost也是主頁常用的控件,F(xiàn)ragmentTabHost也有相應的后臺殺死處理機制,從名字就能看出,這個是專門針對Fragment才創(chuàng)建出來的控件。 

 

 

 

FragmentTabHost應對后臺殺死做的兼容

FragmentTabHost其實跟ViewPager很相似,在onSaveInstanceState執(zhí)行的時候保存當前位置,并在onRestoreInstanceState恢復postion,并重新賦值給Tabhost,之后FragmentTabHost在onAttachedToWindow時,就可以根據(jù)恢復的postion設置當前位置,代碼如下:

FragmentTabHost.java

  1. @Override 
  2. protected Parcelable onSaveInstanceState() { 
  3.     Parcelable superState = super.onSaveInstanceState(); 
  4.     SavedState ss = new SavedState(superState); 
  5.     ss.curTab = getCurrentTabTag(); 
  6.     return ss; 
  7.  
  8. @Override 
  9. protected void onRestoreInstanceState(Parcelable state) { 
  10.     if (!(state instanceof SavedState)) { 
  11.         super.onRestoreInstanceState(state); 
  12.         return
  13.     } 
  14.     SavedState ss = (SavedState) state; 
  15.     super.onRestoreInstanceState(ss.getSuperState()); 
  16.     setCurrentTabByTag(ss.curTab); 
  17.  

在FragmentTabHost執(zhí)行onAttachedToWindow時候,會首先getCurrentTabTag ,如果是經(jīng)歷了后臺殺死,這里得到的值其實是恢復的SavedState里的值,之后通過doTabChanged切換到響應的Tab,注意這里切換的時候,F(xiàn)ragment由于已經(jīng)重建了,是不會再次新建的。

  1. @Override 
  2. protected void onAttachedToWindow() { 
  3.     super.onAttachedToWindow(); 
  4.  
  5.     String currentTab = getCurrentTabTag(); 
  6.     ... 
  7.      
  8.     ft = doTabChanged(currentTab, ft); 
  9.      
  10.     if (ft != null) { 
  11.         ft.commit(); 
  12.         mFragmentManager.executePendingTransactions(); 
  13.     } 
  14.  

App開發(fā)時針對后臺殺死處理方式

最簡單的方式,但是效果一般:取消系統(tǒng)恢復

比如:針對FragmentActivity ,不重建:

  1. protected void onCreate(Bundle savedInstanceState) { 
  2.      if (savedInstanceState != null) { 
  3.      savedInstanceState.putParcelable(“android:support:fragments”, null);} 
  4.      super.onCreate(savedInstanceState); 
  5. }    

如果是系統(tǒng)的Actvity改成是“android:fragments",不過這里需要注意:對于ViewPager跟FragmentTabHost不需要額外處理,處理了可能反而有反作用。

針對Window,如果不想讓View使用恢復邏輯,在基類的FragmentActivity中覆蓋onRestoreInstanceState函數(shù)即可。

  1. protected void onRestoreInstanceState(Bundle savedInstanceState) { 
  2.  

當然以上的做法都是比較粗暴的做法,最好還是順著Android的設計,在需要保存現(xiàn)場的地方保存,在需要恢復的地方,去除相應的數(shù)據(jù)進行恢復。以上就是后臺殺死針對FragmentActivity、onSaveInstanceState、onRestoreInstanceState的一些分析,后面會有兩篇針對后臺殺死原理,以及ActivityManagerService如何處理殺死及恢復的文章。

責任編輯:龐桂玉 來源: segmentfault
相關推薦

2017-01-12 15:06:30

AndroidAppActivityMan

2018-11-03 16:29:48

Red HatKDE桌面環(huán)境

2019-12-27 14:00:43

傳統(tǒng)IT商業(yè)模式

2025-02-07 08:30:37

2021-11-15 10:35:46

Python線程代碼

2011-03-17 09:20:05

異常處理機制

2021-05-29 10:32:15

XDRSIEM安全

2022-12-26 09:00:07

2024-02-26 00:00:00

RAGGeminiLLM

2023-06-15 14:09:00

解析器Servlet容器

2022-06-10 09:39:16

Ubuntu進程Ubuntu 社區(qū)

2011-07-01 14:20:59

Qt 事件

2011-07-01 14:14:34

Qt 事件

2020-03-27 08:17:01

運維DBA服務器

2009-10-27 08:57:50

linux殺死進程

2017-02-06 10:27:31

2019-05-28 08:12:34

2019-12-26 14:52:31

微軟CortanaAndroid

2022-02-17 19:47:03

安卓ANR故障

2019-06-05 13:00:00

點贊
收藏

51CTO技術棧公眾號

韩国av免费在线观看| 国产精品丝袜一区二区| 国产亚洲一区二区手机在线观看 | 成人精品网站在线观看| 91在线播放观看| 青青一区二区| 在线播放亚洲一区| 国产二区视频在线播放| 黄色在线论坛| 91美女片黄在线观看91美女| 91精品国产综合久久香蕉的用户体验| 日韩精品成人一区| 97人人精品| 日韩精品极品毛片系列视频| 亚洲无在线观看| 成人自拍av| 亚洲一区二区三区视频在线播放 | 法国空姐电影在线观看| 国产麻豆一区二区三区| 91黄色免费版| 自慰无码一区二区三区| 黄av在线免费观看| 国产欧美日韩在线视频| 国产欧美亚洲日本| www.激情五月| 美女脱光内衣内裤视频久久影院| 午夜欧美不卡精品aaaaa| 肉色超薄丝袜脚交69xx图片| 日韩啪啪网站| 精品国产电影一区二区| 中文字幕 欧美日韩| 韩日精品一区二区| 婷婷国产v国产偷v亚洲高清| 精品少妇人妻av一区二区| 国产高清视频在线| 久久嫩草精品久久久精品一| 国产精品嫩草在线观看| 精品国产亚洲一区二区麻豆| 久久国产乱子精品免费女| 日本久久精品视频| 欧美亚洲精品天堂| 夜夜爽av福利精品导航| 久久久久久网址| 精品少妇一二三区| 国产精品www994| 欧美国产在线视频| 九九热国产在线| 欧美日韩国产免费观看| 欧美成人精品在线观看| 99视频只有精品| 综合日韩在线| 欧美尺度大的性做爰视频| 小泽玛利亚一区二区免费| 欧美国产小视频| 精品国产视频在线| √天堂中文官网8在线| 亚洲乱码在线| 九九热99久久久国产盗摄| tube国产麻豆| 国模一区二区三区| 麻豆国产精品va在线观看不卡 | 在线观看xxx| 91在线一区二区三区| 久久99精品久久久久久秒播放器| 四虎精品在线| 国产喷白浆一区二区三区| 五月婷婷一区| av网址在线| 亚洲成人中文在线| 日韩av三级在线| 一区二区视频免费完整版观看| 欧洲av一区二区嗯嗯嗯啊| 在线免费av播放| 国产午夜久久av| 亚洲精品在线电影| 中国黄色a级片| 日韩欧美中字| 欧美福利视频在线| 九九九在线观看| 麻豆视频一区二区| 91亚洲精品丁香在线观看| 无码国产伦一区二区三区视频| 久久精品人人做| 二级片在线观看| 国产在线观看www| 欧美优质美女网站| 中文写幕一区二区三区免费观成熟| 噜噜噜狠狠夜夜躁精品仙踪林| 亚洲片国产一区一级在线观看| 国产极品美女在线| 国产深夜精品| 91老司机在线| 视频福利在线| 亚洲人精品一区| 99色精品视频| 日韩欧美一级| 亚洲天堂视频在线观看| 青青草原在线免费观看| 久久精品一本| 91精品黄色| 午夜视频在线观看网站| 亚洲第一搞黄网站| 视频在线观看免费高清| 日本欧美韩国国产| 另类图片亚洲另类| 国产精品成人久久久| 成人久久18免费网站麻豆| 日韩一区不卡| 欧美少妇精品| 欧美大肚乱孕交hd孕妇| 1024在线看片| 亚洲欧美视频| 国产成人精品免费视频大全最热 | 欧美一级电影免费在线观看| 国产视频手机在线| 国产欧美精品在线观看| 无码专区aaaaaa免费视频| 91嫩草国产线观看亚洲一区二区| 亚洲欧洲一区二区三区久久| 久久久一区二区三区四区| 久久国产剧场电影| 亚洲国产高清国产精品| 自拍偷拍欧美视频| 亚洲高清在线观看| 久久99久久98精品免观看软件 | 在线精品视频免费播放| 一级欧美一级日韩片| 一本到12不卡视频在线dvd| 国产精品高潮呻吟久久av黑人| 欧美一区二区公司| 一区二区三区欧美亚洲| 91精产国品一二三产区别沈先生| blacked蜜桃精品一区| 91成人在线播放| 人人妻人人澡人人爽精品日本| 亚洲欧美视频在线观看| 91女神在线观看| 久久免费精品视频在这里| 国产91色在线|免| 青春有你2免费观看完整版在线播放高清 | 国产亚洲精品精品国产亚洲综合| 亚洲天堂av电影| 中文字幕免费观看| 久久精品欧美一区二区三区麻豆| 日本三区在线观看| 国产乱码精品一区二区三区四区| 欧美在线一级视频| 肉丝一区二区| 91国产免费看| 免费看裸体网站| 蜜臀国产一区二区三区在线播放| 色噜噜一区二区| 欧美成人福利| 另类天堂视频在线观看| 亚洲成人中文字幕在线| 亚洲已满18点击进入久久| 国产午夜在线一区二区三区| 亚洲国产1区| 久久精品日产第一区二区三区精品版| 欧亚av在线| 一本一本久久a久久精品综合小说| 亚洲精品国产精品乱码视色| 成人免费在线视频| 日本黄色www| 99精品免费网| 欧洲精品一区色| 欧美成人毛片| 欧美精品videosex极品1| 日韩一区二区三区不卡| 欧美性猛交xxxx| 国产一区二区三区视频播放| 国产精品一区不卡| 久久亚洲中文字幕无码| 精品国产中文字幕第一页| 国产欧美va欧美va香蕉在线| 欧美xxxx免费虐| 亚洲精品有码在线| 国产精品人人妻人人爽| 亚洲午夜视频在线观看| 久久久久久久久久久久| 国产一区三区三区| 美女日批免费视频| 欧美高清视频在线观看mv| 粉嫩av四季av绯色av第一区| 欧美××××黑人××性爽| 伦伦影院午夜日韩欧美限制| 亚洲人午夜射精精品日韩| 欧美日本国产视频| 国产精品suv一区二区| 国产亲近乱来精品视频| 在线观看一区二区三区视频| 久久综合影视| 国产精品国三级国产av| 国产免费播放一区二区| 亚洲精品欧美日韩| 香蕉视频亚洲一级| 九九视频这里只有精品| av女优在线| 亚洲精品国产品国语在线 | 亚洲成人网在线| 中文字幕91爱爱| 香蕉成人伊视频在线观看| 成年人视频软件| 久久一日本道色综合| 俄罗斯女人裸体性做爰| 美女在线观看视频一区二区| 国产原创中文在线观看| 午夜国产欧美理论在线播放| 日韩精品国内| 同性恋视频一区| 国产精品久久国产三级国电话系列| 欧美va视频| 97超级碰碰人国产在线观看| 97超碰资源站在线观看| 中文字幕视频在线免费欧美日韩综合在线看 | 欧美成人第一区| 2021年精品国产福利在线| 国产精品视频区| 日韩成人影音| 国产91精品久久久久| 草草影院在线| 欧美日本精品在线| 国产黄色小视频在线| 国产一区二区三区精品久久久| 网站黄在线观看| 日韩精品一区二| 亚洲av无码一区二区三区性色| 欧美精品国产精品| 一炮成瘾1v1高h| 欧美色大人视频| 国语对白做受69按摩| 91国产精品成人| jizz国产在线观看| 色噜噜狠狠成人网p站| 高清乱码免费看污| 在线欧美一区二区| 国产精品无码粉嫩小泬| 91国产精品成人| 日韩不卡高清视频| 欧美探花视频资源| 中文字幕人妻色偷偷久久| 色八戒一区二区三区| 国产黄色免费视频| 在线精品视频免费播放| 在线免费观看中文字幕| 欧美乱熟臀69xxxxxx| 国产精品爽爽久久久久久| 91麻豆精品国产91久久久更新时间 | 欧美精品中文字幕一区二区| 色综合中文网| 日韩欧美亚洲在线| 日韩一区电影| 国产成人三级视频| 国色天香一区二区| 久久成人免费观看| 日本亚洲一区二区| 中文字幕在线观看日| 国产真实精品久久二三区| 美女被艹视频网站| 成人精品亚洲人成在线| 亚洲av无码一区二区三区网址 | 久久综合入口| 国产欧美日韩一区二区三区四区 | 毛片在线看片| 久久99久国产精品黄毛片入口| 爱情岛亚洲播放路线| 人体精品一二三区| 日本成人一区二区| 国产精品久久久久久久小唯西川| 日本在线中文字幕一区| 先锋影音亚洲资源| 欧美成人日韩| 日韩久久一级片| 国内精品免费在线观看| 人妻av一区二区| 日本一区二区三区四区在线视频| 一级片一级片一级片| 天天综合网 天天综合色| 超碰在线97观看| 日韩欧美亚洲另类制服综合在线| 午夜国产在线视频| 久久精品国产清自在天天线 | 91精品国产自产拍在线观看蜜| 欧美亚洲色图视频| 日韩高清在线一区| 免费看三级黄色片| 久久久噜噜噜久久人人看 | 国产精品女主播一区二区三区| 欧美一级裸体视频| 成人精品视频网站| 91大神福利视频| 欧美日韩中文字幕| av av片在线看| 亚洲视频欧洲视频| 国产美女一区视频| 国产日韩欧美自拍| 天天操综合520| 香蕉视频免费版| 天堂成人免费av电影一区| 国产又粗又猛又爽又黄| 欧美激情综合五月色丁香小说| 日韩激情一区二区三区| 欧美亚一区二区| 色视频在线看| 久久久久五月天| 亚洲国产天堂| 日韩欧美激情一区二区| 在线视频精品| 97中文字幕在线观看| 国产精品久久久久久久久免费桃花| 综合激情网五月| 精品福利av导航| 好了av在线| 国产日韩在线一区| 沈樵精品国产成av片| 国产老熟妇精品观看| 岛国精品一区二区| 日韩欧美123区| 欧美日韩国产片| 国产福利在线看| 欧美在线视频免费| 天堂99x99es久久精品免费| 国产xxxx振车| 国产成人精品影视| 日韩三级在线观看视频| 9191成人精品久久| 日本视频在线观看| 国产精品久久久久一区二区| 国产免费播放一区二区| av片中文字幕| 久久久久亚洲蜜桃| 欧美一区二区三区不卡视频| 精品偷拍各种wc美女嘘嘘| 欧美日韩国产观看视频| 精品欧美国产一区二区三区不卡| 伊人成人在线视频| 亚洲欧美日韩色| 亚洲成人av中文| 亚洲日本在线播放| 欧美影院在线播放| 视频一区中文| 中文字幕第80页| 国产精品久久久久久久久果冻传媒| 影音先锋国产资源| 日韩中文字幕精品视频| 国产精品麻豆免费版现看视频| 亚洲视频www| 久久人妻一区二区| 欧美视频免费在线| 可以在线观看的av网站| 国产成人久久精品| 欧美综合久久| 亚洲一区二区在线视频观看| 专区另类欧美日韩| 精品国产亚洲一区二区麻豆| 欧美激情xxxx性bbbb| 日韩美脚连裤袜丝袜在线| 青青青在线播放| 国产精品久久久久久一区二区三区 | 色视频欧美一区二区三区| 国产理论电影在线观看| 成人免费网站在线看| 欧美婷婷在线| www.久久av| 欧美日韩激情在线| 最新av在线播放| 久久日韩精品| 蜜臀av性久久久久蜜臀aⅴ四虎| 永久免费看片直接| 亚洲成在人线av| 欧美黄色三级| 国产精品国三级国产av| 久久色在线视频| 99re只有精品| 欧美制服第一页| 性xxxx欧美老肥妇牲乱| 视频免费在线观看| 欧美日韩专区在线| 91超碰在线播放| 水蜜桃一区二区三区| 国产成人免费在线观看| 国产精品777777| 久久久美女毛片| 亚洲天堂网一区二区| 欧美精品一级二级三级| 17videosex性欧美| 亚洲午夜精品久久久中文影院av| 国产成人av一区| 波多野结衣黄色网址| 欧美日韩电影在线观看| 精品视频黄色| 蜜臀视频在线观看| 欧美三区免费完整视频在线观看| 中文av资源在线| 日韩欧美精品久久| 成人黄色av电影| 国产又粗又黄又爽的视频| 91sa在线看| 日韩在线视频精品| xxxxx在线观看|