[Android]EventBus-来一趟快速公交初体验[上]

前言

作为一款非常著名的Android开源框架(http://greenrobot.org/eventbus/),它主要是解决当前很多代码的松耦合问题,即简化了代码,这也大大提高了开发者的开发效率,本文就以当前最新的3.0版本来体验这一次来的比较晚的快速公交,当然我这里多是以代码的示例来帮助读者更快的理解它的使用,具体的原理,我想你们其中有兴趣自个儿也会去挖掘的,我还是那句话:工欲善其事,必先利其器。


场景1

在Activity中点击控件发起网络请求,并显示结果到界面。

1.BaseActivity-先看我们demo的Activity的基类,里面主要是默认在onStart中注册了EventBus,在onStop再解除,这我不用再解释了吧^_^

package com.example.myapp;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

import com.example.myapp.event.BaseEvent;
import com.example.myapp.event.HttpEvent;
import com.example.myapp.event.MyEvent;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

/**
 * Created by Jan on 2016/6/8.
 */
public class BaseActivity extends Activity {
    public EventBus mEventBus;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mEventBus = EventBus.getDefault();

    }

    @Override
    protected void onStart() {
        super.onStart();
        mEventBus.register(this);
    }

    @Override
    protected void onStop() {
        mEventBus.unregister(this);
        super.onStop();
    }

    @Subscribe
    public void onEvent(MyEvent myEvent){
    }
    //在Activity和Fragment中订阅了相同的BaseEvent,
    @Subscribe
    public void onEvent(BaseEvent myEvent){
        Log.i("BaseActivity","---onEvent---isRead="+myEvent.isrREAD());
        if(myEvent.isrREAD()){
            //如果已经处理过了,咱们这边就不处理这个Event了
            return;
        }
    }

    //订阅网络请求类型事件的接收方法
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onHttpEvent(HttpEvent event){
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }
}
2.这里我就用常用的方式和EventBus的方式来实现,可以对比一下:
 Button btn1;
    TextView mNotificationTv;
    Switch sw;
    HttpUtils httpUtils = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        httpUtils = new HttpUtils(this);
        initViews();

    }

    //订阅网络请求类型事件的接收方法
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onHttpEvent(HttpEvent event){
        //简单更新UI 注意别做什么耗时任务
        mNotificationTv.setText("code="+event.stateCode+",message="+event.message);
    }

    private void initViews(){
        mNotificationTv = (TextView) findViewById(R.id.tv_notification);
        btn1 = (Button) findViewById(R.id.button1);
        btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //一.使用传统的事件监听回调,利用Handler来更新UI
                httpUtils.httpGet("http://blog.csdn.net/jan_s?viewmode=contents", new HttpUtils.OnHttpCallBack() {
                    @Override
                    public void onFailure(Exception e) {
                        Log.w("HomeActivity","---onFailure---"+e.getLocalizedMessage());
                    }

                    @Override
                    public void onSuccess(String response) {
                        Log.w("HomeActivity","---onSuccess---");
                        mNotificationTv.setText("onSuccess");
                    }
                });
                //二.使用EeventBus来通知订阅者来处理对应的UI更新事件
                httpUtils.httpGetByBus("http://blog.csdn.net/jan_s?viewmode=contents");
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
3.HttpUtisl-本次Demo中用到的一个最简单的Http方案,大家不需要在吐槽了,因为就是为了demo而写的,他不是主演,只是个跑龙套的^_^

package com.example.myapp.http;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;

import com.example.myapp.event.HttpEvent;

import org.greenrobot.eventbus.EventBus;

import java.io.IOException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * 一个很简单的网络请求demo,真的很简单,因为什么都没有
 * Created by jan on 2016/6/7.
 */
public class HttpUtils {
    private Context context;
    private static OkHttpClient httpClient = new OkHttpClient();
    private Handler handler;
    public HttpUtils(Context context){
        this.context = context;
        this.handler = new Handler(Looper.myLooper());
    }

    /**
     * 这边的回调方式是通过H主线程Handler来通知前台更新
     * @param url
     * @param callBack
     */
    public void httpGet(String url, final OnHttpCallBack callBack ){
        try{
            Request request = new Request.Builder().url(url).build();
            Call call = httpClient.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    handlerErr(callBack,e);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    handlerSuccess(callBack,response.body().string());
                }
            });
        }catch (Exception e){
            callBack.onFailure(e);
        }
    }

    /**
     * 因为OkHttp的Callback事件是在子线程中执行的,所以这边顺便模拟使用EventBus来通知到前台Activity中更新界面
     * @param url
     */
    public void httpGetByBus(String url){
        try{
            Request request = new Request.Builder().url(url).build();
            Call call = httpClient.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    HttpEvent he = new HttpEvent();
                    he.stateCode= -1;
                    he.message = e.getMessage();
                    EventBus.getDefault().post(he);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    postSuccess(EventBus.getDefault(),response);
                }
            });
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void postSuccess(final EventBus bus ,Response response) throws IOException {
        HttpEvent he = new HttpEvent();
        he.stateCode= 0;
        he.result = response.body().string();
        he.message = "通讯成功";
        bus.post(he);
    }

    private void handlerSuccess(final OnHttpCallBack callBack, final String result){
        handler.post(new Runnable() {
            @Override
            public void run() {
                callBack.onSuccess(result);
            }
        });
    }

    private void handlerErr(final OnHttpCallBack callBack, final Exception e){
        handler.post(new Runnable() {
            @Override
            public void run() {
                callBack.onFailure(e);
            }
        });
    }

    public interface OnHttpCallBack{
        public void onFailure(Exception e);
        public void onSuccess(String response);
    }
}

