长洪 發表於 2019-9-18 20:32:00

Android开发 ViewModel_1_了解与简单使用

<h1><span style="color: rgba(0, 128, 128, 1)">版权声明</span></h1>
<p>本文来自博客园,作者:观心静&nbsp;,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/11545166.html</p>
<div>本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。</div>
<h1><span style="color: rgba(0, 128, 128, 1)">前言</span></h1>
<p><span style="color: rgba(0, 128, 128, 1)">  <span style="color: rgba(0, 0, 0, 1)">ViewModel是google推出的一个数据处理框架,ViewModel类是被设计用来以可感知生命周期的方式存储和管理 UI 相关数据ViewModel中数据会一直存活即使 activity configuration发生变化.另外它生来可能目的就是与Fragment在数据共享上进行配合的.</span></span></p>
<p><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">使用它常与LiveData数据前台类(类似观察者模式的数据实体回调类)进行配合以前使用,如果你未了解<span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">LiveData</span></span>建议你先了解它Android开发 LiveData与MutableLiveData详解<span class="postTitle2"> 然后在回头在来看这篇博客</span></span></span></p>
<p><span style="color: rgba(0, 0, 0, 1)">  在总结下有的这些特征:</span></p>
<p><span style="color: rgba(0, 0, 0, 1)">1.<strong>让数据与UI隔离:</strong>让ViewModel来获取数据加工数据并且回调给UI层.明确职责工作分离(参考MVP,MVVM这些框架结构)</span></p>
<p><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">2.<strong>数据与生命周期绑定</strong>:</span><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">ViewModel与注册的Activity的生命周期绑定,有着与Activity同步的生命周期,如下图.这样就算网络请求的数据的异步回来后Activity已经销毁也不会出现问题,因为<span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">ViewModel</span></span></span>也会被销毁终止数据的回调.</span></span></span></p>
<p><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 128, 128, 1)"><img src="https://img2018.cnblogs.com/blog/1497956/201909/1497956-20190919140353810-352580996.png" alt=""></span></span></p>
<p>&nbsp;</p>
<p><span style="color: rgba(0, 0, 0, 1)">3.<span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)"><strong>数据持久化</strong></span></span>:ViewModel不会因为屏幕的旋转导致Activity重新创建而重置数据.(这样避免了Activity被旋转数据丢失的问题)</span></p>
<p><span style="color: rgba(0, 0, 0, 1)">4.<strong>与其他Activity独立</strong>:ViewModel的数据是独立的,它跟每一个绑定的Activity都是实例一个单独的数据(意思是它无法跟多个Activity绑定后同步共享数据)</span></p>
<p><span style="color: rgba(0, 0, 0, 1)">5.<strong>天生为了配合<span style="color: rgba(0, 0, 0, 1)">Fragment</span></strong>:ViewModel可以与一个Activity与多个Fragment绑定后共享数据.(你终于可以不用很蛋疼的把Fragment的数据暂存到Activity里了)并且可以都与他们的生命周期关联.这样Fragment短暂的生命周期将不在让你烦恼数据的暂存问题.</span></p>
<h1><span style="color: rgba(0, 128, 128, 1)">依赖</span></h1>
<div class="cnblogs_code">
<pre>    implementation "androidx.fragment:fragment:1.1.0"<span style="color: rgba(0, 0, 0, 1)">
    implementation </span>"androidx.lifecycle:lifecycle-viewmodel:2.1.0"<span style="color: rgba(0, 0, 0, 1)">
    implementation </span>"androidx.lifecycle:lifecycle-extensions:2.1.0"</pre>
