中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android?ViewModel創建不受橫豎屏切換影響怎么實現

發布時間:2023-03-08 10:43:45 來源:億速云 閱讀:121 作者:iii 欄目:開發技術

這篇“Android ViewModel創建不受橫豎屏切換影響怎么實現”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Android ViewModel創建不受橫豎屏切換影響怎么實現”文章吧。

ViewModel的創建方式

在我們項目中, 引入了viewModel 做MVI 設計模式的組成部分,它是JetPack 組件庫中的重要成員。今天來了解下它。

// 在 Activity 中使用
class MainActivity : AppCompatActivity() {
   // 使用 Activity 的作用域
   private val viewModel : MainViewModel by viewModels()
}
// 在 Fragment 中使用
class MainFragment : Fragment() {
   // 使用 Activity 的作用域,與 MainActivity 使用同一個對象
   val activityViewModel : MainViewModel by activityViewModels()
   // 使用 Fragment 的作用域
   val viewModel : MainViewModel by viewModels()
}
// ViewModel 創建工廠
private final Factory mFactory;
// ViewModel 存儲容器
private final ViewModelStore mViewModelStore;
// 默認使用 NewInstanceFactory 反射創建 ViewModel
public ViewModelProvider(ViewModelStoreOwner owner) {
    this(owner.getViewModelStore(), ... NewInstanceFactory.getInstance());
}
// 自定義 ViewModel 創建工廠
public ViewModelProvider(ViewModelStoreOwner owner, Factory factory) {
    this(owner.getViewModelStore(), factory);
}
// 記錄宿主的 ViewModelStore 和 ViewModel 工廠
public ViewModelProvider(ViewModelStore store, Factory factory) {
    mFactory = factory;
    mViewModelStore = store;
}
@NonNull
@MainThread
public <T extends ViewModel> T get(Class<T> modelClass) {
    String canonicalName = modelClass.getCanonicalName();
    if (canonicalName == null) {
        throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
    }
    // 使用類名作為緩存的 KEY
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
// Fragment
@NonNull
@MainThread
public <T extends ViewModel> T get(String key, Class<T> modelClass) {
    // 1. 先從 ViewModelStore 中取緩存
    ViewModel viewModel = mViewModelStore.get(key);
    if (modelClass.isInstance(viewModel)) {
        return (T) viewModel;
    }
    // 2. 使用 ViewModel 工廠創建實例
    viewModel = mFactory.create(modelClass);
    ...
    // 3. 存儲到 ViewModelStore
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}
// 默認的 ViewModel 工廠
public static class NewInstanceFactory implements Factory {
    private static NewInstanceFactory sInstance;
    @NonNull
    static NewInstanceFactory getInstance() {
        if (sInstance == null) {
            sInstance = new NewInstanceFactory();
        }
        return sInstance;
    }
    @NonNull
    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        // 反射創建 ViewModel 對象
        return modelClass.newInstance();
    }
}

可以看到:

ViewModel 實例的方法最終是通過 ViewModelProvider 完成的。ViewModelProvider 可以理解為創建 ViewModel 的工具類,它需要 2 個參數:

參數 1 ViewModelStoreOwner:

它對應于 Activity / Fragment 等持有 ViewModel 的宿主,它們內部通過 ViewModelStore 維持一個 ViewModel 的映射表,ViewModelStore 是實現 ViewModel 作用域和數據恢復的關鍵;

參數 2 Factory:

它對應于 ViewModel 的創建工廠,缺省時將使用默認的 NewInstanceFactory 工廠來反射創建 ViewModel 實例。

創建 ViewModelProvider 工具類后,你將通過 get() 方法來創建 ViewModel 的實例。get() 方法內部首先會通過 ViewModel 的全限定類名從映射表(ViewModelStore)中取緩存,未命中才會通過 ViewModel 工廠創建實例再緩存到映射表中。 正因為同一個 ViewModel 宿主使用的是同一個 ViewModelStore 映射表,因此在同一個宿主上重復調用 ViewModelProvider.get() 返回同一個 ViewModel 實例。

// ViewModel 本質上就是一個映射表而已
public class ViewModelStore {
   // <String - ViewModel> 哈希表
   private final HashMap<String, ViewModel> mMap = new HashMap<>();
   final void put(String key, ViewModel viewModel) {
       ViewModel oldViewModel = mMap.put(key, viewModel);
       if (oldViewModel != null) {
           oldViewModel.onCleared();
       }
   }
   final ViewModel get(String key) {
       return mMap.get(key);
   }
   Set<String> keys() {
       return new HashSet<>(mMap.keySet());
   }
   public final void clear() {
       for (ViewModel vm : mMap.values()) {
           vm.clear();
       }
       mMap.clear();
   }
}

ViewModel 宿主是 ViewModelStoreOwner 接口的實現類,例如 ComponentActivity:

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
    ContextAware,
    LifecycleOwner,
    ViewModelStoreOwner ... {
    // ViewModel 的存儲容器
    private ViewModelStore mViewModelStore;
    // ViewModel 的創建工廠
    private ViewModelProvider.Factory mDefaultFactory;
    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        if (mViewModelStore == null) {
            // 已簡化過程
            mViewModelStore = new ViewModelStore();
        }
        return mViewModelStore;
    }
}

由此,ViewModel 的創建其實跟activity 是相關聯的。

ViewModel 為什么不受 Activity 橫豎屏生命周期的影響

1、在 Activity 走到 onDestroy 方法時,做了判斷 isChangingConfigurations

Android?ViewModel創建不受橫豎屏切換影響怎么實現

可以看到,在 ComponentActivity 構造方法中添加了生命周期的判斷,當 Activity onDestroy 時,如果是發生了橫豎屏切換,就不會走 getViewModelStore().clear(),清理操作,保證了ViewModel 持有的數據還能存在。

2、在 Activity 獲取 getViewModelStore 時,

Android?ViewModel創建不受橫豎屏切換影響怎么實現

Android?ViewModel創建不受橫豎屏切換影響怎么實現

通過getLastNonConfigurationInstance() 獲取 NonConfigurationInstances 實例,從而得到這個實例中的 viewModelStore

Android?ViewModel創建不受橫豎屏切換影響怎么實現而且,Activity 生命周期的變化都會走這個方法,來保證viewModelStore 不為空。

Android?ViewModel創建不受橫豎屏切換影響怎么實現

3、onRetainNonConfigurationInstance 調用

在 Activity 屏幕旋轉時,onRetainNonConfigurationInstance()onStoponDestroy之間調用

onRetainNonConfigurationInstance() 是個重要的方法

Android?ViewModel創建不受橫豎屏切換影響怎么實現

這保證了 在銷毀前,viewModelStore 實例被拿到并交給 NonConfigurationInstances 實例,將 viewModelStore 賦值給他

Android?ViewModel創建不受橫豎屏切換影響怎么實現

以上就是關于“Android ViewModel創建不受橫豎屏切換影響怎么實現”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

灵宝市| 新疆| 万山特区| 平湖市| 垦利县| 湖口县| 原阳县| 朝阳县| 苍梧县| 茌平县| 城步| 万载县| 苍溪县| 武安市| 通许县| 宁晋县| 龙海市| 孟州市| 柘城县| 稻城县| 绥阳县| 东乡族自治县| 长丰县| 广水市| 临朐县| 亳州市| 铜鼓县| 朝阳县| 昌黎县| 丹凤县| 临潭县| 新丰县| 松溪县| 江孜县| 嵊泗县| 东乡族自治县| 阜平县| 揭西县| 吐鲁番市| 平江县| 商都县|