我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android-jetPack技术(Lifecycle、ViewModel、LiveData)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android-jetPack技术(Lifecycle、ViewModel、LiveData)

Android-jetPack技术(Lifecycle、ViewModel、LiveData) 简介

借用文档上面的话
Jetpack 是一套库、工具和指南,可帮助开发者更轻松地编写优质应用。这些组件可帮助您遵循最佳做法、让您摆脱编写样板代码的工作并简化复杂任务,以便您将精力集中放在所需的代码上。

Jetpack 包含与平台 API 解除捆绑的 androidx.* 软件包库。这意味着,它可以提供向后兼容性,且比 Android 平台的更新频率更高,以此确保您始终可以获取最新且最好的 Jetpack 组件版本。

Lifecycle 基本用发

创建了一个类去实现了androidx这个包里面的LifecycleObserver接口;
看后面这个Observer,就知道是个观察者
@OnLifecycleEvent(Lifecycle.Event.ON_START)订阅我们需要回调的生命周期;

package com.example.lk;
import android.util.Log;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;

public class MyLifeObserver implements LifecycleObserver {
    
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private void onStartJett(){
        Log.i("jett","onStartJett");
    }
}

在Activity或者fragment中使用,进行绑定

        //完成绑定
        getLifecycle().addObserver(new MyLifeObserver());
ViewModel 基本使用

用ViewModel,我们可以无论在哪个界面或者什么任务中,只要去获取这个仓库,就可以改变视图。
使用ViewModel记得要导入依赖

    //livedata+viewmodel
    implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'

我们创建了一个类去继承了ViewModel 这个类
定义一个对象,相当于一个用来存放数据的仓库MutableLiveData,记得需要使用static静态的
模拟数据,并将数据添加到仓库中 liveData.setValue(data);
每次数据更新的时候,就调用 liveData.setValue(data);,前提是我们得是从这个仓库中取出来的值liveData.getValue()
setValue 这个方法一定要在主线程中调用!
postValue这个方法可以在子线程中调用,其实最后还是会调用到setValue这个方法;
具体为什么需要在主线程调用,以为postValue这个方法的调用,后续源码中去看。

package com.example.lk.viewmodel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.example.lk.R;
import com.example.lk.bean.Girl;
import java.util.ArrayList;
import java.util.List;
public class MyGirl extends ViewModel {
    //定义一个对象,相当于一个用来存放数据的仓库
    private static MutableLiveData<List> liveData;
    //用于获取数据
    public LiveData<List> getDataBean(){
        if(liveData==null){
            liveData=new MutableLiveData();
            loadData();
        }
        return liveData;
    }
    
    private void loadData() {
        List data;
        data = new ArrayList();
        data.add(new Girl(R.drawable.f1, "一星", "****"));
        data.add(new Girl(R.drawable.f2, "一星", "****"));
        data.add(new Girl(R.drawable.f3, "一星", "****"));
        data.add(new Girl(R.drawable.f4, "一星", "****"));
        //把这些数据存放到仓库里面
        liveData.setValue(data);
    }
    //提供一个方法来改变数据
    public void changeValue(int item,int i){
        List value = liveData.getValue();
        value.get(item).setLike(i+"");
        liveData.setValue(value);	//主线程调用
       // liveData.postValue(value);	//子线程中调用
    }
}

我们去Activity中使用它

调用系统的API去初始化上面这个ViewModel; ViewModelProviders.of(this).get(MyGirl.class);
观察者订阅,用于数据更改时做更新myGirl.getDataBean().observe();
这样在其他地方一样的初始化这个ViewModel对象,都能去访问和更改这个数据了

package com.example.lk;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import com.example.lk.adapter.GirlAdapter;
import com.example.lk.bean.Girl;
import com.example.lk.viewmodel.MyGirl;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
    ListView listView;
    List data;
    MyGirl myGirl;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listView=(ListView)findViewById(R.id.listview);
        init();
        listView.setAdapter(new GirlAdapter(MainActivity.this,data));
        //完成绑定
        getLifecycle().addObserver(new MyLifeObserver());
        //调用系统API初始化这个对象
        myGirl= ViewModelProviders.of(this).get(MyGirl.class);
        myGirl.getDataBean().observe(this, new Observer<List>() {
            
            @Override
            public void onChanged(List girls) {
                listView.setAdapter(new GirlAdapter(MainActivity.this,girls));
            }
        });
        listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView parent, View view, int position, long id) {
                myGirl.changeValue(position,1);
                Intent intent=new Intent(MainActivity.this,SecActivity.class);
                MainActivity.this.startActivity(intent);
                return false;
            }
        });
    }
    //初始化默认数据
    private void init() {
        data = new ArrayList();
        data.add(new Girl(R.drawable.f1, "一星", "****"));
        data.add(new Girl(R.drawable.f2, "一星", "****"));
        data.add(new Girl(R.drawable.f3, "一星", "****"));
        data.add(new Girl(R.drawable.f4, "一星", "****"));
        data.add(new Girl(R.drawable.f5, "一星", "****"));
    }
}

