Android 架構煉成 教你怎樣寫組件間通訊架構EventBus

來源:互聯網
上載者:User

標籤:

轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/41096639 。本文出自:【張鴻洋的部落格】1、概述

關於Eventbus的介紹。前面已經有兩篇:Android EventBus實戰 沒聽過你就out了和Android EventBus原始碼解析 帶你深入理解EventBus 。 假設你覺得還有問題,沒關係,接下來我帶大家手把手打造從無到有的編寫這種架構~~~

首先我們回想一下,這玩意就是在register時,掃描類中複合命名規範的方法,存到一個map,然後post的時候。尋找到匹配的方法,反射調用;好,那麼依據這一句話。我們就開始編寫架構之旅~~~

2、依舊是原來的配方

下面出現的執行個體代碼和Android EventBus實戰 沒聽過你就out了基本一致。所以我就貼出部分

1、ItemListFragment

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 com.zhy.eventbus.EventBus;public class ItemListFragment extends ListFragment{@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);// RegisterEventBus.getInstatnce().register(this);}@Overridepublic void onDestroy(){super.onDestroy();// UnregisterEventBus.getInstatnce().unregister(this);}@Overridepublic void onViewCreated(View view, Bundle savedInstanceState){super.onViewCreated(view, savedInstanceState);// 開啟線程載入列表new Thread(){public void run(){try{Thread.sleep(2000); // 類比延時// 公布事件,在後台線程發的事件EventBus.getInstatnce().post(new ItemListEvent(Item.ITEMS));} catch (InterruptedException e){e.printStackTrace();}};}.start();}public void onEventUI(ItemListEvent event){setListAdapter(new ArrayAdapter<Item>(getActivity(),android.R.layout.simple_list_item_activated_1,android.R.id.text1, event.getItems()));}@Overridepublic void onListItemClick(ListView listView, View view, int position,long id){super.onListItemClick(listView, view, position, id);EventBus.getInstatnce().post(getListView().getItemAtPosition(position));}}
2、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 com.zhy.eventbus.EventBus;public class ItemDetailFragment extends Fragment{private TextView tvDetail;@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);// registerEventBus.getInstatnce().register(this);}@Overridepublic void onDestroy(){super.onDestroy();// UnregisterEventBus.getInstatnce().unregister(this);}/** List點擊時會發送些事件,接收到事件後更新詳情 */public void onEventUI(Item item){if (item != null)tvDetail.setText(item.content);}@Overridepublic 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;}}

能夠看到。我們在ItemListFragment裡面使用了:

EventBus.getInstatnce().post(new ItemListEvent(Item.ITEMS));去公布了一個事件。然後更新了我們的列表;

點擊Item的時候,使用EventBus.getInstatnce().post(getListView().getItemAtPosition(position));公布了一個事件,更新了我們的ItemDetailFragment的列表;

效果:


和之前的一摸一樣~~~

可是請注意,如今我們用的是EventBus.getInstatnce()。並發是EventBus.getDefault();而且看下包名import com.zhy.eventbus.EventBus;

我想你應該明確了,這是我們自己寫的類來實現的~~~~

好了,接下來就帶大家一起實現這個類~~

ps :以上代碼和。全然是為了部落格的完整性。勿見怪~~

3、無中生有1、getInstance

我們這裡為了方便,直接簡單粗暴的使用惡漢模式建立單例:

private static EventBus eventBus = new EventBus();public static EventBus getInstatnce(){return eventBus;}private EventBus(){mHandler = new Handler(Looper.getMainLooper());}

然後在構造方法中初始化了一個mHandler,沒錯,它就是用來在處理在UI線程調用方法的。

接下來看register

2、register

