Android Activity被回收的情況分析
1.onSaveInstanceState()方法
當(dāng)一個Activity進入了停止?fàn)顟B(tài),是有可能被系統(tǒng)回收的。想象以下場景:應(yīng)用中有一個ActivityA,用戶在ActivityA的基礎(chǔ)上啟動了ActivityB,ActivityA就進入了停止?fàn)顟B(tài),這個時候由于系統(tǒng)內(nèi)存不足,將ActivityA回收掉了,然后用戶按下Back鍵返回ActivityA,會出現(xiàn)什么情況呢?其實還是會正常顯示ActivityA的,只不過這時并不會執(zhí)行onRestart()方法,而是會執(zhí)行ActivityA的onCreate()方法,因為ActivityA在這種情況下會被重新創(chuàng)建一次。
但是這種情況下可能會出現(xiàn)一個重要的問題:ActivityA中是可能存在臨時數(shù)據(jù)和狀態(tài)的。打個比方,MainActivity中如果有一個文本輸入框,現(xiàn)在你輸入了一段文字,然后啟動NormalActivity,這時MainActivity由于系統(tǒng)內(nèi)存不足被回收掉,過了一會你又點擊了Back鍵回到MainActivity,這個時候你會發(fā)現(xiàn)剛剛輸入的文字都沒了,因為MainActivity被重新創(chuàng)建了。
如果我們的應(yīng)用出現(xiàn)了這種情況是比較影響用戶體驗的,其實Activity還提供了一個onSaveInstanceState()回調(diào)方法,這個方法可以保證在Activity被回收之前一定會被調(diào)用,因此我們可以通過這個方法來解決這個問題。
onSaveInstanceState()方法會攜帶一個Bundle類型的參數(shù),Bundle提供了一系列的方法保存數(shù)據(jù),比如可以使用putString()方法保存字符串,使用putInt()方法保存整型數(shù)據(jù),以此類推。每個保存方法需要傳入兩個參數(shù),第一個參數(shù)是鍵,用于后面從Bundle中取值,第二個參數(shù)是真正要保存的內(nèi)容。
在MainActivity中添加如下代碼就可以將臨時數(shù)據(jù)進行保存了:
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) val tempData="Something you just typed" outState.putString("data_key",tempData) }
數(shù)據(jù)是已經(jīng)保存下來了,那么我們應(yīng)該在哪里進行恢復(fù)呢?其實我們一直在使用的onCreate()方法其實也有一個Bundle類型的參數(shù)。這個參數(shù)在一般情況下都是null,但是如果在Activity被系統(tǒng)回收之前,你通過onSaveInstanceState()方法保存數(shù)據(jù),這個參數(shù)就會帶有之前保存的全部數(shù)據(jù),我們只需要再通過相應(yīng)的取值方法將數(shù)據(jù)取出即可。
修改MainActivity的onCreate()方法,如下所示:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_first) if(savedInstanceState!=null){ val tempData = savedInstanceState.getString("data_key") tempData?.let { Log.d("tag", it) } } }
取出值之后就可以再做相應(yīng)的恢復(fù)操作就可以了,比如將文本內(nèi)容重新賦值到文本輸入框上,這里我只是簡單打印一下。
這里使用Bundle保存和取出數(shù)據(jù)和我們之前使用Intent傳遞數(shù)據(jù)的方法很類似,首先我們可以把需要傳遞的數(shù)據(jù)都保存在Bundle對象中,然后再將Bundle對象存放在Intent里。到了目標(biāo)Activity之后,先從Intent中取出Bundle,再從Bundle中一一取出數(shù)據(jù)。
另外在手機的屏幕發(fā)生旋轉(zhuǎn)的時候,Activity也會經(jīng)歷一個重新創(chuàng)建的過程,因而在這種情況下,Activity中的數(shù)據(jù)也會丟失。這種問題也可以通過onSaveInstanceState()方法來解決,但是對于橫豎屏已經(jīng)有了更好的方案。
2.ViewModel
使用 ViewModel,我們就無需再用這種方法保存,因為 ViewModel 會自動感知生命周期,處理數(shù)據(jù)的保存與恢復(fù)。即數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置(其它例如分辨率調(diào)整、權(quán)限變更、系統(tǒng)字體樣式、語言變更等)更改后繼續(xù)留存。
代碼如下:
package com.example.viewmodeldemo; import androidx.appcompat.app.AppCompatActivity; import androidx.lifecycle.ViewModelProvider; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends AppCompatActivity { private MyViewModel mMyViewModel; private TextView textView; private Button mButton1; private Button mButton2; private final String TAG="MainActivityTest"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG, "onCreate: "); //創(chuàng)建一個ViewModel對象 mMyViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class); textView=findViewById(R.id.textView); //ViewModel會保存數(shù)據(jù),當(dāng)你重新創(chuàng)建的時候會加載顯示出來 textView.setText(String.valueOf(mMyViewModel.number)); mButton1=findViewById(R.id.button1); mButton2=findViewById(R.id.button2); mButton1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mMyViewModel.number++; textView.setText(String.valueOf(mMyViewModel.number)); } }); mButton2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mMyViewModel.number+=2; textView.setText(String.valueOf(mMyViewModel.number)); } }); } @Override protected void onStart() { super.onStart(); Log.d(TAG, "onStart: "); } @Override protected void onStop() { super.onStop(); Log.d(TAG, "onStop: "); } @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy: "); } @Override protected void onPause() { super.onPause(); Log.d(TAG, "onPause: "); } @Override protected void onResume() { super.onResume(); Log.d(TAG, "onResume: "); } }
package com.example.viewmodeldemo; import androidx.lifecycle.ViewModel; //這里的ViewModel可以看作全局變量倉庫 public class MyViewModel extends ViewModel { public int number=0; }
這樣當(dāng)你旋轉(zhuǎn)屏幕生命周期發(fā)生變化,你的數(shù)據(jù)還在。
到此這篇關(guān)于Android Activity被回收的情況分析的文章就介紹到這了,更多相關(guān)Android Activity被回收內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android中實現(xiàn)地址欄輸入網(wǎng)址能瀏覽該地址網(wǎng)頁源碼并操作訪問網(wǎng)絡(luò)
Android中實現(xiàn)地址欄輸入網(wǎng)址能瀏覽該地址網(wǎng)頁源碼的效果,想必有很多朋友都不清楚吧,下面為大家詳細(xì)介紹下2013-06-06Android入門之利用OKHttp實現(xiàn)斷點續(xù)傳功能
這篇文章主要為大家詳細(xì)介紹了Android如何使用OKHttp多線程制作像迅雷一樣的斷點續(xù)傳功能,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-01-01Android自帶倒計時控件Chronometer使用方法詳解
這篇文章主要為大家詳細(xì)介紹了Android自帶倒計時控件Chronometer的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11詳解Android SpannableString多行圖文混排的應(yīng)用實戰(zhàn)
本篇文章主要介紹了Android SpannableString多行圖文混排的應(yīng)用實戰(zhàn),具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12Android開發(fā)之TabActivity用法實例詳解
這篇文章主要介紹了Android開發(fā)之TabActivity用法,結(jié)合實例形式較為詳細(xì)的分析了Android擴展Activity實現(xiàn)標(biāo)簽頁效果的具體步驟與相關(guān)技巧,需要的朋友可以參考下2016-03-03