六月牛 發表於 2020-1-15 21:55:00

Android开发 ViewModel_2_了解多种自定义实例方式 (Factory 与 key)

<h1><span style="color: rgba(0, 128, 128, 1)">前言</span></h1>
<p>  ViewModel的虽然可以以很简单方便的<span style="color: rgba(0, 0, 0, 1)"> ViewModelProviders.of(getActivity()).get(ViewModel.class); 但是这只是google提供的简单构建,你需要引入下面的库才能使用:</span></p>
<div class="cnblogs_code">
<pre>implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"</pre>
</div>
<p><span style="color: rgba(0, 0, 0, 1)">但是!<span style="color: rgba(0, 0, 0, 1)">远远不止这样。l还可以使用ViewModelProvider.Factory自定义实例ViewModel(其实继承工厂类实例ViewModel才是google推荐的,这点在Android studio的模板代码里可以看到)</span></span></p>
<p><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">  转载请注明来源:https://www.cnblogs.com/guanxinjing/p/12198971.html</span></span></p>
<h1><span style="color: rgba(0, 128, 128, 1); background-color: rgba(255, 255, 255, 1)">为什么要学习ViewModel自定义实例?</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">  那么你可能会疑问了,使用 <span style="color: rgba(0, 0, 0, 1)">ViewModelProviders.of(getActivity()).get(ViewModel.class); </span>创建ViewModel这么简单轻松,为什么还要自己构建Factory呢。原因有以下几点:</span></span></span></span></p>
<ol>
<li><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">如果你继承的ViewModel类是有参构造,那么上面这个方式是不支持在实例ViewModel的传参的,所以需要自己构建<span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">Factory</span></span>类</span></span></span></span></li>
<li><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">一个Activity可能根据业务会有多个不同的ViewModel,那么根据不同的业务下配置不同的ViewModel,<span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">需要自己构建<span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">Factory类</span></span></span></span></span></span>,来根据类别返回不同的ViewModel给外部(这也是工厂模式的核心,解决接口选择的问题)</span></span></span></span></li>
</ol>
<h1><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 128, 128, 1)">了解</span>ViewModel的构建原理</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">  因为后续的使用ViewModelProvider.Factory创建ViewModel,所以我们必需了解一些些ViewModel构建、保存、移除原理。好在有一个参照物可以阅读理解,那就是上面提到以<span style="color: rgba(0, 0, 0, 1)"> ViewModelProviders </span>形式的构建<span style="color: rgba(0, 0, 0, 1)">ViewModel</span>。对照着它看基本上就能明白一些东西了。</span></p>
<h2><span style="color: rgba(0, 0, 0, 1)">看看 <span style="color: rgba(0, 0, 0, 1)">ViewModelProviders.of() 干了啥事情</span></span></h2>
<p><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">我们点击进入源码后可以看到如下代码</span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">    @NonNull
    @MainThread
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> ViewModelProvider of(@NonNull FragmentActivity activity) {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> of(activity, <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
    }</span></pre>
</div>
<p>恩,of又去调用了一个重载的of,但是传入了一个activity或者Fragment 和 一个null ,我们看看这个2个参数的of干了什么</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">    @NonNull
    @MainThread
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> ViewModelProvider of(@NonNull FragmentActivity activity,
            @Nullable Factory factory) {
      Application application </span>= checkApplication(activity); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">源码在这里检查了一下activity的application</span>
      <span style="color: rgba(0, 0, 255, 1)">if</span> (factory == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">它拿application去创建了一个Factory类
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这个factory其实就是构建ViewModel的工厂类</span>
            factory =<span style="color: rgba(0, 0, 0, 1)"> ViewModelProvider.AndroidViewModelFactory.getInstance(application);
      }
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">实例化了一个ViewModelProvider,
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">在activity里取得ViewModelStore(这个东西是用于保存ViewModel使用的),也传入了
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">并且也把Factory类一起传入
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">其实ViewModelStore和factory传入后就直接成为成员变量缓存了,等待你调用get方法来创建ViewModel</span>
      <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ViewModelProvider(activity.getViewModelStore(), factory);
    }</span></pre>
</div>
<p>我们可以看看<span style="color: rgba(0, 0, 0, 1)">ViewModelProvider.AndroidViewModelFactory.getInstance(application)</span> 这行代码</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> AndroidViewModelFactory sInstance;

      </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * Retrieve a singleton instance of AndroidViewModelFactory.
         *
         * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> application an application to pass in {</span><span style="color: rgba(128, 128, 128, 1)">@link</span><span style="color: rgba(0, 128, 0, 1)"> AndroidViewModel}
         * </span><span style="color: rgba(128, 128, 128, 1)">@return</span><span style="color: rgba(0, 128, 0, 1)"> A valid {</span><span style="color: rgba(128, 128, 128, 1)">@link</span><span style="color: rgba(0, 128, 0, 1)"> AndroidViewModelFactory}
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
      @NonNull
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> AndroidViewModelFactory getInstance(@NonNull Application application) {
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (sInstance == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                sInstance </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> AndroidViewModelFactory(application);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sInstance;
      }</span></pre>
</div>
<p>可以看到,直接给你了一个有Application的全局单例的<span style="color: rgba(0, 0, 0, 1)">Factory类。</span></p>
<h2><span style="color: rgba(0, 0, 0, 1)">接下来看看<span style="color: rgba(0, 0, 0, 1)">ViewModelProviders.of().get(<span style="color: rgba(0, 0, 128, 1); font-weight: bold">)</span></span> &nbsp;&nbsp; get方法干了啥事 </span></h2>
<p>  get()方法其实就是实现了<span style="color: rgba(0, 0, 0, 1)"> factory 创建 与 ViewModelStore保存 ViewModel,并且返回<span style="color: rgba(0, 0, 0, 1)">ViewModel</span>。 我们可以看看下面这些代码</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">    @NonNull
    @MainThread
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> &lt;T <span style="color: rgba(0, 0, 255, 1)">extends</span> ViewModel&gt; T get(@NonNull Class&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)"> modelClass) {
      String canonicalName </span>= modelClass.getCanonicalName(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取了传入的实现的ViewModel的类名</span>
      <span style="color: rgba(0, 0, 255, 1)">if</span> (canonicalName == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
            </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> IllegalArgumentException("Local and anonymous classes can not be ViewModels"<span style="color: rgba(0, 0, 0, 1)">);
      }
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">因为我们没有传入key,所以这里直接用类名取代的成为了key
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">然后就进入下面这个重载的get方法里进行实现了</span>
      <span style="color: rgba(0, 0, 255, 1)">return</span> get(DEFAULT_KEY + ":" +<span style="color: rgba(0, 0, 0, 1)"> canonicalName, modelClass);
    }

    @NonNull
    @MainThread
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> &lt;T <span style="color: rgba(0, 0, 255, 1)">extends</span> ViewModel&gt; T get(@NonNull String key, @NonNull Class&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)"> modelClass) {
      ViewModel viewModel </span>= mViewModelStore.get(key);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">去查找这个ViewModelStore 对应key的保存viewModel</span>

      <span style="color: rgba(0, 0, 255, 1)">if</span> (modelClass.isInstance(viewModel)) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">检查一下这个viewModel是不是已经实例化,不是null
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">noinspection unchecked</span>
            <span style="color: rgba(0, 0, 255, 1)">return</span> (T) viewModel;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果已经实例化,不等于null就直接返回</span>
      } <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">noinspection StatementWithEmptyBody</span>
            <span style="color: rgba(0, 0, 255, 1)">if</span> (viewModel != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO: log a warning.</span>
<span style="color: rgba(0, 0, 0, 1)">            }
      }
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">下面就用传入的Factory类来实例化你需要的ViewModel</span>
      <span style="color: rgba(0, 0, 255, 1)">if</span> (mFactory <span style="color: rgba(0, 0, 255, 1)">instanceof</span> KeyedFactory) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里检查是不是带key</span>
            viewModel =<span style="color: rgba(0, 0, 0, 1)"> ((KeyedFactory) (mFactory)).create(key, modelClass);
      } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
            viewModel </span>=<span style="color: rgba(0, 0, 0, 1)"> (mFactory).create(modelClass); <span style="color: rgba(0, 128, 0, 1)">//<span style="color: rgba(0, 128, 0, 1)">这里的create使用了反射的形式创建实例</span></span>
      }
      mViewModelStore.put(key, viewModel); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">然后存一下ViewModel
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">noinspection unchecked</span>
      <span style="color: rgba(0, 0, 255, 1)">return</span> (T) viewModel; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">返回viewModel</span>
    }</pre>