例如我们新建一个类演示下

package com.example.lk;
import android.os.Bundle;
import android.widget.ListView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProviders;
import com.example.lk.bean.Girl;
import com.example.lk.viewmodel.MyGirl;
import java.util.List;
public class SecActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyGirl myGirl= ViewModelProviders.of(this).get(MyGirl.class);
        //一定要在主线程中调用
        myGirl.changeValue(0,666);
    }
}
LiveData 基本使用

在这里插入图片描述
LiveData在使用的过程中是不需要导入任何包的
低版本好像是需要导包,具体导啥包,可以自行百度…

这个类就是上面图中的总线
自定义了一个泛型的BusMutableLiveData继承了泛型MutableLiveData,这一块的自定义类可以不做,这里是为了解决一个问题,所以我这里定义了这个类;
因为有很多用户会做消息订阅,所以我们创建了Map来存放订阅者
定义了一个类去给用户做订阅的动作,也方便收集订阅者
这个自定义的BusMutableLiveData类里面,我们为了解决去解决一个事件执行顺序的问题:当我们在第一个界面订阅和发布消息的时候, 跳转到第二个界面,第二个界面订阅的是同一个消息,进入第二个界面的时候,就会直接接收到第一个界面发布的消息;应该要先订阅后,发布者发布消息,才接受到消息

package com.example.lk;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class LiveDataBus {
    //存放订阅者   因为用到反射,所以我们这里没有去用泛型,而是用了Objsect
    private Map<String, BusMutableLiveData> bus;
    //单例
    private static LiveDataBus liveDataBus=new LiveDataBus();
    private LiveDataBus(){
        bus=new HashMap();
    }
    public static LiveDataBus getInstance(){
        return liveDataBus;
    }
    
    public synchronized BusMutableLiveData with(String key,Class type){
        //如果是没有存过的
        if(!bus.containsKey(key)){
            //我们就去存
            bus.put(key,new BusMutableLiveData());
        }
        return (BusMutableLiveData) bus.get(key);
    }
    public static class BusMutableLiveData extends MutableLiveData{
        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
            super.observe(owner, observer);
            hook(observer);
        }
        
        private void hook(Observer observer) {
            try{
                //1.得到mLastVersion
                Class liveDataClass=LiveData.class;
                Field mObserversField = liveDataClass.getDeclaredField("mObservers");
                mObserversField.setAccessible(true);
                //获取到这个成员变量对应的对象
                Object mObserversObject = mObserversField.get(this);
                //得到map
                Class mObserversObjectClass = mObserversObject.getClass();
                //获取到mObservers对象的get方法
                Method get=mObserversObjectClass.getDeclaredMethod("get",Object.class);
                get.setAccessible(true);
                //执行get方法
                Object invokeEntry=get.invoke(mObserversObject,observer);
                //取到map中的value
                Object observerWraper=null;
                if(invokeEntry!=null && invokeEntry instanceof Map.Entry){
                    observerWraper=((Map.Entry)invokeEntry).getValue();
                }
                if(observerWraper==null){
                    throw new NullPointerException("observerWraper is null");
                }
                //得到ObserverWrapper的类对象
                Class superclass=observerWraper.getClass().getSuperclass();
                Field mLastVersion = superclass.getDeclaredField("mLastVersion");
                mLastVersion.setAccessible(true);
                //2.得到mVersion
                Field mVersion = liveDataClass.getDeclaredField("mVersion");
                mVersion.setAccessible(true);
                //3.把mVersion的值填入到mLastVersion中
                Object mVersionValue=mVersion.get(this);
                mLastVersion.set(observerWraper,mVersionValue);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

我们来看看为什么是反射去把这个mVersion填入到mLastVersion中就可以解决

既然是想让订阅者获取不到消息,那我们去阻止这个消息的发出
我们反射更改if (observer.mLastVersion >= mVersion) {)这个地方
如果有这个需求的,把上面的hook()方法注释掉

public abstract class LiveData {
 ......
 static final int START_VERSION = -1;
 private int mVersion = START_VERSION;
 ......
 private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
		//这里这个方法里面我们不去反射更改这个方法
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //我们来反射这一块
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }
 }

再来看看这个我们的LiveDataBus的使用

package com.example.lk;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //消费者订阅消息
        LiveDataBus.getInstance().with("huawei",Huawei.class)
                .observe(this,new Observer() {
                    @Override
                    public void onChanged(Huawei huawei) {
                        if(huawei!=null){
                            Toast.makeText(MainActivity.this, huawei.getType(), Toast.LENGTH_SHORT).show();
                        }
                    }
                });
    }
    
    public void sendMessage(View view) {
        Huawei huawei=new Huawei("META-20");
        //厂家发布消息
        LiveDataBus.getInstance().with("huawei",Huawei.class).postValue(huawei);
    }
    public void startSecActivity(View view) {
        Intent intent=new Intent(this,SecActivity.class);
        startActivity(intent);
    }
}
package com.example.lk;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
public class SecActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //消费者订阅消息
        LiveDataBus.getInstance().with("huawei",Huawei.class).observe(
                this,
                new Observer() {//观查者
                    @Override
                    public void onChanged(Huawei huawei) {
                        if(huawei!=null){
                            Toast.makeText(SecActivity.this, huawei.getType(), Toast.LENGTH_SHORT).show();
                        }
                    }
                }
        );
    }
    
    public void sendMessage(View view){
        Huawei huawei=new Huawei("META-20");
        //厂家发布消息
        LiveDataBus.getInstance().with("huawei",Huawei.class).postValue(huawei);
    }
}
浅析源码LiveData、ViewModel

