由于android系统中应用程序之间不能共享内存。因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些。
在android SDK中提供了4种用于跨进程通讯的方式。这4种方式正好对应于android系统中4种应用程序组件:Activity、Content Provider、Broadcast和Service。
我的同学遇到了两个应用程序进行通讯的问题,下面为解决这个问题所做一下总结。
事情是这样的他们公司有两个不同的应用需要通讯,这里是要用广播方式来实现。 他的广播是在AndroidManifest
中静态注册的因为他需要在程序没有运行时做一些事情,同时呢如果应用正在运行时还需要UI做动态的更新,这就是问题了的所在了。
开始的问题是在 BroadcastReceiver的 onReceive中根本获取不到UI的对象,平时写BroadcastReceiver都是在Activity中直接写了,就需要传递参数了。
我这里呢是使用接口的形式来实现的。首先定义一个接口,接口中就是广播接收器发送来的内容,这里我们是设置文本。
/** * @category XXX广播接收器接口 * * @author ylbf * @version 2016-02-17 17:15:52 */
public interface BRInteraction {
/** * * @param content * 传递内容 */
public void setText(String content);
}
我这里是用插拔USB的方式来来触发对充电状态的广播来模拟别的应用发送的广播。然后把数据通过接口来发送。同时弹出一个Toast来证明应用退出了广播接收器还在工作状态中。
public class PowerConnectionReceiver extends BroadcastReceiver {
private BRInteraction brInteraction;
@Override
public void onReceive(Context context, Intent intent) {
int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;
Toast.makeText(context, "USB充电:" + usbCharge, Toast.LENGTH_SHORT).show();
if (brInteraction != null) {
brInteraction.setText("USB充电:" + usbCharge);
}
}
public void setBRInteractionListener(BRInteraction brInteraction) {
this.brInteraction = brInteraction;
}
}
下面别忘了在AndroidManifest文件中静态注册
<receiver android:name=".PowerConnectionReceiver" >
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
intent-filter>
receiver>
到了这一步这个广播接收器已经完成一半了启动应用会发现这个这个广播接收器可以工作了可以弹出这个Toast来显示充电的状态。
下面是Activity中注册监听器的代码这里呢是改变UI上的一个TextView中的内容。
/** * 注册监听器 * * @param textView */
private void regListener(final TextView textView) {
PowerConnectionReceiver powerConnectionReceiver = new PowerConnectionReceiver();
powerConnectionReceiver.setBRInteractionListener(new BRInteraction() {
@Override
public void setText(String content) {
if (content != null) {
textView.setText(content);
}
}
});
}
启动应用插拔USB之后查看Toast正常弹出但是UI上的TextView并没有改变,经过调试发现Activity调用onReceive方法中brInteraction为NULL ,所以UI上的回掉方法就没有执行。看来这种方法还是不够的。
接着呢下面又在UI界面中又注册了一遍广播接收器发现可以了。
/** * 注册监听器且注册广播 * * @param textView */
private void regListenerAndReceiver(final TextView textView) {
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
PowerConnectionReceiver powerConnectionReceiver = new PowerConnectionReceiver();
registerReceiver(powerConnectionReceiver, intentFilter);
powerConnectionReceiver.setBRInteractionListener(new BRInteraction() {
@Override
public void setText(String content) {
if (content != null) {
textView.setText(content);
}
}
});
}
android的广播分为静态注册和动态注册两种方式,具体的操作方式网上有非常多的案例。这里主要记录一下他们的一些特殊的小知识。
1.动态注册和静态注册可以同时进行,简单来说就是使用一个Receiver分别在
AndroidManifast
中进行注册,又写入在程序中用代码注册(无论Action是否相同),两种注册方式不会造成影响。动态注册只会在程序存在时执行,静态注册一直执行。哪怕是完全相同的Receiver。即如果程序存在,该Receiver会被执行两次。2.动态注册使用同一个Receiver对象,从开始创建直到其被解除注册。会使用同一个Receiver,无论这个广播被触发几次。而静态注册则每次触发都会建立新的Receiver对象。
3.
android.intent.action.SCREEN_ON
与android.intent.action.SCREEN_OFF
不可以使用静态注册(没有效果),必须使用动态注册的方式。可能是由于android的内部管理机制导致,不希望程序在未运行时还保持对屏幕的监视。