Otto框架是square公司为Android出的一款事件总线框架,设计用于解耦应用程序的不同部分,同时仍然允许它们有效地通信。
https://github.com/square/otto
以下简单介绍一下Otto框架的使用方式:
创建Bus实例:
Bus bus = new Bus();
Otto在设计时考虑到了android特定的用例,建议使用单例模式使用(尽管这不是必需的),但是总线只有在共享时才有效。
package com.windfallsheng.myotto;
import com.squareup.otto.Bus;
public class OttoBus extends Bus {
private volatile static OttoBus bus;
private OttoBus() {
}
public static OttoBus getInstance() {
if (bus == null) {
synchronized (OttoBus.class) {
if (bus == null) {
bus = new OttoBus();
}
}
}
return bus;
}
}
public final class BusProvider {
private static final Bus BUS = new Bus();
public static Bus getInstance() {
return BUS;
}
private BusProvider() {
// No instances.
}
}
发布事件 Publish:
通过调用 Bus 的 post 方法,告诉订阅者某个操作已经发生。任何类的实例都可以发布在总线上,并且它只会被分配给该类型的订阅者。
package com.windfallsheng.myotto;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
/**
* Created by Administrator on 2016/11/17 0017.
*/
public class PostActivity extends AppCompatActivity {
private static final String TAG = PostActivity.class.getSimpleName();
private Button mBtnSendEventData;
private String userArray[] = {"Cyra", "Morgen", "Iris", "Mia"};
private String messageArray[] = {"我发表了新的美食文章", "我更新了我的相册", "我在FaceBook申请了账号", "我做了一个好看的小视频"};
public static void start(Context context) {
context.startActivity(new Intent(context, PostActivity.class));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "method:onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post);
mBtnSendEventData = (Button) this.findViewById(R.id.btn_send_event_data);
mBtnSendEventData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int uIndex = (int) (Math.random() * userArray.length);
int mIndex = (int) (Math.random() * messageArray.length);
EventData eventData = new EventData(userArray[uIndex], messageArray[mIndex]);
Log.i(TAG, "method:onCreate#mBtnSendEventData#onClick#eventData#hashCode=" + eventData.hashCode());
Log.i(TAG, "method:onCreate#mBtnSendEventData#onClick#eventData=" + eventData);
OttoBus.getInstance().post(eventData);
// finish();
}
});
}
}
package com.windfallsheng.myotto;
public class EventData {
public String userName;
public String message;
public EventData(String userName, String message) {
this.userName = userName;
this.message = message;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return "EventData{" +
"userName='" + userName + '\'' +
", message='" + message + '\'' +
'}';
}
}
订阅Subscribe:
订阅后就可以接收到已经发出的事件,通过使用@Subscribe注释方法实现订阅。该方法应该只接受一个参数,该参数的类型是您希望订阅的事件。
package com.windfallsheng.myotto;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.squareup.otto.Subscribe;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private Button mBtnJumpToPost, mBtnJumpToProduce, mBtnJumpToMainActivity;
private TextView mTvMessage, mTvMessageUpdate;
public static void start(Context context) {
context.startActivity(new Intent(context, MainActivity.class));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTvMessage = (TextView) this.findViewById(R.id.tv_message);
mTvMessageUpdate = (TextView) this.findViewById(R.id.tv_message_update);
mBtnJumpToPost = (Button) this.findViewById(R.id.btn_jump_to_post);
mBtnJumpToMainActivity = (Button) this.findViewById(R.id.btn_jump_to_main_activity);
mBtnJumpToProduce = (Button) this.findViewById(R.id.btn_jump_to_produce);
mBtnJumpToPost.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PostActivity.start(MainActivity.this);
}
});
mBtnJumpToProduce.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ProduceActivity.start(MainActivity.this);
}
});
mBtnJumpToMainActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.start(MainActivity.this);
}
});
Log.i(TAG, "method:onCreate#this#hashCode=" + this.hashCode());
OttoBus.getInstance().register(this);
}
@Subscribe
public void refreshMessage(EventData eventData) {
Log.i(TAG, "method:Subscribe#refreshMessage#eventData#hashCode=" + eventData.hashCode());
Log.i(TAG, "method:Subscribe#refreshMessage#eventData=" + eventData);
mTvMessage.setText(eventData.getUserName() + ":\n\n" + eventData.getMessage());
}
@Subscribe
public void updateMessage(EventData eventData) {
Log.i(TAG, "method:updateMessage#updateMessage#eventData#hashCode=" + eventData.hashCode());
Log.i(TAG, "method:Subscribe#updateMessage#eventData=" + eventData);
mTvMessageUpdate.setText(eventData.getUserName() + ":\n\n" + eventData.getMessage());
}
@Override
protected void onDestroy() {
super.onDestroy();
OttoBus.getInstance().unregister(this);
}
}
使用@Subscribe注释的方法,它的名称可以是任意的,只需要满足注释、单参数和公共访问修饰符即可。
为了接收事件,类的实例还必须需向总线注册,比如示例中的注册方法:
OttoBus.getInstance().register(this);
另外,在适当的时候也要调用 unregister 方法。
发布事件的另一种方式:
通过生产 Produce 注解方式也可以发布事件,它与 post 方法不同的是,它在任何订阅者注册时立即向其提供回调。
要创建生产者,请使用@Produce注释方法。该方法不应接受任何参数,其返回类型将用作可以生成初始值的事件类型。
package com.windfallsheng.myotto;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.squareup.otto.Produce;
public class ProduceActivity extends AppCompatActivity {
private static final String TAG = ProduceActivity.class.getSimpleName();
private String userArray[] = {"Cyra", "Morgen", "Iris", "Mia"};
private String messageArray[] = {"我发表了新的美食文章", "我更新了我的相册", "我在FaceBook申请了账号", "我做了一个好看的小视频"};
public static void start(Context context) {
context.startActivity(new Intent(context, ProduceActivity.class));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "method:onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_produce);
// 注册Otto
Log.i(TAG, "method:onCreate#this#hashCode=" + this.hashCode());
OttoBus.getInstance().register(this);
}
@Produce
public EventData produceEventData() {
Log.i(TAG, "method:Produce#produceEventData");
int uIndex = (int) (Math.random() * userArray.length);
int mIndex = (int) (Math.random() * messageArray.length);
EventData eventData = new EventData(userArray[uIndex], messageArray[mIndex]);
Log.i(TAG, "method:produceEventData#produceEventData#hashCode=" + eventData.hashCode());
Log.i(TAG, "method:Produce#produceEventData#eventData=" + eventData);
return eventData;
}
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "method:onResume");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "method:onDestroy");
// 注销Otto
OttoBus.getInstance().unregister(this);
}
}
使用@Produce注释方法时,必须要调用 register 方法注释当前类实例,同时在适当的时机调用 unregister 方法。
在总线上,每次只能为每个事件类型注册一个生产者。
有关事件执行线程的问题:
由于有时您可能不清楚正在接收回调的线程是哪个,所以Otto提供了一种强制机制,以确保总是在您希望的线程上调用您。默认情况下,与实例的所有交互都仅限于主线程。
//这两者在功能上是等价的。
Bus bus1 = new Bus();
Bus bus2 = new Bus(ThreadEnforcer.MAIN);
如果您不关心发生在哪个线程上的交互,则使用 ThreadEnforcer.ANY
实例化一个总线实例。如果需要额外的功能或验证,还可以提供自己的 ThreadEnforcer
接口实现。
由于作者水平有限,语言描述及代码实现中难免有纰漏,望各位看官多提宝贵意见!
Hello , World !
感谢所有!