</div>
<p>androidx.lifecycle:lifecycle-extensions:2.1.0 是ViewModelProviders的实现依赖,如果不导入就没有这个。</p>
<h1><span style="color: rgba(0, 128, 128, 1)">创建与绑定Activity</span></h1>
<h3><span style="color: rgba(0, 0, 0, 1)">创建ViewModel</span></h3>
<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)"> DemoViewModel extends ViewModel {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO: Implement the ViewModel</span>
<span style="color: rgba(0, 0, 0, 1)">
    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onCleared() {
      super.onCleared();
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">清除的方法,这个方法需要让你处理一些网络请求的停止或者数据加工的逻辑停止,它与绑定的Activity在销毁的时候触发.你不需要手动在Activity里调用它</span>
<span style="color: rgba(0, 0, 0, 1)">    }
}</span></pre>
</div>
<p>&nbsp;</p>
<h3>绑定Activity</h3>
<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> Demo1Activity <span style="color: rgba(0, 0, 255, 1)">extends</span><span style="color: rgba(0, 0, 0, 1)"> AppCompatActivity {
    </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, 255, 1)">final</span> String TAG = "Demo1Activity"<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> DemoViewModel mDemoViewModel;

    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onCreate(Bundle savedInstanceState) {
      </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onCreate(savedInstanceState);
      setContentView(R.layout.activity_demo);
      mDemoViewModel </span>= ViewModelProviders.of(<span style="color: rgba(0, 0, 255, 1)">this</span>).get(DemoViewModel.<span style="color: rgba(0, 0, 255, 1)">class</span>);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取ViewModel,让ViewModel与此activity绑定</span>
<span style="color: rgba(0, 0, 0, 1)">      
    }
}</span></pre>
</div>
<p>以上简单继承和注册后就与Activity绑定了,它是单例模式的这点你可以在of()方法里看到它实现了单例(一个Activity只有一个单例),另外在<span style="color: rgba(0, 0, 0, 1)">Fragment的方式</span>也是与Activity相同的方式如下:</p>
<div class="cnblogs_code">
<pre>mViewModel = ViewModelProviders.of(getActivity()).get(DemoViewModel.<span style="color: rgba(0, 0, 255, 1)">class</span>);</pre>
</div>
<p>这样你就将Activity和<span style="color: rgba(0, 0, 0, 1)">Fragment</span>之间可以用ViewModel进行数据上的共享与同步了</p>
<p>&nbsp;</p>
<h1><span style="color: rgba(0, 128, 128, 1)">简单的demo</span></h1>
<p>&nbsp;  实际使用的时候是与<span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">LiveData</span></span>一起配合使用的,这里提供一个简单的demo了解下实际使用.</p>
<h2>创建LiveData类</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> DemoData <span style="color: rgba(0, 0, 255, 1)">extends</span> LiveData&lt;DemoData&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> tag1;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> tag2;

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getTag1() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> tag1;

    }
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setTag1(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> tag1) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.tag1 =<span style="color: rgba(0, 0, 0, 1)"> tag1;
      postValue(</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">);
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getTag2() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> tag2;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setTag2(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> tag2) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.tag2 =<span style="color: rgba(0, 0, 0, 1)"> tag2;
      postValue(</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">);
    }
}</span></pre>
</div>
<h2>创建ViewModel并且在内部实例化LiveData</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> DemoViewModel <span style="color: rgba(0, 0, 255, 1)">extends</span><span style="color: rgba(0, 0, 0, 1)"> ViewModel {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO: Implement the ViewModel</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> DemoData mDemoData = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> DemoData();

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> DemoData getDemoData() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> mDemoData;
    }

    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onCleared() {
      </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onCleared();
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">清除的方法,这个方法需要让你处理一些网络请求的停止或者数据加工的逻辑停止</span>
<span style="color: rgba(0, 0, 0, 1)">    }
}</span></pre>
</div>
<h1>绑定Activity,模拟数据变化</h1>
<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> Demo2Activity <span style="color: rgba(0, 0, 255, 1)">extends</span><span style="color: rgba(0, 0, 0, 1)"> AppCompatActivity {
    </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, 255, 1)">final</span> String TAG = "Demo2Activity"<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Button mBtnAddData;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> DemoViewModel mDemoViewModel;

    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onCreate(Bundle savedInstanceState) {
      </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onCreate(savedInstanceState);
      setContentView(R.layout.activity_demo2);
      mBtnAddData </span>=<span style="color: rgba(0, 0, 0, 1)"> findViewById(R.id.btn_add_data);
      mDemoViewModel </span>= ViewModelProviders.of(<span style="color: rgba(0, 0, 255, 1)">this</span>).get(DemoViewModel.<span style="color: rgba(0, 0, 255, 1)">class</span>);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取ViewModel,让ViewModel与此activity绑定</span>
      mDemoViewModel.getDemoData().observe(<span style="color: rgba(0, 0, 255, 1)">this</span>, <span style="color: rgba(0, 0, 255, 1)">new</span> Observer&lt;DemoData&gt;() { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">注册观察者,观察数据的变化</span>
<span style="color: rgba(0, 0, 0, 1)">            @Override
            </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onChanged(DemoData demoData) {
                Log.e(TAG, </span>"onChanged: 数据有更新"<span style="color: rgba(0, 0, 0, 1)">);
            }
      });

      mBtnAddData.setOnClickListener(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> View.OnClickListener() {
            @Override
            </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onClick(View v) {
                Log.e(TAG, </span>"onClick: 已经点击"<span style="color: rgba(0, 0, 0, 1)">);
                mDemoViewModel.getDemoData().setTag1(</span>123); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里手动用按键点击更新数据</span>
<span style="color: rgba(0, 0, 0, 1)">
            }
      });
    }
}</span></pre>
</div>
<h1>绑定<span style="color: rgba(0, 0, 0, 1)">Fragment</span></h1>
<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> DemoFragment <span style="color: rgba(0, 0, 255, 1)">extends</span><span style="color: rgba(0, 0, 0, 1)"> Fragment {
    </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, 255, 1)">final</span> String TAG = "DemoFragment"<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> DemoViewModel mViewModel;

    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                           @Nullable Bundle savedInstanceState) {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> inflater.inflate(R.layout.demo1_fragment, container, <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
    }

    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onActivityCreated(@Nullable Bundle savedInstanceState) {
      </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onActivityCreated(savedInstanceState);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO: Use the ViewModel</span>
      mViewModel = ViewModelProviders.of(getActivity()).get(DemoViewModel.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
      mViewModel.getDemoData().observe(</span><span style="color: rgba(0, 0, 255, 1)">this</span>, <span style="color: rgba(0, 0, 255, 1)">new</span> Observer&lt;DemoData&gt;<span style="color: rgba(0, 0, 0, 1)">() {
            @Override
            </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onChanged(DemoData demoData) {
                Log.e(TAG, </span>"onChanged: 数据有更新"<span style="color: rgba(0, 0, 0, 1)">);
               
            }
      });

    }
}</span></pre>
</div>
<h3><span style="color: rgba(0, 0, 0, 1)">Fragment绑定ViewModel , of(getActivity())与of(this)的区别</span></h3>
<div class="cnblogs_code">
<pre>mViewModel = ViewModelProviders.of(getActivity()).get(DemoViewModel.<span style="color: rgba(0, 0, 255, 1)">class</span>); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用getActivity()获得的ViewModel 作用域在<span style="color: rgba(0, 128, 0, 1)">Activity</span>里和所有他创建碎片的里,意思是你在其他Fragment也获取相同内存地址的ViewModel</span>
<span style="color: rgba(0, 0, 0, 1)">
mViewModel </span>= ViewModelProviders.of(<span style="color: rgba(0, 0, 255, 1)">this</span>).get(DemoViewModel.<span style="color: rgba(0, 0, 255, 1)">class</span>); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这个ViewModel是独立的,只为这个Fragment单独服务,其他Fragment无法获取到相同内存地址的<span style="color: rgba(0, 128, 0, 1)">ViewModel</span></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/11545166.html </p>
    <div style="color:orange;font-size:16px;">本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。 </div>
</div><br><br>
来源:https://www.cnblogs.com/guanxinjing/p/11545166.html
頁: [1]
查看完整版本: Android开发 ViewModel_1_了解与简单使用