FanChat学习笔记(五)——终结篇

上一篇讲了主界面,里面包含了个人动态、联系人列表、会话列表,没有阅读的话建议看看FanChat学习笔记(四)——主页面。本文接着说一说添加好友与聊天界面的逻辑及一些重要的知识点。

  1. 添加好友——AddFriendActivity用到的知识点
  2. 添加好友——AddFriendActivity界面逻辑
  3. 聊天——ChatActivity用到的知识点
  4. 聊天——ChatActivity界面逻辑

1、添加好友——AddFriendActivity用到的知识点:

setHasFixedSize(boolean hasFixedSize)

RecycleView的这个方法的目的是RecycleView的ItemView宽高保持固定,不管Item增加或者减少,ItemView的宽高都不会变化。如果没有设置为false的话,RecyclerView会需要额外计算每个item的尺寸,而调用onMesure方法。

EventBus 3.0的使用

其实这个才是今天的重点,甚至是整个项目的重点,因为我研究这个项目就是为了学习EventBus 3.0在项目中的实际运用。在研究该项目之前,也曾翻过弘神的博客Android EventBus源码解析 带你深入理解EventBus。因为我记得当初我面试现在这份工作的时候,老板说:你们只知道那些东西怎么用,但是不只是为什么这么用?知其然不知其所以然!
所以,我们先来看看这个EventBus 3.0如何使用,以及其原理是怎么回事?
其实Github上面已经介绍了一遍,那么我尽量介绍得和上面不一样吧!
首先依赖,这个是没有办法不一样的!(因为我已经开始学习AndroidStudio了,所以Eclipse就不讨论了!)

compile 'org.greenrobot:eventbus:3.0.0'

接下来我们就可以注册了,注册的作用在后面再解释!

EventBus.getDefault().register(this);

注册了是不是就可以注销了?这就好像李白清的段子,英语刚刚说了一句“Hello”马上来一句“Goodbye”一样。所以我们不能闹这样的笑话!
那么我们不结束还能说什么啊?英文是一句都不会啊!!既然不会,我们就去自定义一个事件,就是我们要消息数据,这个就是我们要表达的内容!!

package com.itheima.leon.qqdemo.event;

/**
 * 创建者:   Leon
 * 创建时间:  2016/10/19 20:26
 * 描述:    EventBus事件
 */
public class AddFriendEvent {
   
   
    public static final String TAG = "AddFriendEvent";

    private String mFriendName;

    private String mReason;

    public AddFriendEvent(String friendName, String reason) {
        this.mFriendName = friendName;
        this.mReason = reason;
    }


    public String getFriendName() {
        return mFriendName;
    }

    public void setFriendName(String friendName) {
        this.mFriendName = friendName;
    }

    public String getReason() {
        return mReason;
    }

    public void setReason(String reason) {
        this.mReason = reason;
    }
}

这个类需要讲一下,EventBus的事件类型是Object,也就是说我们可以传递任意数据。这一点我们在下一个方法后来证实。因此,我们这个类可以只有属性没有get/set方法,类里面的数据类型以及相应的方法根据自己的需要构造。比如AddFriendEvent是按照标准实体来构建的,所有的属性都是私有的,然后提供公共方法来设置相应属性,而下面我们需要到这些数据的时候就可以通过方法来调用。
OK,我们知道说什么话了,那么我们开始对话吧?

 @Subscribe(threadMode = ThreadMode.MainThread, sticky = true, priority = 100)
    public void deleteFriend(AddFriendEvent event){
        Log.d(TAG, "deleteFriend: "+event.getFriendName());
    }

这里相当于收到了一句话,但是这句话就像是一个成语,简单一个方法却囊括了很多内容,我们一点一点来剖析。方法大家都明白是什么意思?不明白也没有关系,只要知道我们通过EventBus发布的消息会通过这个方法来实现,这个方法类似于回调。就是我们在其它地方发布消息,然后这个方法就会执行。接下来我们就说一下注解吧!

  1. threadMode

    这个参数是表示这个方法应该在什么线程运行?属于必选参数,可选线程有四种,如下:

    1. ThreadMode.PostThread
      在发布消息所在的线程执行

    2. ThreadMode.MainThread
      在主线程(UI线程)执行

    3. BackgroundThread
      在子线程(后台线程)执行

    4. ThreadMode.Async
      必须在子线程执行(强制在后台线程)执行

  2. sticky

    这个参数默认为false,意思是deleteFriend方法需要先注册(register), 再发布消息,才能接受到事件; 如果使用post(Object event)方法发布消息的话该参数完全没有意义。它的意义在于使用postSticky(Object event)发布消息时, 参数如果为true,那么可以不需要先注册, 也能接受到事件.如果参数为false的话,不管什么方法发布消息都得先注册才能接受到事件。

  3. priority

    这个参数代表优先级,属于可选参数,默认值是0。概念和有序广播的接受顺序类似,即优先级越高,会优先被调用。也仅仅如此而已。比如我们还有一个同类型参数的方法,如下,

 @Subscribe(threadMode = ThreadMode.BACKGROUND,sticky = true,priority = 90)
    public void addFriend(AddFriendEvent event) {
        Log.d(TAG, "addFriend: ");

    }

