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
그 다음에 우리는 반사 호출을 통해 방법의 유형 정보, 방법 정보와 사용자 정의 주해에서 방법이 운행하는 라인을 알아야 한다.여기서 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
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.