HttpEvent.java-这是自己定义的一个网络事件

public class HttpEvent extends BaseEvent {
    public int stateCode;
    public String result;
    public String message;
}

4.效果图(无)其实效果很简单,就如我们假设的场景一样,简单的把网络请求成功的数据显示到Activity中去,事实上,两种方案都实现了。这里我们可以看出,EventBus确实可以简化很多代码,就看我们怎么去更好的使用它。

场景2

Fragment与Activity之间发生的交互,比如在fragment中去点击了某个事件必须调用Activity的方法,如何实现?很简单的回答就是直接通过getActivity()去调用即可,还有的方式就是写个接口回调,这里我们用EventBus去实现怎么样,对比一下看看吧!

效果图


1.MainActivity.java-先看这个Activity的代码,主要是看我先写了个一个onEvent(MyEvent myEvent)的订阅事件-处理接收来自Fragment的通知,它是subscribe注解,EventBus3开始使用注解的方式,比起之前的用固定方法名,看起来更加灵活。

这边我们先看LooK look 26-36处的代码,以及122-133的代码,其他代码是别的功能哦(确实有点乱...哈恰恰..)

public class MainActivity extends BaseActivity { 
    Button btn1;
    TextView mNotificationTv;
    FrameLayout mContainer;
    FragmentTransaction ft;
    Switch sw;
    HttpUtils httpUtils = null;
    public TextListener textListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        httpUtils = new HttpUtils(this);
        textListener = new TextListener();
        initViews();
        if(savedInstanceState==null){
            FirstFragment ff = new FirstFragment();
            FragmentManager fm = getFragmentManager();
            ft = fm.beginTransaction();
            ft.add(R.id.fl_container,ff,"first");
            ft.commit();
        }
    }
    //在HomeActivity中订阅一个事件,这边主要是用来接收两个Fragment的通知
    @Subscribe
    public void onEvent(MyEvent myEvent){
        Log.i("HomeActivity","onEvent->MyEvent");
        if(myEvent.eventType==1){
            mNotificationTv.setText(myEvent.object.toString());
        }else if(myEvent.eventType==2){
            mNotificationTv.setText(myEvent.object.toString());
        }
        //这里表示已经先接受过了,因为我的Event有父子关系,并会传递到下个订阅事件
        myEvent.setIsrREAD(true);
    }

    //在Activity和Fragment中订阅了相同的BaseEvent,
    @Subscribe
    public void onEvent(BaseEvent myEvent){
        Log.i("HomeActivity","---onEvent---isRead="+myEvent.isrREAD());
        if(myEvent.isrREAD()){
            //如果已经处理过了,咱们这边就不处理这个Event了
            return;
        }
    }

    //订阅网络请求类型事件的接收方法
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onHttpEvent(HttpEvent event){
        //简单更新UI 注意别做什么耗时任务
        mNotificationTv.setText("code="+event.stateCode+",message="+event.message);
    }


    private void initViews(){
        mNotificationTv = (TextView) findViewById(R.id.tv_notification);
        mContainer = (FrameLayout) findViewById(R.id.fl_container);
        sw = (Switch) findViewById(R.id.switch1);
        sw.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(isChecked){
                    SecondFragemrnt sf = new SecondFragemrnt();
                    FragmentManager fm = getFragmentManager();
                    FragmentTransaction tx = fm.beginTransaction();
                    tx.replace(R.id.fl_container, sf, "second");
//                    tx.addToBackStack(null);
                    tx.commit();
                }else {
                    FirstFragment ff = new FirstFragment();
                    FragmentManager fm = getFragmentManager();
                    FragmentTransaction tx = fm.beginTransaction();
                    tx.replace(R.id.fl_container, ff, "first");
//                    tx.addToBackStack(null);
                    tx.commit();
                }
            }
        });
        btn1 = (Button) findViewById(R.id.button1);
        btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 因为都在相同的视图内,可以通过标志位的方式来处理
                EventBus.getDefault().post(new BaseEvent());
                //下面是测试Sticky事件的代码
