Android消息通信之Activity间消息传递
https://blog.csdn.net/qq_34911465/article/details/79420559
https://www.cnblogs.com/chenjy1225/p/9662510.html
Android 开发之中我们常常需要应用到消息传递的机制,消息的传递有多种方式。消息传递的作用不必多说,主要是在不同的组件之间传播消息或者共享某些状态等,以下是几种常用的消息传递机制:
- Intent Bundle
- 静态变量
- 全局变量 及Application
- Android系统剪切板
- 本地化存储方式
- Andorid组件
- EventBus
二、方案对比及适用场景
三、详细描述
1. Intent Bundle
这是很常见的方式了,不必多说,简单的写法如下:
Intent intent = new Intent();
intent.putExtra("send","发送了消息");
intent.setClass(MainActivity.this,ReceiveActivity.class);
startActivity(intent);
Bundle:我们可以通过将数据封装在Bundle
对象中 ,然后在Intent跳转的时候携带Bundle
对象
bundle
本质上是使用arrayMap
实现的
Bundle bundle = new Bundle();
bundle.putString("name", "chenjy");
bundle.putInt("age", 18);
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtras(bundle);
startActivity(intent);
用上述方法可以传递基本数据类型和String类型的数据,如果传递的是对象就需要进行序列化:Serializable 和 Parcelable
Parcelable
运用真实的序列化处理代替反射,大量的引入代码但是速度会远快于Serializable
。所以优先选择Parcelable
bundle.putSerializable("person",person);
这样就可以在目标Activity中接收到消息。
下图是Intent可以传递的数据大全,只要为每个数据设置不同的name就可以通过name取出。
2. 静态变量 && 3 全局变量及Application &&4 Android 系统剪切板
这三种方式其实非常相似,静态变量和全局变量都可以采用static的方式来定义,如果采用这种方式还是推荐用一个专门的类结合单体模式进行管理,尽量减少对内存的消耗。
而使用系统剪切板的方式一般也很少用,比较多限制,容易丢失数据,几乎没有看到有这样用的。
Application
: 可以通过在Application
中的全局静态变量来实现
这里还有利用Application进行共享Handler来消息传递,方法很简单,就是在Application中定义一个全局的Handler,虽然这种方法可以实现,但是却保留了在整个App中保留了全局的Handler,如果在Handler的设置中引用了某个Activity,就容易造成内存泄露了。
5. 本地化存储方式
本地存储方式有如下三种:
SharedPreference
SQLite
File
这三种方式的好处就是他们是持久存储的,只要不卸载APP或者不删除文件就可以一直保存下去,而且也几乎没有大小的限制,可以做一些统计。不过缺点也比较明显,这三种方式最好是采用多线程来进行读写,尤其是数据量大的时候,我们知道,IO的操作是非常耗费时间的,所以尽量不要在UI线程中使用这三种方式读写。
示例代码:
SharedPreference:
// 发送消息
SharedPreferences.Editor editor = MainActivity.this.getSharedPreferences("SEND", Context.MODE_PRIVATE).edit();
editor.putString("SEND","SharedPreferences的消息");
editor.apply();
startActivity(new Intent(MainActivity.this,ReceiveActivity.class));
// 接收消息
SharedPreferences sharedPreferences = getSharedPreferences("SEND", MODE_PRIVATE);
textView.setText(sharedPreferences.getString("SEND", ""));
附支持的数据类型如下:
SQLite
SQLite需要先创建数据库,后面向数据库中插入和读取数据实现信息共享。
首先要继承SQLiteOpenHelper并在onCreate方法中创建数据库:
sqLiteDatabase.execSQL("CREATE TABLE Teacher(teacherId INTEGER PRIMARY KEY" +
" AUTOINCREMENT,userId VARCHAR(20) UNIQUE,name VARCHAR(20),password VARCHAR(20))");
向数据库中插入:
String type = "Teacher";
sqLiteDatabase.execSQL("INSERT INTO " + type + "(userId,name,password) values (?,?,?)",
new String[]{userId, userName, userPassword});
从数据库中读取信息:
String type = "Teacher";
Cursor cursor = sqLiteDatabase.rawQuery("SELECT * FROM " + type + " WHERE userId = ?",
new String[]{userId.getText().toString()});
if(cursor.moveToFirst()){
String userId = cursor.getString(cursor.getColumnIndex("userId"));
String name = cursor.getString(cursor.getColumnIndex("name"));
}
cursor.close();
File
文件方式要记得申请权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
写入数据:
try {
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/data/temp.txt");
FileOutputStream out = new FileOutputStream(file);
out.write("message".getBytes(Charset.forName("UTF-8")));
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
读取数据:
try {
FileInputStream in = new FileInputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + "/temp.txt");
byte[] reader = new byte[256];
int read = in.read(reader);
String content = "";
if (read > 0)
content = new String(reader, 0, read, Charset.forName("UTF-8"));
Toast.makeText(this, content, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
6.Android 组件
Broadcast方式
使用组件也就是说利用Broadcast进行消息传递。 优选LocalBroadcast:
LocalBroadcastManager.getInstance(context).registerReceiver(@NonNull BroadcastReceiver receiver, @NonNull IntentFilter filter)
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
如果说使用Android 进行消息传递的话,Broadcast是最好的了,顾名思义的我们知道,广播就是有一个发送消息和接受消息的过程,所以可以用于消息传递。
示例:
注册广播和接受消息
// 定义广播
final Button broadButton = findViewById(R.id.broadcast);
final BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
broadButton.setText("" + intent.getStringExtra("data"));
}
};
broadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
registerReceiver(receiver,new IntentFilter("broadsend.action"));
startActivity(new Intent(MainActivity.this,ReceiveActivity.class));
}
});
发送广播:
Intent intent = new Intent("broadsend.action");
intent.putExtra("data","send");
sendBroadcast(intent);
这种方式有一些限制,因为接收事件要比发送事件先定义好,所以只能在当前Activity中注册广播,在跳转的Activity发送,所以严格说这不能算是消息传递,因为是单向的。
Service方式
Service可以结合Broadcast进行消息传递,不过这样子就不能算是Service了。
使用Service进行消息传递,我们可以定义接口,并利用接口进行消息传递。
定义消息接收的接口:
public static MessageCallback messageCallback = new MessageCallback() {
@Override
public void onMessage(String message) {
Log.d("tag","" + message);
}
};
public interface MessageCallback{
public void onMessage(String message);
}
进行消息发送:
MainActivity.messageCallback.onMessage("message");
有的人说这种方式不久和共享变量一样了吗,不不不,这是完全不一样的,如果是共享变量的话,当变量被改变了是不是还得程序员或者用户去响应这种改变呢,这就很不好了,而采用这种静态接口的方法,只要函数被调用,就立刻可以进行响应并处理,不是很方便吗。当然也可以想办法将接口的对象进行传递,例如利用Broadcast来进行传递。
。。。 未完待续
EventBus
EventBus 是一款针对Android的发布以及订阅事件总线,使用它可以很方便的进行信息传递,而且使用起来很方便。
首先是定义一个消息:
public class Event {
private String message;
public Event(){
message = "EventBus message";
}
public void setMessage(String message){
this.message = message;
}
public String getMessage(){
return message;
}
}
发送消息:
这里使用了postSticky,这是发送的粘性广播,使用这个发送就可以先发送信息再进行注册,后注册的也能接收到前面发送的广播。当然还有其他的使用方式,可以查查api文档。
EventBus.getDefault().postSticky(new Event());
startActivity(new Intent(MainActivity.this,ReceiveActivity.class));
注册事件的订阅者:
EventBus.getDefault().register(this);
接受粘性广播:
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEventThread(Event event) {
textView.setText(event.getMessage());
}
总结及对比
对上面所说的各种消息传递和通信进行一个对比,Intent的方法是不太适合大量的数据传递的,如果大于0.5M会抛出异常。而才用静态变量或者全局变量则占用内存较大,且不易管理。才用系统剪切板的很少见,以为容易丢失数据。本地化的存储方式需要较多的时间,但是这种方式存储的数据是持久化的,可以用于故障恢复等场景,不过就是需要考虑IO的时间。使用Androdi组件的Broadcast或者service在小数据传输时例如仅仅是Activity跳转传输一两个变量,就未免太大才小用了。EventBus是基于事件订阅和发布的,使用上很方便。总之,就是要根据自己的应用场景来合理选择。