《极简笔记》源码分析(二)

0. 介绍

此文将对Github上lguipeng大神所开发的 极简笔记 v2.0 (点我下载源码)代码进行分析学习。
通过此文你将学到:

  • 应用源码的研读方法
  • MVP架构模式
  • Application的应用
  • Degger2依赖注入框架
  • 搜索控件的使用
  • ButterKnife库的使用
  • Material主题
  • RecyclerView等新控件的用法
  • Lambda表达式
  • Java自定义注解
  • aFinal框架
  • RxJava框架
  • EventBus消息框架
  • 布局文件常用技巧
  • PreferenceFragment
  • 动态申请权限

此为系列文章,传送门: 《极简笔记》源码分析(一)

3.3 onCreate()方法

3.3.1 Activity崩溃的信息保存

想要在Activity崩溃的时候,其实主要是屏幕发生旋转时保存信息,以便重启Activity后能够恢复信息,需要怎么做呢?很简单,重写 onSaveInstanceState(Bundle outState) 方法,在内部实现信息的保存,并在onCreate方法中对信息进行恢复即可,如:

// 信息的保存: 笔者猜测是用于保存当前界面,保存在"Normal"模式还是"回收站"模式
public void onSaveInstanceState(Bundle outState){
    outState.putInt(CURRENT_NOTE_TYPE_KEY, mCurrentNoteTypePage.getValue());
}

然后再onCreate中恢复信息:

if (savedInstanceState != null){
    int value = savedInstanceState.getInt(CURRENT_NOTE_TYPE_KEY);
    mCurrentNoteTypePage = SNote.NoteType.mapValueToStatus(value);
}

3.3.2 初始化视图

view.initToolbar();
initDrawer();
initMenuGravity();
initItemLayoutManager();
initRecyclerView();

在onCreate方法中还进行了各视图的初始化。

3.3.2.1 initToolbar

调用所有继承自MainView接口的Activity的初始化Toolbar方法以初始化。

3.3.2.2 初始化抽屉
drawerList = Arrays.asList(mContext.getResources()
        .getStringArray(R.array.drawer_content));
view.initDrawerView(drawerList);
view.setDrawerItemChecked(mCurrentNoteTypePage.getValue());
view.setToolbarTitle(drawerList.get(mCurrentNoteTypePage.getValue()));

这里值得留意的是在strings.xml中定义数组:

<array name="drawer_content">
    <item>SNotes</item>
    <item>回收站</item>
</array>
3.3.2.3 设置抽屉方向

抽屉居右效果
通过view.setMenuGravity(Gravity.END)和view.setMenuGravity(Gravity.START)设置抽屉的方向,由MVP模式,具体的实现放在MainActivity中。

@Override
public void setMenuGravity(int gravity) {
    DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) drawerRootView.getLayoutParams();
    params.gravity = gravity;
    drawerRootView.setLayoutParams(params);
}
3.3.2.4 设置RecyclerView线性或网格排列
private void switchItemLayoutManager(boolean card){
    if (card){
        view.setLayoutManager(new StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL));
    }else {
        view.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));
    }
    isCardItemLayout = card;
}

在MainActivity中进行视图操作:

recyclerView.setLayoutManager(manager);
3.3.2.5 加载笔记
public void initRecyclerView(){
    view.showProgressWheel(true);
    mObservableUtils.getLocalNotesByType(mFinalDb, mCurrentNoteTypePage.getValue())
            .subscribeOn(Schedulers.computation())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe((notes) -> {
                view.initRecyclerView(notes);
                view.showProgressWheel(false);
            }, (e) -> {
                e.printStackTrace();
                view.showProgressWheel(false);
            });
}

这段代码又用到RxJava,所以显得比较复杂,我们来慢慢分析。

3.3.2.5.1 getLocalNotesByType

那么首先来看ObservableUtils里的getLocalNotesByType方法,它将返回一个Observable对象,此处截取了关键部分:

