Android Architecture Components

一、简介

Android Architecture Components 是谷歌在Google I/O 2017发布一套帮助开发者解决Android 架构设计的方案。使用Google 提供的处理数据持久化和管理组件生命周期的类,有助于应用开发者们构建更加鲁棒性,可测的,稳定可靠的应用。

二、Lifecycle

Lifecycle 组件指的是 android.arch.lifecycle 包下提供的各种类与接口,可以让开发者构建能感知其他组件(主要指Activity 、Fragment)生命周期(lifecycle-aware)的类。

1、为什么要使用Lifecycle

下面举一个常用的 MVP 例子,没引进 lifecycle 之前,我们需要在 Activity 或者 Fragment 销毁的时候,即 onDestroy 的时候手动调用 onDestroy 方法,这里会带来一些问题,每一次在 Activity 或者 Fragment 销毁的烧开后都要调用 presenter.destory() 方法,这样的代码枯燥,毫无意义。

class MainPresenter{
    public MainPresenter() {
    }

    void onCreate() {
        //do something
    }

    void onDestroy() {
        //do something
    }
}

在 MainActivity的生命周期方法中回调MainPresenter的生命周期方法:

class MainActivity extends AppCompatActivity {
    private MainPresenter presenter;

    public void onCreate(...) {
        presenter= new MainPresenter ();
        presenter.onCreate();
    }

    public void onDestroy() {
        super.onDestroy();
        presenter.onDestory();
    }
}

上面这种方式有什么缺点呢?

1、不够灵活,假如除了 MainPresenter类,还有别的类要监听 Activity 生命周期变化,那也需要添加许多生命周期的回调方法,比较繁琐,导致Activity生命周期方法中有很多其他类的生命周期方法。

2、某些类需要在Activity的onDestroy()中调用自己的销毁方法,但是另一个开发者在Activity使用时可能对这个类不熟悉,就不会调用销毁方法。

使用lifecycle 就可以解决上面的问题。

2、使用Lifecycle

MainPresenter改造如下:

public class MainPresenter {
    private static final String TAG = MainPresenter.class.getSimpleName();
    private Lifecycle lifecycle;

    public MainPresenter(Lifecycle lifecycle){
        this.lifecycle = lifecycle;
        lifecycle.addObserver(new GenericLifecycleObserver() {
            @Override
            public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_CREATE) {
                    onCreate();
                } else if (event == Lifecycle.Event.ON_DESTROY) {
                    onDestroy();
                }
            }
        });
    }

    public void onCreate() {
        Log.d(TAG, "onCreate:");
    }


    public void onDestroy() {
        Log.d(TAG, "onDestroy:");
    }
}

使用Lifecycle MainPresenter的逻辑都集中在MainPresenter中。避免了在Activity中多次调用。

Activity中调用如下:

public class LifecycleActivity extends AppCompatActivity {
    private static final String TAG = LifecycleActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lifecycle);
        Lifecycle lifecycle = getLifecycle();
        MainPresenter presenter = new MainPresenter(lifecycle);
    }
}

三、ViewModel

多数人都遇到过旋转手机并且应用程序崩溃或UI失去状态的问题。解决它最简单的办法就是配置Activitypotrait模式,但这是一个很糟糕的做法。幸运的是,Android团队在2017年Google I / O期间发布了ViewModel。

ViewModel不会因为Activity因配置改变销毁时被销毁(配置改变如旋转屏幕、设置中字体大小、粗细改变。Activity中配置改变会回调onRetainCustomNonConfigurationInstance和getLastNonConfigurationInstance)。ViewModelProviders.of(this).get(UserInfoViewModel.class)因配置改变时只是重连,不是新建。这就是使用ViewModel的好处。

ViewModel使用例子结合下节一起讲解。

四、LiveData

LiveData是google发布的lifecycle-aware components中的一个组件,它最大的特点就是具备生命周期感知功能。LiveData的优点:

1、解决内存泄露问题
由于LiveData会在Activity/Fragment等具有生命周期的lifecycleOwner组件调用onDestory的时候自动解绑,所以解决了可能存在的内存泄漏问题。之前我们为了避免这个问题,一般有注册绑定的地方都要解绑(即注册跟解绑要成对出现),而LiveData利用生命周期感知功能解决了这一问题,可以实现只需关心注册,而解绑会根据生命周期自动进行的功能。
2、不需要手动处理生命周期的变化
观察者并不需要手动处理生命周期变化对自身的逻辑的影响,只需要关心如何处理获取到的数据。LiveData能够感知Activity/Fragment等组件的生命周期变化,所以就完全不需要在代码中告诉LiveData组件的生命周期状态,当数据发生变化时,只在生命周期处于active下通知观察者,而在inactive下,不会通知观察者。(例如联网返回数据后弹出Dialog提示,联网时退出Activity,后台Http还在运行,这种情况返回数据后弹出Dialog提示就会崩溃)

1、如何注册观察者

1)、public void observe (LifecycleOwner owner, Observer<? super T> observer)

这个方法添加的observer会受到owner生命周期的影响,在owner处于active状态时,有数据变化会通知,当owner处于inactive状态,不会通知,并且当owner的生命周期状态时DESTROYED时,自动removeObserver。