//                startActivity(new Intent(HomeActivity.this,DetaiActivity.class));
//                new Handler().postDelayed(new Runnable() {
//                    @Override
//                    public void run() {
//                        EventBus.getDefault().postSticky(new BaseEvent("Hello everyone!"));
//                    }
//                },3000);
//                new Thread(){
//                    @Override
//                    public void run() {
//                        try {
//                            sleep(2000);
//                        } catch (InterruptedException e) {
//                            e.printStackTrace();
//                        }
//                        EventBus.getDefault().postSticky(new BaseEvent("Hello everyone!"));
//                        try {
//                            sleep(2000);
//                        } catch (Exception e) {
//                            e.printStackTrace();
//                        }
//                        EventBus.getDefault().post(new BaseEvent("我是后来者!"));
//                    }
//                }.start();
            }


        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    //一,最经典的回调方式,通过实现FirstFragemnt的接口来回调(通知)当前Activity它做了什么
    public class TextListener implements FirstFragment.OnFragmentTextOnClickListener {

        @Override
        public void onTextViewClick(MyEvent myEvent) {
            if(myEvent.eventType==1){
                mNotificationTv.setText(myEvent.object.toString());
            }else if(myEvent.eventType==2){
                mNotificationTv.setText(myEvent.object.toString());
            }
        }
    }
}
MyEvent.java

public class MyEvent extends BaseEvent {
    public int eventType;
    public Object object;
    public MyEvent() {
    }
}
在看我们的FirstFragment和SecondFragment之前,我们先来看看基类BaseFragment,它和BaseActivity一样,都是给EventBus做绑定的。

BaseFragment.java

package com.example.myapp.fragment;

import android.app.Fragment;
import android.os.Bundle;

import com.example.myapp.event.BaseEvent;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

/**
 * Created by jan on 2016/6/3.
 */
public abstract class BaseFragment extends Fragment{

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        EventBus.getDefault().register(this);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        EventBus.getDefault().unregister(this);
    }

    /**
     * 在当前Fragment中去实现各种UI事件
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onUIEvent(BaseEvent event){
        if(event.isrREAD()){
            return;
        }
    }

    public abstract void handlerEvent(BaseEvent event);
}

好了,看主演Firstfragment了,它是onCreateView中给TextView加了个点击事件,通过注释中的一和二两种方法去实现本场景中的需求-通知Activity的方法更新界面

传统的方法一就是实现回调接口,而EventBus比较简单了,直接通知Activity的订阅方法即可(haha,di~学生卡偷笑

FirstFragment.java

package com.example.myapp.fragment;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import com.example.myapp.HomeActivity;
import com.example.myapp.R;
import com.example.myapp.event.BaseEvent;
import com.example.myapp.event.MyEvent;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

/**
 * Created by jan on 2016/6/3.
 */
