亞寵展、全球寵物產業風向標——亞洲寵物展覽會深度解析
1269
2022-05-28
當android app發生屏幕旋轉、鍵盤可用性變化及用戶啟用多窗口模式時,正在運行的Activity會被重啟,即先調用onDestroy(),再調用 onCreate()方法。
注意:屏幕方向、鍵盤可用性,以及當用戶啟用多窗口模式這些稱為設備配置,它們一開始就被配置好的。
重啟的原因是為了可以使用新的資源來匹配新的設備配置。比如由豎屏旋轉為橫屏時,可能要使用不同的布局。這個重啟為這些改變提供了一個機會。我們就可以借此機會來利用與新設備配置相匹配的備用資源來自動重新加載我們的應用,從而幫助應用適應新配置。
因為設備配置發生變化時,當前Activity會重啟,那么有些數據就可能會丟失,比如說用戶輸入的內容,因為那么輸入框在activity重啟時,都會被初始化為空。我們肯定是不希望丟失的。所以當發生配置變化時,我們如何做才能不丟失數據呢?這些數據我們通常都喜歡稱其為activity狀態(想想也確實如此,狀態就是要由數據來表現的)。
針對設備變化的處理有兩種處理方式:
1.自行處理設備配置變化
如果重啟activity需要恢復大量數據、重新建立網絡連接等等,那么配置變化引起的activity重啟會嚴重影響用戶體驗,給用戶 感覺app的運行很慢。
如果應用在設備配置變化時,不需要更新資源,并且考到慮性能的限制,盡量避免activity重啟,那么我們可以聲明 Activity 自行處理配置變更,從而阻止系統重啟 Activity。
1.1.聲明由Activity 處理配置變更的方法
在AndroidManifest.xml清單文件中編輯相應的
"orientation" :在屏幕方向發生變更時阻止重啟。
"screenSize" :在屏幕方向發生變更時阻止重啟,但僅適用于 Android 3.2(API 級別 13)及以上版本的系統。
"keyboardHidden" :在鍵盤可用性發生變更時阻止重啟。
例如,聲明 Activity 可同時處理屏幕方向變更和鍵盤可用性變更:
1
2
3
配置變更時,應用會收到回調,以便您可以根據需要手動更新 Activity。如上面配置后,即便其中某個配置發生變化,MyActivity 也不會重啟。但 MyActivity 會接收到對 onConfigurationChanged() 的調用消息。此方法會收到傳遞的 Configuration 對象,從而指定新設備配置。您可以通過讀取 Configuration 中的字段確定新配置,然后通過更新界面所用資源進行適當的更改。調用此方法時,Activity 的 Resources 對象會相應地進行更新,并根據新配置返回資源,以便您在系統不重啟 Activity 的情況下輕松重置界面元素。例如,以下 onConfigurationChanged() 實現用于檢查當前的設備方向:
注意:**只有activity配置了android:configChanges,當配置變化時,onConfigurationChanged()才會被回調。 **
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Checks the orientation of the screen if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show(); } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){ Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show(); } }
1
2
3
4
5
6
7
8
9
10
11
Configuration 對象代表所有當前配置,而不僅僅是已變更的配置。如果無需根據這些配置變更更新應用,則可不必實現 onConfigurationChanged()。在此情況下,應用仍會使用配置變更前所用的全部資源,區別在于我們無需重啟 Activity。但是,不應該認為,使用此方法即可無需保留正常 Activity 生命周期中的狀態。因為一些其他配置變更會強制重啟應用,而且某些事件需要我們進行處理,例如:用戶想離開應用,而系統在此之前便已銷毀了該應用。
2.在設備配置變化期間保存數據
如果我們沒有采用上面的措施阻止activity重啟,那么我們可以通過以下方式來應對配置變化的情況。
2.1. onSaveInstanceState()
activity重啟會經歷 onDestroy()和 onCreate(),在activity銷毀時,會調用 onSaveInstanceState()方法。所以我們可以將activity的狀態(數據)通過 onSaveInstanceState()保存起來,然后在 onCreate()或 onRestoreInstanceState()中進行恢復。
private EditText mET; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toast.makeText(this,"H工",Toast.LENGTH_LONG).show(); mET = findViewById(R.id.et); // if(savedInstanceState != null && savedInstanceState.containsKey("et")){ // mET.setText(savedInstanceState.getString("et")); // } } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); Toast.makeText(this,"newo",Toast.LENGTH_LONG).show(); outState.putString("et",mET.getText().toString()); } @Override protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); if(savedInstanceState != null && savedInstanceState.containsKey("et")){ mET.setText(savedInstanceState.getString("et")); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
使用onSaveInstanceState()使用Bundle類來保存數據,但是該類并非用于攜帶大型對象(例如位圖),且其中的數據必須依次在主線程中進行序列化和反序列化,可能會消耗大量內存并降低配置變更的速度。
因此可以考慮使用ViewModel來保存activity的狀態。
2.2.ViewModel
ViewModel負責為Activity或Fragment準備和管理數據。ViewModel的作用就是為Activity或Fragment獲取或保存必要的信息。它也可以用來處理activity或fragment
與應用其他部分的通信。ViewModel的創建始終與作用域(Activity/Fragment)相關聯,只要作用域處于活動狀態,模型就將保留。例如,作用域是Activity,直接到Activity執行finish(不是onDestroy喔),ViewModel才會被銷毀,否則將一直保留。也就是說當設備配置變化時,ViewModel的所有者(Activity或Fragment)實例被銷毀時,ViewModel是不會被銷毀的。ViewModel的所有者(Activity或Fragment)的新實例會重新連接上這個ViewModel。
Activity和Fragment應能夠觀察到ViewModel的變化。因此ViewModel通常通過LiveData(或Android Data Binding)來暴露它的信息。ViewModel只負責為UI管理數據。它絕不應訪問視圖層次結構或保留對"Activity"或"Fragment"的引用。
因為Activity在配置發生改變時,會先調用onDestroy()再調用onCreate()方法,那么我們可以在onDestroy()或onSaveInstanceState()將數據保存到ViewModel,然后在onCreate()或onRestoreInstanceState()方法中進行恢復:
public class MainActivity extends AppCompatActivity { private EditText mET; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mET = findViewById(R.id.et); MainModel mainModel = new ViewModelProvider(this,new ViewModelProvider.NewInstanceFactory()).get(MainModel.class); // mainModel.getDataBean().observe(this, new Observer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
MainModel的定義:
public class MainModel extends ViewModel { private final MutableLiveData
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
DataBean的定義:
public class DataBean { private String data; public String getData() { return data; } public void setData(String data) { this.data = data; } }
1
2
3
4
5
6
7
8
9
10
11
3.持久存儲
可以借助Sqlite數據庫或本地文件來實現,甚至可以將數據上傳到網絡上。先將數據存儲到本地,再
ViewModel對象以及持久存儲,以在配置變更時保存并恢復 Activity 的界面狀態。
Android
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。