我目前在Android中有一个服务,它是一个示例VOIP客户端,因此它会侦听SIP消息,如果它收到一个,它会启动一个带有UI组件的活动屏幕。
然后,以下SIP消息确定要在屏幕上显示活动的内容。 例如,如果它的来电将显示接听或拒绝或拨出电话,它将显示拨号屏幕。
在那一刻我使用Intents让Activity知道它应该显示的状态。
一个例子如下:
Intent i = new Intent();
i.setAction(SIPEngine.SIP_TRYING_INTENT);
i.putExtra("com.net.INCOMING", true);
sendBroadcast(i);
Intent x = new Intent();
x.setAction(CallManager.SIP_INCOMING_CALL_INTENT);
sendBroadcast(x);
Log.d("INTENT SENT", "INTENT SENT INCOMING CALL AFTER PROCESSINVITE");
因此,活动将为这些意图注册一个广播接收者,并根据收到的最后意图切换其状态。
示例代码如下:
SipCallListener = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(SIPEngine.SIP_RINGING_INTENT.equals(action)){
Log.d("cda ", "Got RINGING action SIPENGINE");
ringingSetup();
}
if(CallManager.SIP_INCOMING_CALL_INTENT.equals(action)){
Log.d("cda ", "Got PHONE RINGING action");
incomingCallSetup();
}
}
};
IntentFilter filter = new IntentFilter(CallManager.SIP_INCOMING_CALL_INTENT);
filter.addAction(CallManager.SIP_RINGING_CALL_INTENT);
registerReceiver(SipCallListener, filter);
但这似乎不是很有效,Intents将获得广播系统范围,并且Intents必须针对不同的状态进行激活,似乎它可能变得效率低下,我必须包括的越多,以及增加复杂性。
所以我想知道是否有更高效,更清洁的方法来做到这一点?
有没有办法让Intents只在应用程序内部进行广播?
回调会更好吗?如果是这样,为什么以及以何种方式实施它们?
答案 0 :(得分:52)
更新2015年:
这个问题/答案仍然有一些活动,但它已经超过5岁了,事情已经发生了很大变化。 5年前,下面的答案是我将如何处理它。后来我写了一个非常轻量级的依赖注入解决方案,我正在使用一段时间(我在评论中提到)。如今,我会用Dagger和RxAndroid回答这个问题。 Dagger在服务和需要通知的所有活动中注入“中介者”类,服务会将状态更新推送到中介类,并且中介类将公开活动的观察者以使用状态更新(代替OP的广播接收器)。
原始回答
我通常是应用程序的子类,让我的应用内通信通过这个类(或者让应用程序拥有的中介执行工作......无论如何,应用程序是服务与之通信的入口点)。我有一个绑定服务,也需要更新UI(比你的更简单,但相同的想法),它基本上告诉应用程序它的新状态,然后应用程序可以以这种或那种方式将这些信息传递给当前积极的活动。您还可以维护指向当前活动活动的指针(如果有多个),并决定是否只是更新当前活动,广播启动不同活动的意图,忽略该消息等。我会也是子类Activity并让你的新活动基类告诉应用程序它当前是onResume中的活动类,并且它在onPause中被暂停(对于你的服务在后台运行并且活动都被暂停的情况)。 / p>
修改强>
在回应评论时,这里有更具体的细节。
您的应用程序目前大部分由Activity派生类和Service派生类组成。本质上,您从android.app.Application类的实例获得功能。这在您的清单中声明(默认情况下),使用以下行:
<application android:icon="@drawable/icon" android:label="@string/app_name">
清单中的应用程序元素不使用android:name属性,因此它只创建默认android.app.Application类的实例来表示您的全局应用程序上下文。
在我的应用程序中,我创建了一个Application类的子类(例如ApplicationEx),我通过清单告诉我的应用程序,这是要实例化为MY全局应用程序上下文的类。例如:
<application
android:name="com.mycompany.myapp.app.ApplicationEx"
android:icon="@drawable/app_icon"
android:label="@string/app_name">
我现在可以向ApplicationEx添加用于通信的活动和服务的方法。您的全局应用程序上下文始终只有一个实例,因此如果您的应用需要全局,那么这就是您的起点。
第二部分是,我不是从Service和Activity派生我的服务和活动,而是使用getAppContext方法创建每个子类,该方法强制转换getApplicationContext的返回值(因为它们已存在于这两个类中)派生自Context)到我的ApplicationEx类。
所以........
所有这一切,您将CurrentActivity属性添加到Activity类型的ApplicationEx类(如果您像我一样将其子类化,则添加ActivityBase)。在ActivityBase的onResume方法中,您将自己传递给ApplicationEx,以便将CurrentActivity设置为该活动。现在,您可以在ApplicationEx上公开方法,将信息直接传递给当前活动,而不是依赖于Intent机制。
这就像我能做到的那样明确
答案 1 :(得分:2)
帮助程序注册并向您的进程中的本地对象发送Intent广播。与使用sendBroadcast(Intent)发送全局广播相比,这有许多优点:
您知道您正在播放的数据不会离开您的应用,因此无需担心泄露私人数据。
其他应用程序无法将这些广播发送到您的应用程序,因此您无需担心他们可以利用的安全漏洞。
它比通过系统发送全局广播更有效。
但是,我仍然建议在必要时使用Service方法和本地绑定以及通过Handler进行通话来更新UI组件以提高效率。