我们这里看的是Android 26以后的源码;

ViewModelProviders.of(this)

先获取了一下Application;
factory工厂第一次进来是个空,所以通过单例ViewModelProvider.AndroidViewModelFactory.getInstance(application);去创建一个AndroidViewModelFactory工厂,这里就是个全局唯一的工厂了,所以后面进来的时候,这个工厂都是不为空的;
最终返回了一个ViewModelProvider对象,所以of最终得到的是ViewModelProvider对象;
activity.getViewModelStore()方法是从NonConfigurationInstances对象去取一个缓存的ViewModel集合(viewModelStore),如果没有的话会new一个ViewModelStore出来,这个viewModelStore里面创建了一个HashMap键值对存放ViewModel对象;

public class ViewModelProviders {
	......
 	@NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity) {
        return of(activity, null);
    }
    ......
        @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity,
            @Nullable Factory factory) {
        Application application = checkApplication(activity);
        if (factory == null) {
            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
        }
        return new ViewModelProvider(activity.getViewModelStore(), factory);
    }
    ......
    private static Application checkApplication(Activity activity) {
        Application application = activity.getApplication();
        if (application == null) {
            throw new IllegalStateException("Your activity/fragment is not yet attached to "
                    + "Application. You can't request ViewModel before onCreate call.");
        }
        return application;
    }
}
ViewModelProviders.of(this).get(MyGirl.class)

上面of方法调用得到的是这个ViewModelProvider对象吧?
调用get方法的时候是传入了我们自己写的ViewModel这个子类,最终获取到这个自己写的ViewMode的实例;
1、这个get方法中获取了这个传入进来的类的全类名;
2、在调用了重载的get方法,传入了key,这个key是通过拼接DEFAULT_KEY和类名的方式作为key;
3、通过调用mViewModelStore.get(key)获取到这个ViewModel,这个ViewModelStore里面是用了个HashMap集合,键值对的方式储存的,也就是这类读取内存中是否存在这个ViewModel对象;
4、我们在MainActivity中第一次使用,所以我们这里从HashMap中读取肯定是拿不到这个ViewModel的;
5、所以这里 if (modelClass.isInstance(viewModel)) {}不会被直接return出去;
6、走入下面,会判断我们上面创建的工厂类型,通过不同的工厂类型去创建我们的ViewModel,下面内部类AndroidViewModelFactory 的create方法,通过反射创建了ViewModel的实例,然后添加到缓存的HashMap中;后续进来的类在HashMap中通过全类名能拿到ViewModel的是将不会在此创建,而是从缓存的HashMap中去进行拿取直接返回;