/* * 我們的強大的map。儲存我們的方法 */private static Map<Class, CopyOnWriteArrayList<SubscribeMethod>> mSubscribeMethodsByEventType = new HashMap<Class, CopyOnWriteArrayList<SubscribeMethod>>();public void register(Object subscriber){Class clazz = subscriber.getClass();Method[] methods = clazz.getDeclaredMethods();CopyOnWriteArrayList<SubscribeMethod> subscribeMethods = null;/** * 遍曆全部方法 */for (Method method : methods){String methodName = method.getName();/** * 推斷方法是否以onEvent的開頭 */if (methodName.startsWith("onEvent")){SubscribeMethod subscribeMethod = null;// 方法命中提前在什麼線程執行。預設在UI線程String threadMode = methodName.substring("onEvent".length());ThreadMode mode = ThreadMode.UI;Class<?

>[] parameterTypes = method.getParameterTypes();// 參數的個數為1if (parameterTypes.length == 1){Class<?> eventType = parameterTypes[0];synchronized (this){if (mSubscribeMethodsByEventType.containsKey(eventType)){subscribeMethods = mSubscribeMethodsByEventType.get(eventType);} else{subscribeMethods = new CopyOnWriteArrayList<SubscribeMethod>();mSubscribeMethodsByEventType.put(eventType,subscribeMethods);}}if (threadMode.equals("Async")){mode = ThreadMode.Async;}// 提取出method,mode,方法所在類對象。存數的類型封裝為SubscribeMethodsubscribeMethod = new SubscribeMethod(method, mode,subscriber);subscribeMethods.add(subscribeMethod);}}}}enum ThreadMode{UI, Async}class SubscribeMethod{Method method;ThreadMode threadMode;Object subscriber;public SubscribeMethod(Method method, ThreadMode threadMode,Object subscriber){this.method = method;this.threadMode = threadMode;this.subscriber = subscriber;}}



能夠看到我們使用了一個Map儲存全部的方法。key為參數的類型class;value為CopyOnWriteArrayList<SubscribeMethod>

這裡我們封裝了一個SubscribeMethod,這個裡面儲存了我們須要執行方法的全部參數,畢竟我們執行時。須要該方法,該方法所在的對象。以及在什麼線程執行;三個對象足以。當然也缺一不可了~~

register裡面,我們遍曆該類的全部方法,找到onEvent開頭的,封裝成SubscribeMethod。存在Map裡面。當然了,一個參數類型相應非常多方法,所以value是個CopyOnWriteArrayList。

掃描完畢。我們就完畢了將方法的儲存。

另一點,我們這裡預設在UI線程執行,假設方法是onEventAsync則覺得在子線程執行,我們也僅僅支援這兩種模式,簡化一點~

3、post

private static ThreadLocal<PostingThread> mPostingThread = new ThreadLocal<PostingThread>(){@Overridepublic PostingThread get(){return new PostingThread();}};public void post(Object eventTypeInstance){//拿到該線程中的PostingThread對象PostingThread postingThread = mPostingThread.get();postingThread.isMainThread = Looper.getMainLooper() == Looper.myLooper();//將事件增加事件隊列List<Object> eventQueue = postingThread.mEventQueue;eventQueue.add(eventTypeInstance);//防止多次調用if (postingThread.isPosting){return;}postingThread.isPosting = true;//取出全部事件進行調用while (!eventQueue.isEmpty()){Object eventType = eventQueue.remove(0);postEvent(eventType, postingThread);}postingThread.isPosting = false;}

我們這裡學習了原始碼,也搞了個當前線程中的變數,儲存了一個事件隊列以及事件的狀態;

class PostingThread{List<Object> mEventQueue = new ArrayList<Object>();boolean isMainThread;boolean isPosting;}

終於公布的事件先增加到事件隊列。然後再取出來調用postEvent

private void postEvent(final Object eventType, PostingThread postingThread){CopyOnWriteArrayList<SubscribeMethod> subscribeMethods = null;synchronized (this){subscribeMethods = mSubscribeMethodsByEventType.get(eventType.getClass());}for (final SubscribeMethod subscribeMethod : subscribeMethods){if (subscribeMethod.threadMode == ThreadMode.UI){if (postingThread.isMainThread){invokeMethod(eventType, subscribeMethod);} else{mHandler.post(new Runnable(){@Overridepublic void run(){invokeMethod(eventType, subscribeMethod);}});}} else{new AsyncTask<Void, Void, Void>(){@Overrideprotected Void doInBackground(Void... params){invokeMethod(eventType, subscribeMethod);return null;}};}}}

postEvent也非常easy,直接依據參數類型,去map改到該方法,依據其threadMode。假設在UI線程。則推斷當前線程。假設是UI線程,直接調用。否則通過handler執行;

假設非UI線程。這裡我們直接開啟了一個Thread去執行;

invokeMethod非常easy。就是反射調用方法了~

private void invokeMethod(Object eventType, SubscribeMethod subscribeMethod){try{subscribeMethod.method.invoke(subscribeMethod.subscriber, eventType);} catch (Exception e){e.printStackTrace();}}

4、unregister

public void unregister(Object subscriber){Class clazz = subscriber.getClass();Method[] methods = clazz.getDeclaredMethods();List<SubscribeMethod> subscribeMethods = null;for (Method method : methods){String methodName = method.getName();if (methodName.startsWith("onEvent")){Class<?>[] parameterTypes = method.getParameterTypes();if (parameterTypes.length == 1){synchronized (this){mSubscribeMethodsByEventType.remove(parameterTypes[0]);}}}}}

unregister時。由於我們沒有存不論什麼的輔助狀態,我們僅僅能再去遍曆了方法了~~只是通過這個。也能反應出EventBus內部好幾個Map的作用了~~

而且。我們也不支援一些狀態的查詢,還是由於我們沒有存一些輔助狀態,比如isRegister等等。

到此,我們的EventBus就寫好了。100多行代碼。肯定沒有EventBus健壯,主要目的還是學習人家的思想,經過自己寫了這麼個類,我相信對於EventBus的理解就更深刻了~面試的時候,恨不得拿僅僅筆寫給面試官看,哈哈~~

5、EventBus最佳實務

前面的文章,非常多朋友問。假設我多個方法參數都一樣,豈不是post一個此參數,會多個方法調用;而此時我想調用指定的方法怎麼辦?

還有。項目中會有非常多地方去接收List參數,而List<T>中的泛型是不一致的,所以也可能post(List)時。會調用非常多方法。造成出錯。

的確。上述,不加處理肯定會出現;

可是,推薦大家在使用EventBus的時候。建立一個事件類別,把你的每個參數(或者可能發生衝突的參數),封裝成一個類:

比如:

public class Event{public static class UserListEvent{public List<User> users ;}public static class ItemListEvent{public List<Item> items;}}

這種話。就不會發生什麼調用衝突了~~



原始碼點擊下載





我建了一個QQ群,方便大家交流。群號:55032675


----------------------------------------------------------------------------------------------------------

博主部分視頻已經上線,假設你不喜歡枯燥的文本。請猛戳(初錄。期待您的支援):

1、高仿5.2.1主介面及訊息提醒

2、高仿QQ5.0側滑

3、Android智能機器人“小慕”的實現





Android 架構煉成 教你怎樣寫組件間通訊架構EventBus

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.