return Observable.create(new Observable.OnSubscribe<T>() {
    @Override
    public void call(Subscriber<? super T> subscriber) {
        try {
            T t = fun.call();
            subscriber.onNext(t);
        }catch (Exception e){
            subscriber.onError(e);
        }
    }
});

下面是fun.call():

@Override
public List<SNote> call() throws Exception {
    return mFinalDb.findAllByWhere(SNote.class, "type = " + type, "lastOprTime", true);
}

其中type为mCurrentNoteTypePage.getValue(),标志是否为回收站的内容。
findAllByWhere方法原型为:

List<T> findAllByWhere(Class<T> clazz, String strWhere, String orderBy, boolean desc);

它是aFinal库中FinalDb中的方法,功能为依据条件查找所有元素并反序列化为对象List。

3.3.2.5.2 指定线程
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())

此处的代码用于指定观察者和被观察者所在的线程,由于加载笔记属于重大任务,所以指定在computation计算线程,另外subscribeOn可指定的参数如图:
可指定的线程
此处回顾一下RxJava的调度器:

在RxJava 中,Scheduler ——调度器,相当于线程控制器,RxJava 通过它来指定每一段代码应该运行在什么样的线程。RxJava 已经内置了几个 Scheduler ,它们已经适合大多数的使用场景:

  • Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。
  • Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。
  • Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
  • Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
  • 另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。
3.3.2.5.3 订阅

subscribe(onNext, onError)方法需要两个参数,一个是接下来需要执行的操作,一个是执行错误的回调操作,均需要实现Action1接口,此处使用lambda表达式简化了代码。

3.3.3 EventBus库

EventBus.getDefault().register(this);

接下来使用到了 EventBus 库,所以让我们先来学习一下EventBus,这个库真可以说是发现的一块新大陆。

3.3.3.1 介绍

EventBus是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间传递消息.优点是开销小,代码更优雅。以及将发送者和接收者解耦。

3.3.3.2 使用
  • 导入库
compile 'org.greenrobot:eventbus:3.0.0'
  • 编写消息类,传递的消息是一个对象
public class FirstEvent {
   

    private String mMsg;  
    public FirstEvent(String msg) {
        mMsg = msg;  
    }  
    public String getMsg(){
        return mMsg;  
    }  
}  
  • 注册与反注册
    在onCreate方法中进行注册:
EventBus.getDefault().register(this); 

在onDestroy方法中进行反注册:

EventBus.getDefault().unregister(this);
  • 发送消息
EventBus.getDefault().post(new FirstEvent("FirstEvent btn clicked"));
  • 接收消息
    在接受消息的Activity中重写事件接收方法,如onEventMainThread:
public void onEventMainThread(FirstEvent event);

注参数一定要匹配,否则该方法将接收不到数据。消息的接收是通过判断参数是否匹配来的,它将调用四种接收方法中所有匹配该参数的方法。

3.3.3.3 4种接收消息方法

前文在接受消息使用到是onEventMainThread方法,那么各方法有什么区别呢。

  • onEvent:如果使用onEvent作为订阅函数,那么该事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。
  • onEventMainThread:如果使用onEventMainThread作为订阅函数,那么不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。
  • onEventBackground:如果使用onEventBackgrond作为订阅函数,那么如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。
  • onEventAsync:使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync.

至此,EventBus的使用已基本介绍完毕,接下来分析EventBus在本项目中的使用。

3.3.3.3 本项目中EventBus使用
3.3.3.3.1 注册与反注册

首先在onCreate和onDestroy中进行了注册与反注册。

3.3.3.3.2 消息接收——同步笔记
public void onEventMainThread(EverNoteUtils.SyncResult result){
    if (result != EverNoteUtils.SyncResult.START)
        view.stopRefresh();
    switch (result){
        case ERROR_NOT_LOGIN: view.showGoBindEverNoteSnackbar(R.string.unbind_ever_note_tip, R.string.go_bind);break;
        ...
        case SUCCESS:view.showSnackbar(R.string.sync_success);refreshNoteTypePage();break;
   
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值