Android 项目最新架构

0.前言

为了帮助开发着打造一款优秀的APP,Google可谓费尽心力,推出了各种诸如MVP,MVVM等等项目架构的思路,帮助开发者更加高效的开发,尽管这样,Google还是接着推出了一个新的项目架构,以便给予开发者更多的选择,至于这种架构思路和MVP等框架的优劣,各位看完文章或许自有定论。

1.生命周期

在移动操作系统上开发软件其实是十分复杂的一件事情,因为我们随时需要面对系统和用户的各种不可预料的操作,很多时候,事情并不向着我们预设的方向方向进展。因此系统向我们提供了核心组件的生命周期这种东西,告知我们的APP正处在什么样的状况中,以便于我们做出相应的处理。

如上图。虽然Google给出了Activity非常详尽的生命周期结构,因此我们对根据生命周期做出相应的合理的安排,比如添加和移除实时GPS位置监听:

可是随着业务的逐渐复杂,我们可能在添加监听之间需要向服务器验证某些用户信息,等返回信息正确才去监听定位。那么在网络异步回调的时候,我们就很难知道当前的activity的生命周期状态。

如果发生上图的情况,那么我们的占用的相关资源就可能永远无法移除了。这还只是冰山一角,大家尽可以想想,当我们的异步调用面对无法预知的用户操作和系统处理的时候,什么问题都可能发生。

总而言之,由于我们对于UI实时的状态做不到了如指掌,以至于对数据和逻辑的处理就无法尽善尽美。这是类似隐患得不到很好的解决根本原因。

2. Google大礼包

这次Google推出了一套新的项目架构组件和架构思路,从UI到Data,帮助我们更加精准的开发自己的APP。

2.1 核心:Lifecycle Components

这套架构最核心的就是生命周期组件,:Lifecycle Components用于管理UI控制器(Activity/Freagment)的生命周期,方便查询当前组件生命周期的状态。

可查询的状态如下:

具体的使用方式有两种:

  • 继承LifecycleActivity/LifecycleFragment即可
  • 自己实现LifecycleRegistryOwner接口

java

// 通过继承,就已经将自己的生命周期的交给了Lifecycle Components管理了。
public class MainActivity extends LifecycleActivity {

}

那我们如何使用呢?

// 通过继承LifecycleObserver,保证我们可以通过注解或者接口查询UI的生命周期
public class MyTest implements LifecycleObserver {
    private Lifecycle lifecycle;
    // Lifecycle包含了当前组件的生命周期
    public MyTest(Lifecycle lifecycle){
        lifecycle.addObserver(this);
        this.lifecycle=lifecycle;
    }

// 当onResume发生的时候,该方法被调用
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void resume(){
        Log.i("TAG","it called when resume ");
    }

    public void doTest(String s){
        // 随时可以查询当前的UI状态
        if(lifecycle.getCurrentState().equals(Lifecycle.State.RESUMED)){
            Log.i("TAG","resume");
        }else{
            Log.i("TAG","is not resume !! ");
        }
    }

}


public class MainActivity extends LifecycleActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //将当前Activity的生命周期传递到MyTest中即可
        MyTest myTest=new MyTest(this.getLifecycle());
    }
}

看到这里,你一定心头一喜,如果有这个组件,那么我们就完全有能力将Activity作为一个UI的控制器,仅仅用来显示UI和相应用户操作,把Activity的大小缩小至最小。不用着急,大礼包远不止这些。

3.ViewModel和LiveData

  • ViewModel 是一个UI相关数据的暂存器,当所有相关的UI都finish掉的时候,它才会清除自己的数据。
  • LiveData则是一个持有具体数据并且可被观察,能感知生命周期的组件(它就像RxJava中一个能遵循组件生命周期的Observable)

他俩的关系,就是,ViewModel负责管理着不同的LiveData,并把它提供给UI。

3.1 LiveData