public class ViewModelProvider {
    private static final String DEFAULT_KEY =
            "androidx.lifecycle.ViewModelProvider.DefaultKey";
    private final ViewModelStore mViewModelStore;
	......
	  @NonNull
    @MainThread
    public  T get(@NonNull Class modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }
	......
	 @NonNull
    @MainThread
    public  T get(@NonNull String key, @NonNull Class modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);
        if (modelClass.isInstance(viewModel)) {
            //noinspection unchecked
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }
	......
	 
    public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
        private static AndroidViewModelFactory sInstance;
        
        @NonNull
        public static AndroidViewModelFactory getInstance(@NonNull Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }
        private Application mApplication;
        
        public AndroidViewModelFactory(@NonNull Application application) {
            mApplication = application;
        }
        @NonNull
        @Override
        public  T create(@NonNull Class modelClass) {
            if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
                //noinspection TryWithIdenticalCatches
                try {
               		//反射的方法创建了ViewModel的实例
                    return modelClass.getConstructor(Application.class).newInstance(mApplication);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InstantiationException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                }
            }
            return super.create(modelClass);
        }
    }
}

ViewModelStore这个类
里面就是一个HashMap,用来缓存ViewModel


package androidx.lifecycle;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public class ViewModelStore {
    private final HashMap 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 keys() {
        return new HashSet(mMap.keySet());
    }
    
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}
数据共享

这里需要分析的是Activity与fragment之间的数据共享、以及屏幕旋转后,数据还有保存这一块;
我们的Activity是继承了AppCompatActivity这个Activity;
这个AppCompatActivity继承了FragmentActivity这个Activity;
这个FragmentActivity继承了ComponentActivity这个Activity;

onRetainNonConfigurationInstance()在onSaveInstanceState()之后被调用
这个方法里面会把ViewModelStore保存下来;
还记得这个ViewModelStore 吗?
这个类里面就是用HashMap通过键值对的方式存储了ViewModel对象
最终将这个存储ViewModel对象的缓存类保存到这个NonConfigurationInstances 对象的成员变量中去;
NonConfigurationInstances 类因为是静态的final内部类 所以这个类会一直跟着程序的生命周期吧,所以这个里面的成员变量是会常驻内存的吧,这个是Android 26以后源码中做的保存数据;
这里就会造成这一块的内存没有做释放,这样就会有助于ui重绘也不会丢失数据,屏幕旋转就是在重绘UI;

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {
        //因为是静态的final内部类 所以这个类会一直跟着程序的生命周期吧,也就是这个里面的成员变量是会常驻内存的吧
    static final class NonConfigurationInstances {
        Object custom;
        //缓存了ViewMpdel的这个类吧
        ViewModelStore viewModelStore;
    }
     ......
      @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        if (getApplication() == null) {
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }
 
    @Override
    @Nullable
    public final Object onRetainNonConfigurationInstance() {
        Object custom = onRetainCustomNonConfigurationInstance();
        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
            // No one called getViewModelStore(), so see if there was an existing
            // ViewModelStore from our last NonConfigurationInstance
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }
        if (viewModelStore == null && custom == null) {
            return null;
        }
		//公用的
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        //最终将这个存储ViewModel对象的缓存类保存到这个NonConfigurationInstances 对象的成员变量中去
        nci.viewModelStore = viewModelStore;
        return nci;
    }
    ......
}
LiveData订阅

接下来来看这一块

通过myGirl.getDataBean()获取到了LiveData对象;
然后调用了LiveData类里面的订阅方法observe

myGirl.getDataBean().observe(this, new Observer<List>() {
            
            @Override
            public void onChanged(List girls) {
                listView.setAdapter(new GirlAdapter(MainActivity.this,girls));
            }
        });

来看看这个observe这个方法

1、判断了下是否在主线程;
2、判断了下是否已经是onDestroy状态了;
3、将Activity和观察者包装到LifecycleBoundObserver这个对象里面;
4、将这个对象以键值对 的方式存入到集合,键(观察者),值(包装好的LifecycleBoundObserver对象),最终返回了一个ObserverWrapper对象;
5、最后调用addObserver(ObserverWrapper)进行了观察者的注册;
这里通过键值对的集合将这个观察者存了起来;

public abstract class LiveData {
......
	@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
    //判断是否在主线程
        assertMainThread("observe");
        //判断了下是否已经onDestroy了,也就是判断下了当前这个订阅的Activity是否已经被关闭了吧
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
    }
 ......
}
数据更改liveData.setValue(value);

