Android - 100줄 코드에서 EventBus 쓰기 (초상세)

백 줄 코드 찾아보기 이벤트 버스
  • 배경
  • 사용법
  • 사고
  • 요약
  • 배경.
    안드로이드 개발에서 이벤트버스는 현재 비교적 유행하는 메시지 버스 프레임워크이다.현재 유행하는 모듈화, 조립화에서도 중요한 역할을 하고 있다.그 원리를 믿어 어린 친구들도 다 안다.그것의 핵심 논리는 사실 백여 줄의 코드만 있으면 쓸 수 있다.오늘 우리는 이벤트버스 간이판 프레임워크(My EventBus)를 한 번 훑어보았다.
    사용법
    프레임을 훑기 전에 프레임의 사용법을 정의해야 한다.여기서 우리는 EventBus의 사용법을 본떠서 상세한 내용은 다음과 같다. 1. 대상을 초기화할 때 EventBus를 등록해야 하고 대상을 소각할 때 묶음을 풀어야 한다.예:
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            MyEventBus.getInstance().register(this);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            MyEventBus.getInstance().unRegister(this);
        }
    

    2. EventBus가 메시지를 받는 방법은 특정한 주석 표지를 사용하고 형참은 제한되지 않으며 방법명은 제한되지 않는다.예:
        @EventReceiver()
        public void getMessage1(String str){
            ···
        }
    

    3. EventBus 메시지 처리 방법은 주석을 통해 주 스레드나 하위 스레드에서 실행하거나 스레드를 전환하지 않도록 할 수 있다.예:
        @EventReceiver(ThreadMode.MAIN)
        public void getMessage2(User user){
            ···
        }
    

    4. 이벤트버스 메시지는 임의의 장소에서post 방법을 사용하여 발송할 수 있고 이미 등록된 이벤트버스의 대상에 대응하는 주석 방법은 리셋을 촉발할 수 있다.예:
    	MyEventBus.getInstance().post(user);
    

    사고의 방향
    1. 우리는 사용자 정의 주석을 통해 하나의 클래스를 표시하고 찾을 수 있으며,post 방법에서 반사로 그것을 되돌릴 수 있다.2. 우리는 메모리에서 변수를 유지하여 이벤트버스의 대상과 클래스 정보, 리셋이 필요한 방법과 리셋 방식을 저장할 수 있다.(등록과 해제는 대상 단위이기 때문에 메모리에 있는 데이터는 대상-기타 데이터의 형식으로 저장해야 한다. 해제하기 편리하다.)3. EventBus가 장면을 사용하는 데 여러 개의 EventBus 대상이 필요하지 않기 때문에 단례 모델을 사용하여 이 구조를 설계한다.
    전체적인 사고방식: 이벤트버스의register 방법은 메모리에 등록자의 실례인 (클래스 정보, 리셋 방식, 리셋 방법)을 저장하는 데 사용된다.post 방법에서 보내야 할 메시지를 받은 후 메모리에 저장된 모든 방법을 옮겨다니며 방법형이 메시지 유형에 참여하면 반사로 리셋합니다.unRegister 방법은 메모리에 대응하는 실례적인 방법 정보만 제거하면 된다.
    이루어지다
    구현을 시작합니다. 우선, 주석과 그 값 정의를 정의합니다.
    public class ThreadMode {
        /**
         *      , post      
         */
        public static final int POSTING = 0;
        /**
         *         
         */
        public static final int MAIN = 1;
        /**
         *         
         */
        public static final int BACKGROUND = 2;
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface EventReceiver {
        int value() default ThreadMode.POSTING;
    }
    

    상기 사용자 정의 주해 중 @Retention(RetentionPolicy.RUNTIME)은 주해가 운행할 때 보류하도록 규정하고 @Target(ElementType.METHOD)은 주해를 방법에만 사용할 수 있도록 규정했다.사용자 정의 주석에 대한 더 많은 세부 사항은 모르는 것은 먼저 배워서 배울 수 있습니다.
    다음은 메모리에 저장된 방법의 데이터 구조를 정의합니다.우선, 우리는 대상-기타 정보의 구조가 필요하다. 가장 적합한 것은 맵이다.그러므로 구조는 다음과 같이 정의할 수 있다. private Map> map; 그 다음에 우리는 반사 호출을 통해 방법의 유형 정보, 방법 정보와 사용자 정의 주해에서 방법이 운행하는 라인을 알아야 한다.여기서 MessageBean이라는 JavaBean을 정의합니다.
    class MessageBean {
        private Method method;
        private Class type;
        private int threadMode;
    
        Method getMethod() {
            return method;
        }
    
        void setMethod(Method method) {
            this.method = method;
        }
    
        Class getType() {
            return type;
        }
    
        void setType(Class type) {
            this.type = type;
        }
    
        int getThreadMode() {
            return threadMode;
        }
    
        void setThreadMode(int threadMode) {
            this.threadMode = threadMode;
        }
    }
    

    이제 EventBus 핵심 클래스를 작성하겠습니다.EventBus 클래스는 단일 클래스로 getInstance(), register(Object context), unRegister(Object context), post(Object message) 네 가지 대외 방법을 포함한다.
    public class EventBus {
    
        private Map<Object, List<MessageBean>> map;
        ···
    
        public synchronized static EventBus getInstance() {
            ···
        }
    
        private MyEventBus() {
            map = new HashMap<>();
            ···
        }
    
        /**
         *   
         * @param context        
         */
        public void register(Object context) {
            ···
        }
    
        /**
         *   
         * @param context        
         */
        public void unRegister(Object context) {
            ···
        }
    
        /**
         *     
         * @param message        
         */
        public void post(Object message) {
            ···
        }
    }
    

    먼저 getInstance() 방법을 사용하여 단일 인스턴스 객체를 가져옵니다.
    	private static EventBus instance;
    	
        public synchronized static EventBus getInstance() {
            if (instance == null) {
                instance = new EventBus();
            }
            return instance;
        }
    

    다음으로 register(Object context) 방법을 살펴보겠습니다.이 메서드는 Object에서 대상 메모와 관련 정보를 가져와 맵에 저장해야 합니다.
        /**
         *   
         *
         * @param context        
         */
        public void register(Object context) {
            //         ,             。            
            if (map.get(context) == null) {
                map.put(context, new ArrayList<MessageBean>());
            } else {
                Log.e("MyEventBus", "context is registered");
                return;
            }
            Method[] methods = context.getClass().getDeclaredMethods(); //            (        )
            List<MessageBean> messageBeans = map.get(context);
            for (Method method : methods) {     //            ,        
                EventReceiver eventReceiver = method.getAnnotation(EventReceiver.class);    //      
                if (eventReceiver != null) {    //eventReceiver            
                    //       ,     false,         ,     。(                      )
                    Class[] paramTypes = method.getParameterTypes();
                    if (paramTypes.length == 1) {
                        if(method.getReturnType() == Void.class) {
                            MessageBean messageBean = new MessageBean();
                            messageBean.setMethod(method);
                            messageBean.setThreadMode(eventReceiver.value());
                            messageBean.setType(paramTypes[0]);
                            messageBeans.add(messageBean);
                        }else {
                            Log.e("MyEventBus", "Return type must be void");
                        }
                    } else {
                        Log.e("MyEventBus", "Parameter must have only one");
                    }
                }
            }
        }
    

    상기 코드에서 방법의 참조 수량과 반환 값 유형을 추가로 판단했다.우리는 인삼이 하나만 있을 수 있고 되돌아오는 값은void이어야 한다고 규정하고 있다.이렇게 하면 사용자가 주석을 남용한 후에 발생하는 프로그램 붕괴를 피할 수 있다.
    등록 방법에 비해 묶음 해제 방법 unRegister(Object context)은 훨씬 간단합니다. 맵에서 대상에 대응하는 데이터만 제거하면 됩니다.
        /**
         *   
         *
         * @param context        
         */
        public void unRegister(Object context) {
            map.remove(context);
        }
    

    마지막으로 메시지 post(Object message) 보냈습니다.이 방법은 모든 메모리를 옮겨다니며 반사 리셋을 통해
        /**
         *     
         *
         * @param message        
         */
        public void post(Object message) {
            Set<Object> objects = map.keySet();
            for (Object object : objects) {
                List<MessageBean> messageBeans = map.get(object);
                if (messageBeans == null || messageBeans.size() == 0) {
                    continue;
                }
                for (MessageBean messageBean : messageBeans) { //      
                    invoke(object, message, messageBean);   //      (    )
                }
            }
        }
    

    여기서 우리는 invoke 방법을 분리해 냈다.이 방법은 메시지 형식과 리셋 방법의 매개 변수 형식이 일치하는 상황에서 리셋을 해야 한다.리콜 시 실행 스레드 선택:
        /**
         *       (    )
         * @param object
         * @param message
         * @param messageBean
         */
        private void invoke(final Object object, final Object message, MessageBean messageBean) {
            final Method method = messageBean.getMethod();
            if (message.getClass().isAssignableFrom(messageBean.getType())) {   //              
                switch (messageBean.getThreadMode()) {
                    case ThreadMode.POSTING:    //
                        try {
                            method.invoke(object, message);
                        } catch (IllegalAccessException | InvocationTargetException e) {
                            e.printStackTrace();
                        }
                        break;
                    case ThreadMode.MAIN:
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    method.invoke(object, message);
                                } catch (IllegalAccessException | InvocationTargetException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                        break;
                    case ThreadMode.BACKGROUND:
                        executorService.execute(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    method.invoke(object, message);
                                } catch (IllegalAccessException | InvocationTargetException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                        break;
                }
            }
        }
    

    라인을 전환할 필요가 없을 때, 우리는 직접 반사 리셋을 반사하면 된다는 것을 알 수 있다.주 스레드에서 리셋이 필요할 때, 우리는 주 스레드Handler에서 리셋을 한다.Handler는 구성 방법에서 다음과 같이 정의합니다.
        private Handler handler;
    
        private MyEventBus() {
        	···
            handler = new Handler(Looper.getMainLooper());
        }
    

    하위 스레드에서 실행할 때 우리는 스레드 풀을 사용했다.
        private ExecutorService executorService;
    
        private MyEventBus() {
        	···
            executorService = Executors.newCachedThreadPool();
        }
    

    이로써 완공되었다.코드 줄 수를 세어 봐, 백 줄밖에 안 돼.
    총결산
    현재 훑고 있는 이벤트버스는 단순 버전입니다.실제 이벤트버스 내부에는 대량의 호환성 코드와 점성 이벤트 등 다양한 메시지 기능이 진행되었다.손으로 훑는 틀은 유명 구조 설계자의 구조 사상을 이해하게 할 수도 있고 자신의 사고 능력과 구조 능력을 더욱 뚜렷하게 할 수도 있다.성장의 길은 아직 멀었으니 함께 노력하자.Navisphere EventBus 소스 주소:https://github.com/cjfu/MyEventBus

    좋은 웹페이지 즐겨찾기