我们可以先来说说LiveData。由于它已经能够感知生命周期,也就意味着我们并不需要在去查询当前UI的生命周期,由于可被观察,也就意味着当它持有的数据发生改变,观察者可以立即受到信息。livedata最重要的方法是一下几个:

 onActive() // 当前LiveData有超过一个的活跃的观察者时,被调用

onInactive() // 当前没有任何活跃的观察时,着被调用

setValue()  // 勇于改变当前数据,这样观察者可以受到改变后的数据。

// 观察数据变化,并感知当前UI的生命周期
observe(LifecycleOwner owner, Observer<T> observer) 

这里有一个活跃的观察者的概念,我们不妨把它放在后面来看。LiveData的用法如下:

public class LocationLiveData extends LiveData<Location> {
    private LocationManager locationManager;

    private SimpleLocationListener listener = new SimpleLocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setValue(location);
        }
    };

    public LocationLiveData(Context context) {
        locationManager = (LocationManager) context.getSystemService(
                Context.LOCATION_SERVICE);
    }

    @Override
    protected void onActive() {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
    }

    @Override
    protected void onInactive() {
        locationManager.removeUpdates(listener);
    }
}



public class MainActivity extends LifecycleActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LiveData<Location> myLocationListener = new LocationLiveData();
        /*
        * observe(LifecycleOwner owner, Observer<T> observer)
        * 这个方法就是向LiveData中添加观察者,
        * LiveData则可以通过LifecycleOwner来判断
        * 当前传入的观察者是否是活跃的(也就是UI是否可见了)
        */
        myLocationListener.observe(this, new Observer<Location>() {
            @Override
            public void onChanged(@Nullable Location location) {
                // update
                //当LiveData中通过setValue()修改了数据时,
                //这里将会受到修改后的数据
            }
        });
    }
}

好了,LiveData基本的用法讲完了,由于有了LiveData,我们的data更加“智能”了。当UI不可见的时候,改变的数据将不会被更新到UI上。

而且如果数据在不同的UI界面都会被用到的时候,我们还可以一个单例的LiveData,为不同的UI提供统一的数据。这些操作就不去细讲了。

现在回头看LiveData,我们发现它至少有以下几个优点:

  • 可以避免内存泄露:由于 Observer 和 Lifecycle 绑定,当 Lifecycle 被销毁后,Observer 自动被清理。
  • 避免在 Activity 被销毁后更新数据导致的崩溃情况
  • 数据可共享
  • 数据更新更智能:当数据在UI不可见的时候更新了,在恢复可见的时候,最新的数据会及时更新到UI上。
  • 不需要在Activity中额外处理生命周期事件

一颗赛艇!

3.2 ViewModel

ViewModel则相对简单些,因为他的作用是暂存UI相关的数据,保证即使Activity配置更改,重新创建时,数据依然能够被保存好。

基本用法如下:

public class MyViewModel extends ViewModel {
    // MyViewModel用于管理不同的LiveData
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<Users>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // do async operation to fetch users
    }
}

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
    // 通过了ViewModelProviders来获取ViewModel
    // 用户获取和Activity绑定的ViewModel
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

这是ViewModel的最基本的用法,它负责从各个地方获取数据,然后把数据装到LiveData中,提供给UI;当然ViewModel也可以在不同的Fragment中共享,在这里就不多讲了。

由于ViewModel的本身和activity/fragment的生命周期绑定,当与之绑定的最后一个UI 销毁时,ViewModel才会clean自身的数据。

如图所示

4.数据持久化:Room

Room是Google提供的SQLite的ORM的解决方案,其实本质上和其他的ORM框架没什么特别大的差别,没有太多新意,因此只给出大体的架构图,有兴趣的同学可以自行去学习

5.总结

我们现在回头看整个架构

其实最有有趣的就是UI-ViewModel这个部分,这套架构至少可以帮助我们做到一下几点:

  • UI与Data真正分离
  • 异步调用和逻辑控制可以更加精细(因为对生命周期感知更多)
  • 实现Model驱动UI

6.勘误

暂无

附录

android官网: https://developer.android.com/topic/libraries/architecture/index.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容