还记得这个mVersion吗?
我们在上面hook反射的时候用到的了…
setValue这个方法的调用
1、主线程的判断;这里就是上面说的为什么要在主线程调用
2、mVersion版本号递增;
3、将需要修改的值赋值到了全局变量mData中;
4、调用分发的方法 dispatchingValue
插一句
上面我们说过postValue是可以在子线程中调用,并且最后还是会调用setValue()这个方法;
我们来看看postValue方法的调用,这个方法里面没有直接去判断主线程吧…
但是数据上的赋值是加了同步锁;
最后调用了 ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);传递进去了一个Runnable对象,这里面基本就是new了主线程的Handler,调用了post方法运行了这个Runnable;
在Runnable中调用了setValue这个方法,这就是我上面说到的postValue最终会调用setValue方法
分发dispatchingValue这个方法中
是调用了这个considerNotify方法去通知观察者的;
这里面做了些判断,注意下 if (observer.mLastVersion >= mVersion) {}这个判断,还记得我们当时hook反射的时候,更改的这两个值吗?
最终调用观察者的onChanged方法,给我们注册的观察者进行了回调

public abstract class LiveData {
    static final int START_VERSION = -1;
   private int mVersion = START_VERSION;
......
  private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            setValue((T) newValue);
        }
    };
......
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        //版本号递增
        mVersion++;
        mData = value;
        //调用分发
        dispatchingValue(null);
    }
    ......
    //进行分发
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
            //所有的观察者都拿了出来
                for (Iterator<Map.Entry<Observer, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
    ......
       protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
    ......
    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //回调观察者的onChanged方法
        observer.mObserver.onChanged((T) mData);
    }
    ......
}

可以看看这个postToMainThread方法的调用
就是我上面说的new了一个主线程的Handler,最终调用了handler的post方法去运行Runnable;
Looper.getMainLooper() 看过Handler源码的就知道这是拿到程序唯一的主线程Looper对象,这个Looper对象是在ActivityThread中创建的吧

public class DefaultTaskExecutor extends TaskExecutor {
......
@Override
    public void postToMainThread(Runnable runnable) {
        if (mMainHandler == null) {
            synchronized (mLock) {
                if (mMainHandler == null) {
                    mMainHandler = new Handler(Looper.getMainLooper());
                }
            }
        }
        //noinspection ConstantConditions
        mMainHandler.post(runnable);
    }
    ......
}
总结

ViewModel也是通过获得LiveData去做订阅

创建ViewModel
1、在创建ViewModel实例之前,先创建了ViewModelProvider对象,在创建ViewModelProvider对象的时候,还会去创建一个用来存放ViewModel的HashMap的对象ViewModelStore;
2、然后通过ViewModelProvider.get方法去获取ViewModel实例或者创建实例,里面先从ViewModelStore中的HashMap中通过key去获取ViewModel,为了就是查找是否有对应key的ViewModel缓存对象,如果有就直接用,如果没有就通过反射的方式创建了一个ViewModel实例,并存到了ViewModelStore中的HashMap中;

在订阅的时候
在订阅的时候,ViewModel通过获取到LiveData然后调用订阅的方法将我们new出来的观察者进行了包装,然后添加Map集合中,如果相同的ViewModel对象,那么久会存放在同一个观察者集合中;

setValue更改值的时候
用户更改数据调用postValue和setValue的时候,最终都是调用的是setValue这个方法,调用分发值的方法,三层判断后,调用了观察者的onChanged方法,将值回调给了观察者的onChanged的方法,这样我们在注册的观察者中,复写的onChanged方法中就能获取到set的值;

数据共享和屏幕旋转
至于这个ViewModel,在Android26以后,UI的重绘,fragment之间传值,都是可以直接用到这个ViewModel去给界面赋值,因为在ComponentActivity中,会将这个ViewModel储存的ViewModelStore对象进行赋值到一个内部类NonConfigurationInstances的成员变量中中,而这个内部类是一个静态的不可更改的类,所以这个类的生命周期跟随这个跟着应用,这个里面的ViewModelStore对象也会一直存在,直到应用结束


作者:倾尽杯中酒


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android-jetPack技术(Lifecycle、ViewModel、LiveData)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android-jetPack技术(Lifecycle、ViewModel、LiveData)

Android-jetPack技术(Lifecycle、ViewModel、LiveData) 简介 借用文档上面的话 Jetpack 是一套库、工具和指南,可帮助开发者更轻松地编写优质应用。这些组件可帮助您遵循最佳做法、让您摆脱编写样板代
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录