Android系統設備配置變更處理

      網友投稿 1269 2022-05-28

      當android app發生屏幕旋轉、鍵盤可用性變化及用戶啟用多窗口模式時,正在運行的Activity會被重啟,即先調用onDestroy(),再調用 onCreate()方法。

      注意:屏幕方向、鍵盤可用性,以及當用戶啟用多窗口模式這些稱為設備配置,它們一開始就被配置好的。

      重啟的原因是為了可以使用新的資源來匹配新的設備配置。比如由豎屏旋轉為橫屏時,可能要使用不同的布局。這個重啟為這些改變提供了一個機會。我們就可以借此機會來利用與新設備配置相匹配的備用資源來自動重新加載我們的應用,從而幫助應用適應新配置。

      因為設備配置發生變化時,當前Activity會重啟,那么有些數據就可能會丟失,比如說用戶輸入的內容,因為那么輸入框在activity重啟時,都會被初始化為空。我們肯定是不希望丟失的。所以當發生配置變化時,我們如何做才能不丟失數據呢?這些數據我們通常都喜歡稱其為activity狀態(想想也確實如此,狀態就是要由數據來表現的)。

      針對設備變化的處理有兩種處理方式:

      1.自行處理設備配置變化

      如果重啟activity需要恢復大量數據、重新建立網絡連接等等,那么配置變化引起的activity重啟會嚴重影響用戶體驗,給用戶 感覺app的運行很慢。

      如果應用在設備配置變化時,不需要更新資源,并且考到慮性能的限制,盡量避免activity重啟,那么我們可以聲明 Activity 自行處理配置變更,從而阻止系統重啟 Activity。

      1.1.聲明由Activity 處理配置變更的方法

      在AndroidManifest.xml清單文件中編輯相應的 元素,增加android:configChanges屬性,該屬性的值表示要處理的配置。阻止系統在特定配置變更期間重啟您的 Activity。該屬性最常用的值包括 "orientation"、"screenSize" 、 "keyboardHidden"。可以在屬性中聲明多個配置值,方法是用管道 | 字符將其進行分隔。

      "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

      Android系統設備配置變更處理

      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() { // @Override // public void onChanged(DataBean dataBean) { // mET.setText(dataBean.getData()); // } // }); } @Override protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); MainModel mainModel = new ViewModelProvider(this,new ViewModelProvider.NewInstanceFactory()).get(MainModel.class); mainModel.getDataBean().observe(this, new Observer() { @Override public void onChanged(DataBean dataBean) { mET.setText(dataBean.getData()); } }); } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); MainModel mainModel = new ViewModelProvider(this,new ViewModelProvider.NewInstanceFactory()).get(MainModel.class); mainModel.doAction(mET.getText().toString()); } @Override protected void onDestroy() { super.onDestroy(); // MainModel mainModel = new ViewModelProvider(this,new ViewModelProvider.NewInstanceFactory()).get(MainModel.class); // mainModel.doAction(mET.getText().toString()); } }

      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 dataBeanLiveData = new MutableLiveData<>(); public LiveData getDataBean(){ return dataBeanLiveData; } public MainModel(){ // trigger databean load dataBeanLiveData.setValue(new DataBean()); } void doAction(String data){ // depending on the action, do necessary business logic calls and update the // userLiveData. dataBeanLiveData.getValue().setData(data); } }

      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小時內刪除侵權內容。

      上一篇:云計算產品設計腦洞
      下一篇:2021-08-26 網安實驗-Linux操作系統加固之Linux服務器通用安全加固指南
      相關文章
      含羞草国产亚洲精品岁国产精品| 亚洲七久久之综合七久久| 亚洲中文字幕久久精品蜜桃| 亚洲伊人久久大香线焦| 亚洲福利秒拍一区二区| 久久精品国产亚洲AV麻豆不卡| 亚洲精品你懂的在线观看| 亚洲欧洲日产国码无码久久99| 亚洲日韩aⅴ在线视频| 亚洲日本乱码在线观看| 亚洲精品无码久久久久sm| 亚洲国产成人一区二区精品区| 亚洲精品tv久久久久久久久| 亚洲国产成人精品无码区在线观看| 国产亚洲美日韩AV中文字幕无码成人 | 亚洲日韩精品无码AV海量| 亚洲一区二区观看播放| 亚洲人成网站色7799| 亚洲熟伦熟女专区hd高清| 亚洲成av人无码亚洲成av人| 亚洲欧美成人av在线观看| 亚洲国产精品无码久久98| 亚洲AV无码精品国产成人| 另类专区另类专区亚洲| 国产亚洲午夜精品| 亚洲精品tv久久久久久久久久| 国产成人99久久亚洲综合精品| 国产成人99久久亚洲综合精品 | 亚洲线精品一区二区三区| 国产成人无码综合亚洲日韩| 无码乱人伦一区二区亚洲| 亚洲最新中文字幕| 亚洲天堂免费在线| 亚洲AV无码一区二区三区网址| 一本色道久久88亚洲综合| 亚洲av乱码中文一区二区三区| 亚洲国产乱码最新视频| 亚洲色精品三区二区一区| www国产亚洲精品久久久日本| 久久久久亚洲精品中文字幕| 久久精品国产亚洲一区二区|