美文网首页
Jetpack---LifeCycle/LiveData/Vie

Jetpack---LifeCycle/LiveData/Vie

作者: 大苏打6815 | 来源:发表于2020-05-06 18:37 被阅读0次
    Jetpack 是一套库、工具和指南,可帮助开发者更轻松地编写优质应用。这些组件可帮助您遵循最佳做法、让您摆脱编写样板代码的工作并简化复杂任务,以便您将精力集中放在所需的代码上。Jetpack 包含与平台 API 解除捆绑的 androidx.* 软件包库。这意味着,它可以提供向后兼容性,且比 Android 平台的更新频率更高,以此确保您始终可以获取最新且最好的 Jetpack 组件版本。

    前几篇都是用MVP写的demo,下面讲解jetpack的时候可能换成MVC会比较更容易理解,当然了,也可以直接放在MVP里面用。jetpck的使用,可以让你的项目焕然一新,个人觉得对安卓新入门的门槛至少砍掉了百分之三十。及时了解这些技术还是有必要的,哪怕我目前项目里面目前还没用上,说不定哪一天就用上了呢?(新建项目的时候把androidx勾上)

    我们这篇主要讲解lifecycle/livedata-viewmodel/livedatabus

    一 Lifycycles(管理Activity或者fragment的生命周期)

    如果我们在项目中,想监控生命周期实现业务逻辑,我们以前一般常规的做发就是先声明一个接口,新建一个类去实现接口,然后再所对应的Activity或者fragment里面创建对象然后调用其里面的方法这三步。

    public class Main implements IMain{
        @Override
        public void onStart() {
        }
    
        @Override
        public void onStop() {
        }
    }
    
    public interface IMain {
        public void onStart();
        public void onStop();
    }
    
    public class MainActivity extends AppCompatActivity {
        Main maincycle=new Main();
        @Override
        protected void onStart(){
            super.onStart();
            maincycle.onStart();
        }
    }
    

    这样的话很麻烦,每次都要新创建一个对象。我们完全可以用lifecycleobserver来替代。注意@OnLifecycleEvent(Lifecycle.Event.ON_START)里面有提供的的声明周期方法,自己选择,这样当走到对应的生命周期方法中的时候就会打印log,根据业务需求可以实现对应的逻辑。

    /**
     * 我们用这个观查者来盯好需要感知生命周期的对象 */
    public class MyLifeObserver implements LifecycleObserver {
        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        private void onStartJett(){
            Log.i("dasuda","onStartSuda");
        }
    }
    

    然后再其Activity或者fragement的oncreat初始化里面实现绑定

     protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //完成绑定
            getLifecycle().addObserver(new MyLifeObserver());
    }
    

    那么在我们之前写的标准的MVP模式里面怎样加入这个lifecycle呢?(lifecycle在MVC,MVP,MVVM都能加)42_JetPackAndMvp
    首先我们在BasePresent里面定义好这些声明周期方法,记得要实现这个lifecycleObserver等接口

    public class BasePresenter<T extends IBaseView> implements LifecycleObserver,LifecycleOwner {
    
        //持有左边(VIEW)
    //    IGirlView iGirlView;
        WeakReference<T> iGirlView;
    
        public void attachView(T view){
            iGirlView=new WeakReference<>(view);
        }
        public void detachView(){
            if(iGirlView!=null){
                iGirlView.clear();
                iGirlView=null;
            }
        }
    
        @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
        void onAny(LifecycleOwner owner){
    
        };
    
        @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
        void onCreate(LifecycleOwner owner){
    
        };
    
        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        void onStart(LifecycleOwner owner){};
    
        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        void onStop(LifecycleOwner owner){};
    
        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        void onResume(LifecycleOwner owner){};
    
        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        void onPause(LifecycleOwner owner){};
    
        @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        void onDestory(LifecycleOwner owner){};
    
        @NonNull
        @Override
        public Lifecycle getLifecycle() {
            return null;
        }
    
    

    然后我i们在对应的GirlPresenter(继承至BasePresenter的)里面去重写这些方法,可以自己有需求的重写哪几个,比如我选择两个

    @Override
        void onDestory(LifecycleOwner owner) {
            super.onDestory(owner);
            Log.i("dasuda","onDestory");
        }
    
        @Override
        void onCreate(LifecycleOwner owner) {
            super.onCreate(owner);
            Log.i("dasuda","onCreate");
        }
    

    然后再所对应的Activity或者fragment的初始化里面完成绑定这个Presenter

     @Override
        protected void init() {
            //完成绑定(订阅关系)
            getLifecycle().addObserver(presenter);
        }
    
    二 viewmodel+livedata

    标准写法目前可以再fragment与fragment,或者fragment与Activity之间相互传输数据
    一个极好的MVVM框架和jetpack使用的demo https://github.com/KunMinX/Jetpack-MVVM-Best-Practice

    需要添加依赖implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
    首先我们新建一个类继承Viewmodel。这个就相当于存放数据的仓库’
    注意:用static修饰MutableLiveData是livedata用的同一个布局文件,一般来说项目里面99%都不会用同一个文件。这里示例是用的同一个文件,如果不这样用会报错。官方文档上面不是用的static修饰,那是因为他每一个livedata用的布局文件不一样。

    public class MyGirl extends ViewModel {
        //定义一个对象,相当于一个用来存放数据的仓库
        private static MutableLiveData<List<Girl>> liveData;
        //用于获取数据
        public LiveData<List<Girl>> getDataBean(){
            if(liveData==null){
                liveData=new MutableLiveData<>();
                loadData();
            }
            return liveData;
        }
    
        private void loadData() {
            List<Girl> 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, "一星", "****"));
            data.add(new Girl(R.drawable.f5, "一星", "****"));
            data.add(new Girl(R.drawable.f6, "一星", "****"));
            data.add(new Girl(R.drawable.f7, "一星", "****"));
            data.add(new Girl(R.drawable.f8, "一星", "****"));
            data.add(new Girl(R.drawable.f9, "一星", "****"));
            data.add(new Girl(R.drawable.f10, "一星", "****"));
    
            //把这些数据存放到仓库里面
            liveData.setValue(data);
        }
    
    
        //提供一个方法来改变数据
        public void changeValue(int item,int i){
            List<Girl> value = liveData.getValue();
            value.get(item).setLike(i+"");
            liveData.setValue(value);
    
        }
    }
    

    然后我们再Activity的oncreat方法或者fragment里面初始化的时候调用,这样就完成了初始化的操作

     //调用系统API初始化这个对象
            myGirl= ViewModelProviders.of(this).get(MyGirl.class);
            myGirl.getDataBean().observe(this, new Observer<List<Girl>>() {
                /**
                 * 当我们的数据发生变化的时候,我们可以在这个onChanged中进行处理
                 * @param girls
                 */
                @Override
                public void onChanged(List<Girl> girls) {
                    listView.setAdapter(new GirlAdapter(MainActivity.this,girls));
                }
            });
    

    我们写个示例,listview条目上面我们随便把一个item长按,让他立刻改变成我们想要变化的样子,下面的myGirl.changeValue(position,1);是我们再MyGirl这个类里面新增加的一个方法便于理解的。可以随时修改listview所在positon当中内容的变化

    listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                    myGirl.changeValue(position,1);
                    return false;
                }
            });
    
    三 事件总线设计---livedatabus(不能跨进程的)(不需要导任何包)

    相对比Rxbus,eventbus,内存泄露源码都已经给你做好了,不会造成内存泄漏
    我们设想一下,A,B,C三个用户,要在京东淘宝上面买苹果华为手机,我们称ABC为订阅者,苹果华为厂商为发布者,而京东淘宝只是个代理商也称为总线,由代理商统一统计上报给手机厂商,然后手机下来后分布给各个不同的订阅者。总线相当于存放了map来存放订阅者。

    首先我们写一个demo看看效果,首先写一个华为的bean类

    public class Huawei {
        public String type;
    
        public Huawei(String type) {
            this.type = type;
        }
    
        public String getType() {
            return type;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    }
    

    然后我们写一个事件总线LiveDataBus

    /**
     * 这个类就是我们的总线(天猫,京东)
     */
    public class LiveDataBus {
        //存放订阅者
        private Map<String, BusMutableLiveData<Object>> bus;
    
        //单例
        private static LiveDataBus liveDataBus=new LiveDataBus();
        private LiveDataBus(){
            bus=new HashMap<>();
        }
        public static LiveDataBus getInstance(){
            return liveDataBus;
        }
    
        /**
         * 用来给用户进行订阅(存入map)
         */
        public synchronized<T> BusMutableLiveData<T> with(String key,Class<T> type){
            if(!bus.containsKey(key)){
                bus.put(key,new BusMutableLiveData<Object>());
            }
            return (BusMutableLiveData<T>) bus.get(key);
        }
    
        public static class BusMutableLiveData<T> extends MutableLiveData<T>{
            @Override
            public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
                super.observe(owner, observer);
                hook(observer);
            }
    
            private void hook(Observer<? super T> observer) {
                try{
                    //1.得到mLastVersion
                    Class<LiveData> 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();
                }
            }
        }
    
    }
    

    注意:以上方法public synchronized<T> BusMutableLiveData<T> with(String key,Class<T> type)。这个Class一定要写,不然系统没办法反射到这个内容的。public static class BusMutableLiveData<T> extends MutableLiveData<T>这个继承类是已经经过优化了的。这是系统里面的一个bug。稍后我们看一下。

    我们再主Activity里面去订阅,发布

    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<Huawei>() {
                        @Override
                        public void onChanged(Huawei huawei) {
                            if(huawei!=null){
                                Toast.makeText(MainActivity.this, huawei.getType(), Toast.LENGTH_SHORT).show();
                            }
                        }
                    });
    
        }
    
        /**
         * 这里就是一个发布者(苹果,华为)
         * @param view
         */
        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);
        }
    

    到了这里我们点击一个sendMessge按钮,对应的上面就有一个吐司了。说明订阅初始化成功了,也成功发布了。
    我们假设一下,跳转到另外一个SecondActivity,并且同样订阅,发布.SecondActivity代码如下

    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<Huawei>() {//观查者
                        @Override
                        public void onChanged(Huawei huawei) {
                            if(huawei!=null){
                                Toast.makeText(SecActivity.this, huawei.getType(), Toast.LENGTH_SHORT).show();
                            }
                        }
                    }
    
            );
        }
        /**
         * 发布者
         * @param view
         */
        public void sendMessage(View view){
            Huawei huawei=new Huawei("META-20");
            //厂家发布消息
            LiveDataBus.getInstance().with("huawei",Huawei.class).postValue(huawei);
        }
    

    此时此刻,第一个Activity跳转到SecondActivity,然后SecondActivity里面的操作效果都是跟Avtivity一样的。这是上面已经优化过的代码。如果LiveDataBus这个类不优化,而是直接当作MutableLiveData类型返回,会出问题(如下图),我们知道订阅是再初始化里面,发布我们是点了按钮才发布,你会发现再第一个Activity里面订阅和发布正常,当跳转到SecondActivity的时候,还没点击发布按钮的时候,他自动就给你订阅消息弹吐司了,因此这是系统的一个bug,我们要通过查找源码反射的方法去修改

    image.png
    我们首先再LiveData里面源码找 image.png

    observer.mObserver.onChanged((T) mData);就是造成这种现象的原因,那么从上面代码看,要想某种情况不执行到这里来,肯定要retrun掉。

    image.png image.png

    mVersion初始值是-1,observer.mLastVersion >= mVersion这里的代码意思是每次执行一次,mVersion都是要+1的,这样就导致observer.mLastVersion >= mVersion这个方法不成立,那么这里就一直走不到return,我们只能通过反射去修改这里。

    相关文章

      网友评论

          本文标题:Jetpack---LifeCycle/LiveData/Vie

          本文链接:https://www.haomeiwen.com/subject/xrpoyhtx.html