public class FirstFragment extends BaseFragment {
    TextView text1;
    HomeActivity mHomeActivtiy;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if(getActivity()!=null){
            mHomeActivtiy = (HomeActivity) getActivity();
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_first,container,false);
        text1 = (TextView) view.findViewById(R.id.tv_f1);
        text1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //这里新建一个事件,希望传递一个String到Activity显示
                MyEvent myEvent = new MyEvent();
                myEvent.eventType = 1;
                myEvent.object = "来自FirstFragment的通知:Hello,My master!";
                //一、通过宿主Activity实现Fragment的接口(如本例中OnFragmentTextOnClickListener)来回调
//                if(mHomeActivtiy.textListener!=null){
//                    mHomeActivtiy.textListener.onTextViewClick(myEvent);
//                }
                //二、通过EventBus来通知给所在宿主Activity,省去单独写回调的麻烦事
                EventBus.getDefault().post(myEvent);
            }
        });
        return view;
    }
    //跟本场景无关,请忽略
    @Override
    public void handlerEvent(BaseEvent event) {
        Log.d("FirstFragment","---handlerEvent---");
        Toast.makeText(getActivity(),"收到通知:"+event.getMessage(),Toast.LENGTH_SHORT).show();
    }
    //跟本场景无关,请忽略
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onUIEvent(BaseEvent event){
        if(event.isrREAD()){
            return;
        }
        Log.i("FirstFragment","---onTest---isRead="+event.isrREAD());
        event.setIsrREAD(true);
        text1.setText("onTest");
    }

    /**
     * 这个是我们给FirstFragment写的接口,是让Activity来实现的,然后在Fragment回调它的方法
     */
    public interface OnFragmentTextOnClickListener{
        public void onTextViewClick(MyEvent myEvent);
    }
}
SecondFragment和他是一样的,这里不重复贴代码拉。

我先写以上以上两个场景吧,其实还想贴个Sticky事件的demo的,但是时间关系,就写到这里了。
ThreadMode的简单说明

最后,写了这么多,我好像忘了记什么了,卧槽,最基本的ThreadMode忘了说明,其实这个很简单,就是在所在的线程去发布事件,用对应的ThreadMode去实现用哪个线程去处理发布过来的事件。

下面是我自己测试的代码,大家看看注释即可,有兴趣的可以自己写写然后装逼即可。

package com.example.myapp;

import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import com.example.myapp.event.BaseEvent;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

/**
 * 用于测试体验不同的ThreadMode下执行的态度
 * Created by jan on 2016/6/3.
 */
public class DetaiActivity extends BaseActivity {
    private TextView mDetailTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);
        mDetailTv = (TextView) findViewById(R.id.tv_detail);
    }

    /**
     * 事件的处理在和事件的发送在相同的进程,默认对应发布请求的线程,当然可能会在UI线程中处理,所以事件处理时间不应太长,不然影响事件的发送线程。
     */
    @Subscribe(threadMode = ThreadMode.MAIN,sticky = false,priority = 0)
    public void onMessageEvent1(BaseEvent event){
        Log.i("DetaiActivity","onMessageEvent1");
        mDetailTv.setText(event.getMessage().toString());
    }
    /**
     * 事件的处理会在UI线程中执行。
     */
    @Subscribe(threadMode = ThreadMode.POSTING,sticky = false,priority = 1)
    public void onMessageEvent2(BaseEvent event){
        Log.i("DetaiActivity","onMessageEvent2");
//        mDetailTv.setText(event.getMessage().toString());

    }

    /**
     * 事件处理会在单独的线程中执行,主要用于在后台线程中执行耗时操作,每个事件会开启一个线程(有线程池),但最好限制线程的数目。
     */
    @Subscribe(threadMode = ThreadMode.ASYNC,sticky = false,priority = 2)
    public void onMessageEvent3(BaseEvent event){
        Log.i("DetaiActivity","onMessageEvent3");
//        mDetailTv.setText(event.getMessage().toString());
    }

    /**
     * 事件的处理会在一个后台线程中执行,事件处理是在后台线程,但事件处理时间还是不应该太长,
     * 因为如果发送事件的线程是后台线程,会直接执行事件,如果当前线程是UI线程,事件会被加到一个队列中,
     * 由一个线程依次处理这些事件,如果某个事件处理时间太长,会阻塞后面的事件的派发或处理。
     */
    @Subscribe(threadMode = ThreadMode.BACKGROUND,sticky = true,priority =3 )
    public void onMessageEvent4(BaseEvent event){
        Log.i("DetaiActivity","onMessageEvent4");
        BaseEvent be = EventBus.getDefault().removeStickyEvent(BaseEvent.class);
        Log.d("DetaiActivity","be->"+be.getMessage());
//        mDetailTv.setText(event.getMessage().toString());
    }

}
本文链接,转载请留言( http://blog.csdn.net/jan_s/article/details/51635823




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值