那么我们也仅仅是先执行当前这个deleteFriend方法,再执行addFriend方法,而并不能像有序广播那样我在优先的接受者(订阅者)这里可以通过abortBroadcast()方法终止传播,这个在EventBus里面是做不到的。另外,如果我这个接受者只有一个,但是我把级别调至最高(经测试,该参数类型为Int类型,所以最大值为2147483647,当然使用Int的最小值-2147483648也不会报错)也并不会有任何异常?最后提一点,这个参数不受发布消息的方法影响,两种方法优先级都是有效的!

接下来可以来研究实现的方法了,埋上面说的坑——“EventBus的事件类型是Object”。这里我们可以来研究一下发布消息的两种方式:

void postSticky(Object event)
void post(Object event)

看见上面的方法就知道了,不管我们使用何种方式发布消息,都可以传输Object数据给接收方(订阅者)。其实看postSticky(Object event)的源码就知道,event其实是保存了两次:

  /**
     * Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky
     * event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}.
     */
    public void postSticky(Object event) {
        synchronized (stickyEvents) {
            stickyEvents.put(event.getClass(), event);
        }
        // Should be posted after it is putted, in case the subscriber wants to remove immediately
        post(event);
    }

代码中前者在没有注册的时候就可以通知到接收方,也就是说接收方(订阅者)sticky参数为true的时候就可以在EventBus未注册的时候执行了。而后者就不行,它需要在注册的时候告诉EventBus当前类里面有几个接收方(订阅者)在等待接收消息,注册实现的原理是将当前的类class作为key,将接收方法的参数作为value,然后以键对值的形式用Map来保存的。当用post方法发布消息时就遍历Map,根据参数类型通知到对应的订阅者。所以这里需要注意两个问题,如果两个订阅者的参数类型相同的话,那么它会通知到每一个订阅者,也就是说每一个订阅者方法都会执行。其次,如果在不同的类需要订阅(接收消息)的话,那么就需要在不同的类注册EventBus。
因此,postSticky方法的原理应该是遍历所有类,然后找到对应的订阅方法并判断其sticky参数是否为true,根据其值决定是否通知订阅者。当然,这个只是我的猜想。
在上面我们通过注册来说“Hello”,然后通过post(Object event)方法(或者是postSticky(Object event))方法来说话(发布消息),通过注解的方式来倾听人家的对话(接收人家的消息),交谈完毕之后就应该说“Goodbye”了。那么我们应该通过什么方式来说呢?

EventBus.getDefault().unregister(this);

上面我们说过EventBus注册的原理,那么我们在当前类关闭的时候就应该将保存的class给清除掉,避免内存泄漏。所以我们应该在注册的当前类的时候,考虑什么时候应该注销掉,假如我们需要在Activity里使用EventBus订阅消息的话,那么我们可以在onCreate方法里面注册,在onDestory方法里面注销。说到内存泄漏我想到了内存泄漏和内存溢出的区别,如下:

内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。
内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
memory leak会最终会导致out of memory!

OK,上面讲完了使用EventBus来收发数据沟通,如果说得还是觉得肤浅的话,可以下载项目看看项目里具体是怎么使用的。

2. 添加好友——AddFriendActivity界面逻辑:

在聊逻辑之前,先看看具体界面,否则会感觉很抽象,所以先上图:

这里写图片描述

首先,当我们输入搜索的关键字以后,然后点击图片中的任意一个放大镜都可以实现搜索好友,搜索好友的主要实现在代码的业务逻辑实现类AddFriendPresenterImpl,所以先看看这个方法:

    @Override
    public void searchFriend(final String keyword) {

        mAddFriendView.onStartSearch();
        //注:模糊查询只对付费用户开放,付费后可直接使用。
        BmobQuery<User> query = new BmobQuery<User>();
        query.addWhereContains("username", keyword).addWhereNotEqualTo("username", EMClient.getInstance().getCurrentUser());
        query.findObjects(new FindListener<User>() {
            @Override
            public void done(List<User> list, BmobException e) {
                processResult(list, e);
            }
        });
    }

通过代码可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值