2)、public void observeForever (Observer<? super T> observer)

这个方法添加的observer不存在生命周期概念,只要有数据变化,LiveData都会通知,并且不会自动remove。

2、如何设置LiveData的值

1)、protected void setValue (T value)

这个方法必须在主线程调用,子线程调用会抛异常。

2)、protected void postValue (T value)

这个方式主要用于在子线程调用。

3、下面结合ViewModel举一个例子

1)定义ViewModel

public class UserInfoViewModel extends ViewModel {
    private static final String TAG = UserInfoViewModel.class.getSimpleName();
    private MutableLiveData<UserInfo> ldUserInfo = new MutableLiveData<>();;
    private int id;
    
    public UserInfoViewModel(){
        UserInfo userInfo = new UserInfo();
        userInfo.name = "王羲之";
        userInfo.id = "" + id;
        ldUserInfo.setValue(userInfo);
    }

    public MutableLiveData<UserInfo> getData() {
        return ldUserInfo;
    }

    public void changeData() {
        UserInfo userInfo = new UserInfo();
        userInfo.name = "王羲之";
        id++;
        userInfo.id = "" + id;
        ldUserInfo.setValue(userInfo);
    }
}

继承ViewModel,ViewModel没有抽象方法,所以我们在子类中也不用实现什么抽象方法,这样UserInfoViewModel就具有了ViewModel的功能。

LiveData是一个抽象类,所以我们使用其实现类MutableLiveData。泛型UserInfo是LiveData中对象的类型。

2)、Activity中的代码如下

public class LiveDataActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = LiveDataActivity.class.getSimpleName();
    private TextView tvUserInfo;
    private UserInfoViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_live_data);
        tvUserInfo = findViewById(R.id.tv_data);
        initViewModel();
        setLisenter();
    }

    /**
     * 初始化ViewModel
     */
    private void initViewModel() {
        viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())
        ).get(UserInfoViewModel.class);
        Log.d(TAG, "viewModel>>" + viewModel.toString());
        Log.d(TAG, "viewModel>>" + viewModel.getData().getValue().toString());
        setDataChangeObserve();
    }

    /**
     * 设置数据观察者
     */
    private void setDataChangeObserve() {
        viewModel.getData().observe(this, new Observer<UserInfo>() {
            @Override
            public void onChanged(@Nullable UserInfo userInfo) {
                Log.d(TAG, "viewModel.getData().observe.onChanged>>" + viewModel.getData().getValue().toString());
                // !!!UserInfo数据变化时统一在这里处理,避免多处处理,增加耦合
                tvUserInfo.setText(viewModel.getData().getValue().toString());
            }
        });
    }

    private void setLisenter() {
        findViewById(R.id.btn_change).setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_change:
                viewModel.changeData();
                break;
        }
    }
}

a、获取ViewModel的实例

viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication());

b、为UserInfo的LiveData设置观察者,UserInfo数据改变时就会回调这里,然后处理更改UI的逻辑

viewModel.getData().observe(this, new Observer<UserInfo>() {
    @Override
    public void onChanged(@Nullable UserInfo userInfo) {
        Log.d(TAG, "viewModel.getData().observe.onChanged>>" + viewModel.getData().getValue().toString());
        // !!!UserInfo数据变化时统一在这里处理,避免多处处理,增加耦合
        tvUserInfo.setText(viewModel.getData().getValue().toString());
    }
});

3)、验证ViewModel的功能

竖屏时打印日志如下:

D/LiveDataActivity: viewModel>>com.demo.archcomponent.livedata.UserInfoViewModel@a0db0be
D/LiveDataActivity: viewModel>>UseInfo{id='2', name='王羲之'}
D/LiveDataActivity: viewModel.getData().observe.onChanged>>UseInfo{id='2', name='王羲之'}

切换横屏时打印日志如下:

D/LiveDataActivity: viewModel>>com.demo.archcomponent.livedata.UserInfoViewModel@a0db0be
D/LiveDataActivity: viewModel>>UseInfo{id='2', name='王羲之'}
D/LiveDataActivity: viewModel.getData().observe.onChanged>>UseInfo{id='2', name='王羲之'}

横竖屏切换时都会调用

viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication());

但是日志中两次打印出的对象都是同一个,而且值也是一样的。这就证明了ViewModelProviders.of(this).get(UserInfoViewModel.class)因配置改变时只是重连,不是新建

4)、验证LiveData的功能

在UserInfoViewModel中添加如下测试代码。

public void testLiveData(){
    new Thread(){
        @Override
        public void run() {
            super.run();
            Log.d(TAG, "延时开始");
            try {
                sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.d(TAG, "延时结束");
            UserInfo userInfo = new UserInfo();
            userInfo.name = "testLiveData";
            userInfo.id = "999";
            ldUserInfo.postValue(userInfo);
        }
    }.start();
}

上面代码延时了4秒再更新UserInfo的数据,调用该方法后我们就退出Activtiy,日志显示并没有回调onChange方法。证明LiveData会在Activity/Fragment等具有生命周期的lifecycleOwner组件调用onDestory的时候自动解绑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值