</div>
<h2>移除缓存的<span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">ViewModel</span></span></h2>
<p><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">  其实蛛丝马迹就在<span style="color: rgba(0, 0, 0, 1)">ViewModelStore</span>里</span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ViewModelStore {

    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span> HashMap&lt;String, ViewModel&gt; mMap = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">();

    </span><span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> put(String key, ViewModel viewModel) {
      ViewModel oldViewModel </span>=<span style="color: rgba(0, 0, 0, 1)"> mMap.put(key, viewModel);
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (oldViewModel != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
            oldViewModel.onCleared();
      }
    }

    </span><span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> ViewModel get(String key) {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> mMap.get(key);
    }

    Set</span>&lt;String&gt;<span style="color: rgba(0, 0, 0, 1)"> keys() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> HashSet&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">(mMap.keySet());
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   *Clears internal storage and notifies ViewModels that they are no longer used.
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">void</span> clear() { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里清理了当前Activity或者Fragment的所有ViewModel,这个方法是在Activity或者Fragment在销毁的时候有调用的</span>
      <span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (ViewModel vm : mMap.values()) {
            vm.clear();
      }
      mMap.clear();
    }
}</span></pre>
</div>
<h1>&nbsp;</h1>
<h1><span style="color: rgba(0, 128, 128, 1)">使用ViewModelProvider.Factory实现创建ViewModel</span></h1>
<h2>&nbsp;使用反射创建无参实例(在上面的源码上可以看到的创建方式,这样一个Factory就可以传入继承ViewModel的泛型,加以实例)</h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> MainViewModelFactory <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> ViewModelProvider.Factory {
    @NonNull
    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> &lt;T <span style="color: rgba(0, 0, 255, 1)">extends</span> ViewModel&gt; T create(@NonNull Class&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)"> modelClass) {
      </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> modelClass.newInstance(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用newInstance反射实例ViewModel,并且传出去</span>
      } <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IllegalAccessException e) {
            e.printStackTrace();
      } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InstantiationException e) {
            e.printStackTrace();
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;

    }
}</span></pre>
</div>
<p><span style="color: rgba(0, 0, 0, 1)">使用MainViewModelFactory创建ViewModel,<strong><span style="color: rgba(255, 0, 0, 1)">注意!</span>千万别自己就使用Factory直接创建ViewModel</strong>,因为上面的get()源码里说明了,这个ViewModel是还需要保存到ViewModelStore里面的,而ViewModelStore的put方法是私有方法。所以我们还是需要交给ViewModelProviders.of().get();来创建让它帮我们保存到<span style="color: rgba(0, 0, 0, 1)">ViewModelStore</span>里,代码如下:</span></p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> MainViewModel mMainViewModel;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> initViewModel() {
      MainViewModelFactory mainViewModelFactory </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MainViewModelFactory();
      mMainViewModel </span>= ViewModelProviders.of(<span style="color: rgba(0, 0, 255, 1)">this</span>, mainViewModelFactory).get(MainViewModel.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
    }</span></pre>
</div>
<h2>使用反射创建有参实例</h2>
<p>代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> MainViewModelFactory4 <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> ViewModelProvider.Factory {
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String mValue;

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> MainViewModelFactory4(String value){
      mValue </span>=<span style="color: rgba(0, 0, 0, 1)"> value;
    }

    @NonNull
    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> &lt;T <span style="color: rgba(0, 0, 255, 1)">extends</span> ViewModel&gt; T create(@NonNull Class&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)"> modelClass) {
      </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            Class[] parameterTypeArray </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Class[]{String.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">};
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> modelClass.getConstructor(parameterTypeArray).newInstance(mValue);
      } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IllegalAccessException e) {
            e.printStackTrace();
      } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InstantiationException e) {
            e.printStackTrace();
      } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (NoSuchMethodException e) {
            e.printStackTrace();
      } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InvocationTargetException e) {
            e.printStackTrace();
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;

    }
}</span></pre>
</div>
<p>还是跟上面一样使用<span style="color: rgba(0, 0, 0, 1)">ViewModelProviders.of().get();</span>来创建。</p>
<h2>简单暴力直接实例目标ViewModel</h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> MainViewModelFactory <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> ViewModelProvider.Factory {
    @NonNull
    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> &lt;T <span style="color: rgba(0, 0, 255, 1)">extends</span> ViewModel&gt; T create(@NonNull Class&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)"> modelClass) {
      MainViewModel mainViewModel </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MainViewModel();
      mainViewModel.setContent(</span>"设置初始化值"<span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (T)mainViewModel;

    }
}</span></pre>
</div>
<p>还是跟上面一样使用<span style="color: rgba(0, 0, 0, 1)">ViewModelProviders.of().get();来创建。</span></p>
<h1><span style="color: rgba(0, 128, 128, 1)">使用KEY创建ViewModel</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">这没啥好说的,就是根据不同的key创建独立数据与内存地址的ViewModel,他们之间数据不互通。</span></span></p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<pre>      mMainViewModel1 = ViewModelProviders.of(<span style="color: rgba(0, 0, 255, 1)">this</span>).get("1", MainViewModel.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
      mMainViewModel2 </span>= ViewModelProviders.of(<span style="color: rgba(0, 0, 255, 1)">this</span>).get("2", MainViewModel.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
      mMainViewModel3 </span>= ViewModelProviders.of(<span style="color: rgba(0, 0, 255, 1)">this</span>).get("3", MainViewModel.<span style="color: rgba(0, 0, 255, 1)">class</span>);</pre>
</div>
<p>&nbsp;</p>
<h1><span style="color: rgba(0, 128, 128, 1)">关于ViewModelProvider.NewInstanceFactory</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">也是继承Factory,然后帮你实现了newInstance();如果你只是简简单单实例一个ViewModel,可以直接继承这个,我们可以看源码:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * Simple factory, which calls empty constructor on the give class.
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">class</span> NewInstanceFactory <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> Factory {

      @SuppressWarnings(</span>"ClassNewInstance"<span style="color: rgba(0, 0, 0, 1)">)
      @NonNull
      @Override
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> &lt;T <span style="color: rgba(0, 0, 255, 1)">extends</span> ViewModel&gt; T create(@NonNull Class&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)"> modelClass) {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">noinspection TryWithIdenticalCatches</span>
            <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> modelClass.newInstance();
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InstantiationException e) {
                </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> RuntimeException("Cannot create an instance of " +<span style="color: rgba(0, 0, 0, 1)"> modelClass, e);
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IllegalAccessException e) {
                </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> RuntimeException("Cannot create an instance of " +<span style="color: rgba(0, 0, 0, 1)"> modelClass, e);
            }
      }
    }</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">关于ViewModelProvider.AndroidViewModelFactory</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">带application的工厂类,你需要配置一个需要application的ViewModel,可以直接使用这个单例的AndroidViewModelFactory。可以看源码(下面的代码上面已经贴了一部分了,这里贴全),需要一个构造方式是传入<span style="color: rgba(0, 0, 0, 1)">application</span>的ViewModel:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">class</span> AndroidViewModelFactory <span style="color: rgba(0, 0, 255, 1)">extends</span><span style="color: rgba(0, 0, 0, 1)"> ViewModelProvider.NewInstanceFactory {

      </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> AndroidViewModelFactory sInstance;

      </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * Retrieve a singleton instance of AndroidViewModelFactory.
         *
         * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> application an application to pass in {</span><span style="color: rgba(128, 128, 128, 1)">@link</span><span style="color: rgba(0, 128, 0, 1)"> AndroidViewModel}
         * </span><span style="color: rgba(128, 128, 128, 1)">@return</span><span style="color: rgba(0, 128, 0, 1)"> A valid {</span><span style="color: rgba(128, 128, 128, 1)">@link</span><span style="color: rgba(0, 128, 0, 1)"> AndroidViewModelFactory}
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
      @NonNull
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> AndroidViewModelFactory getInstance(@NonNull Application application) {
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (sInstance == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                sInstance </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> AndroidViewModelFactory(application);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sInstance;
      }

      </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Application mApplication;

      </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * Creates a {</span><span style="color: rgba(128, 128, 128, 1)">@code</span><span style="color: rgba(0, 128, 0, 1)"> AndroidViewModelFactory}
         *
         * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> application an application to pass in {</span><span style="color: rgba(128, 128, 128, 1)">@link</span><span style="color: rgba(0, 128, 0, 1)"> AndroidViewModel}
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
      <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> AndroidViewModelFactory(@NonNull Application application) {
            mApplication </span>=<span style="color: rgba(0, 0, 0, 1)"> application;
      }

      @NonNull
      @Override
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> &lt;T <span style="color: rgba(0, 0, 255, 1)">extends</span> ViewModel&gt; T create(@NonNull Class&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)"> modelClass) {
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (AndroidViewModel.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">.isAssignableFrom(modelClass)) {
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">noinspection TryWithIdenticalCatches</span>
                <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span> modelClass.getConstructor(Application.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">).newInstance(mApplication);
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (NoSuchMethodException e) {
                  </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> RuntimeException("Cannot create an instance of " +<span style="color: rgba(0, 0, 0, 1)"> modelClass, e);
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IllegalAccessException e) {
                  </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> RuntimeException("Cannot create an instance of " +<span style="color: rgba(0, 0, 0, 1)"> modelClass, e);
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InstantiationException e) {
                  </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> RuntimeException("Cannot create an instance of " +<span style="color: rgba(0, 0, 0, 1)"> modelClass, e);
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InvocationTargetException e) {
                  </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> RuntimeException("Cannot create an instance of " +<span style="color: rgba(0, 0, 0, 1)"> modelClass, e);
                }
            }
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.create(modelClass);
      }
    }</span></pre>
</div>
<p>&nbsp;</p>
<p>End</p>

</div>
<div id="MySignature" role="contentinfo">
    <div style="text-align: center">
    <p style="color:orange;font-size:16px;" >本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/12198971.html </p>
    <div style="color:orange;font-size:16px;">本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。 </div>
</div><br><br>
来源:https://www.cnblogs.com/guanxinjing/p/12198971.html
頁: [1]
查看完整版本: Android开发 ViewModel_2_了解多种自定义实例方式 (Factory 与 key)