ITEMS.add(item);
}
public Item(String id, String content)
{
this.id = id;
this.content = content;
}
@Override
public String toString()
{
return content;
}
}
package com.angeldevil.eventbusdemo;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import com.angeldevil.eventbusdemo.Event.ItemListEvent;
import de.greenrobot.event.EventBus;
public class ItemListFragment extends ListFragment
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Register
EventBus.getDefault().register(this);
}
@Override
public void onDestroy()
{
super.onDestroy();
// Unregister
EventBus.getDefault().unregister(this);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
// 开启线程加载列表
new Thread()
{
public void run()
{
try
{
Thread.sleep(2000); // 模拟延时
// 发布事件,在后台线程发的事件
EventBus.getDefault().post(new ItemListEvent(Item.ITEMS));
} catch (InterruptedException e)
{
e.printStackTrace();
}
};
}.start();
}
public void onEventMainThread(ItemListEvent event)
{
setListAdapter(new ArrayAdapter(getActivity(),
android.R.layout.simple_list_item_activated_1,
android.R.id.text1, event.getItems()));
}
@Override
public void onListItemClick(ListView listView, View view, int position,
long id)
{
super.onListItemClick(listView, view, position, id);
EventBus.getDefault().post(getListView().getItemAtPosition(position));
}
}
ItemListFragment里面在onCreate里面进行了事件的订阅,onDestroy里面进行了事件的取消;onViewCreated中我们模拟了一个子线程去网络加载数据,获取成功后我们调用
了EventBus.getDefault().post(new ItemListEvent(Item.ITEMS));发布了一个事件;
onListItemClick则是ListView的点击事件,我们调用了EventBus.getDefault().post(getListView().getItemAtPosition(position));去发布一个事件,
getListView().getItemAtPosition(position)的类型为Item类型;
细心的你一定发现了一些诡异的事,直接new Thread()获取到数据以后,竟然没有使用handler;我们界面竟然发生了变化,那么List是何时绑定的数据?
仔细看下代码,发现这个方法:
public void onEventMainThread(ItemListEvent event)
{
setListAdapter(new ArrayAdapter(getActivity(),
android.R.layout.simple_list_item_activated_1,
android.R.id.text1, event.getItems()));
}
应该是这个方法为List绑定的数据。那么这个方法是怎么被调用的呢?
现在就可以细谈订阅事件与发布事件了:
如果方法名以onEvent开头,则代表要订阅一个事件,MainThread意思,这个方法最终要在UI线程执行;当事件发布的时候,这个方法就会被执行。
那么这个事件什么时候发布呢?
我们的onEventMainThread触发时机应该在new Thread()执行完成之后,可以看到子线程执行完成之后,执行了EventBus.getDefault().post(new ItemListEvent(Item.ITEMS));
意味着发布了一个事件,当这个事件发布,我们的onEventMainThread就执行了,那么二者的关联关系是什么呢?
其实和参数的类型,我们onEventMainThread需要接收一个ItemListEvent ,我们也发布了一个ItemListEvent的实例。
现在我们完整的理一下:
在onCreate里面执行 EventBus.getDefault().register(this);意思是让EventBus扫描当前类,把所有onEvent开头的方法记录下来,如何记录呢?使用Map,Key为方法的参数类型,Value中包含我们的方法。
这样在onCreate执行完成以后,我们的onEventMainThread就已经以键值对的方式被存储到EventBus中了。
然后当子线程执行完毕,调用EventBus.getDefault().post(new ItemListEvent(Item.ITEMS))时,EventBus会根据post中实参的类型,去Map中查找对于的方法,于是找到了我们的onEventMainThread,最终调用反射去执行我们的方法。
现在应该明白了,整个运行的流程了;那么没有接口却能发生回调应该也能解释了。
现在我们在看看代码,当Item点击的时候EventBus.getDefault().post(getListView().getItemAtPosition(position));我们同样发布了一个事件,参数为Item;这个事件是为了让详细信息的Fragment去更新数据,不用说,按照上面的推测,详细信息的Fragment里面一个有个这样的方法: public void onEventMainThread(Item item) ; 是不是呢?我们去看看。
3、ItemDetailFragment
package com.angeldevil.eventbusdemo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import de.greenrobot.event.EventBus;
public class ItemDetailFragment extends Fragment
{
private TextView tvDetail;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// register
EventBus.getDefault().register(this);
}
@Override
public void onDestroy()
{
super.onDestroy();
// Unregister
EventBus.getDefault().unregister(this);
}
/** List点击时会发送些事件,接收到事件后更新详情 */
public void onEventMainThread(Item item)
{
if (item != null)
tvDetail.setText(item.content);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_item_detail,
container, false);
tvDetail = (TextView) rootView.findViewById(R.id.item_detail);
return rootView;
}
}
果然不出我们的所料,真的存在onEventMainThread(Item item)的方法。当然了,必须在onCreate里面首先书写EventBus.getDefault().register(this);让EventBus扫描再说。
那么这个Fragment的流程就是:onCreate时,EventBus扫描当前类,将onEventMainThread以键值对的形式进行存储,键为Item.class ,值为包含该方法的对象。
然后当ItemListFragment中Item被点击时,发布了一个事件:EventBus.getDefault().post(getListView().getItemAtPosition(position));实参的类型恰好是Item,于是触发我们的
onEventMainThread方法,并把Item实参传递进来,我们更新控件。
4、Event
这里还有个事件类:
package com.angeldevil.eventbusdemo;
import java.util.List;
public class Event
{
/** 列表加载事件 */
public static class ItemListEvent
{
private List items;
public ItemListEvent(List items)
{
this.items = items;
}
public List getItems()
{
return items;
}
}
}
ItemListEvent我们在ItemListFragment中使用的,作为的是onEventMainThread中的参数。为什么封装这么个类呢?会在之后的EventBus源码解析中说明。
到此我们的EventBus的初步用法就介绍完毕了。纵观整个代码,木有handler、木有AsynTask,木有接口回调;but,我们像魔术般的实现了我们的需求;来告诉我,什么是耦合,没见到~~~
3、EventBus的ThreadMode
=====================
EventBus包含4个ThreadMode:PostThread,MainThread,BackgroundThread,Async
MainThread我们已经不陌生了;我们已经使用过。
具体的用法,极其简单,方法名为:onEventPostThread, onEventMainThread,onEventBackgroundThread,onEventAsync即可
具体什么区别呢?
onEventMainThread代表这个方法会在UI线程执行
onEventPostThread代表这个方法会在当前发布事件的线程执行
BackgroundThread这个方法,如果在非UI线程发布的事件,则直接执行,和发布在同一个线程中。如果在UI线程发布的事件,则加入后台任务队列,使用线程池一个接一个调用。
Async 加入后台任务队列,使用线程池调用,注意没有BackgroundThread中的一个接一个。
4、题外话
=====
大家可以利用EventBus尝试做以下操作:
当接收到某个广播,例如短信,在界面上显示。
开启一个Service,在服务器里面启动一个定时线程,不断更新ActivityUI。
等等…之后,你会发现EventBus的魅力!
声明一下:上面两个Fragment的例子是我在网上down到的,做了简单的修改,虽然很简单,但是很能说明问题。看包名应该是angeldevil写的,在此表示感谢。
顺便吐槽一个官方给的例子,什么性能对比,然后一堆TestCase,不直观。
如果你希望深入理解Eventbus,请看:Android EventBus源码解析 带你深入理解EventBus,相信可以为你解除很多困惑,了解该框架的设计之美。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/97a3dbc4cce354cac1932f6f351c65fe.jpeg)
总结:
面试是一个不断学习、不断自我提升的过程,有机会还是出去面面,至少能想到查漏补缺效果,而且有些知识点,可能你自以为知道,但让你说,并不一定能说得很好。
有些东西有压力才有动力,而学到的知识点,都是钱(因为技术人员大部分情况是根据你的能力来定级、来发薪水的),技多不压身。
附上我的面试各大专题整理: 面试指南,满满的都是干货,希望对大家有帮助!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!**
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/97a3dbc4cce354cac1932f6f351c65fe.jpeg)
总结:
面试是一个不断学习、不断自我提升的过程,有机会还是出去面面,至少能想到查漏补缺效果,而且有些知识点,可能你自以为知道,但让你说,并不一定能说得很好。
有些东西有压力才有动力,而学到的知识点,都是钱(因为技术人员大部分情况是根据你的能力来定级、来发薪水的),技多不压身。
附上我的面试各大专题整理: 面试指南,满满的都是干货,希望对大家有帮助!
[外链图片转存中…(img-LXFrDO9r-1712336340604)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!