代码之家  ›  专栏  ›  技术社区  ›  Donal Rafferty

从服务更新ui的效率比意图更高?

  •  41
  • Donal Rafferty  · 技术社区  · 14 年前

    我目前在android中有一个服务,它是一个voip客户机示例,因此它监听sip消息,如果它收到一条消息,它就会启动一个带有ui组件的活动屏幕。

    然后,以下SIP消息确定要在屏幕上显示的活动。 例如,如果它是一个来电,它将显示应答或拒绝,或一个外拨电话,它将显示一个拨号屏幕。

    此时,我使用intents让活动知道它应该显示什么状态。

    示例如下:


            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);
    

    这项工作,但它似乎不是很有效,意图将得到全系统的广播和意图,必须为不同的国家开火,似乎它可能会变得低效,更多我必须包括以及增加复杂性。

    所以我想知道是否有另一种更有效更干净的方法来做这件事?

    有没有办法让意图只在应用程序内部广播?

    回调会是个更好的主意吗?如果是,为什么以什么方式实施?

    2 回复  |  直到 9 年前
        1
  •  52
  •   Rich    9 年前

    更新2015:

    这个问题/答案仍然有一点活跃,但它已经超过5年了,事情已经发生了很大的变化。5年前,下面的答案是我应该如何处理。后来我写了一个非常轻量级的依赖注入解决方案,我使用了一段时间(我在评论中提到)。现在,我会用匕首和恶棍来回答这个问题。匕首将一个“mediator”类注入到服务和所有需要通知的活动中,服务将状态更新推送到mediator类,mediator类将暴露一个可观察的活动来使用状态更新(代替op的广播CEVER)。

    原始答案

    我通常对应用程序进行子类划分,让我的应用程序内通信通过这个类(或者让应用程序拥有的中介来完成工作……不管怎样,应用程序是服务通信的入口点)。我有一个绑定服务,它也需要更新ui(比你的简单得多,但想法相同),它基本上告诉应用程序它的新状态,然后应用程序可以通过某种方式将这些信息传递给当前活动。您还可以维护指向当前活动活动(如果有多个活动)的指针,并决定是否简单地更新当前活动、广播启动其他活动的意图、忽略消息等。我还将对活动进行子类划分,并让您的新活动vity基类告诉应用程序它当前是onresume中的活动类,并且它正在onpause中暂停(对于在后台运行服务并且所有活动都暂停的情况)。

    编辑:

    针对这一评论,这里有更多的细节。

    您的应用程序目前大部分由活动派生类和服务派生类组成。从本质上讲,您可以从android.app.application类的实例获得功能。这是在清单(默认情况下)中用以下行声明的:

    <application android:icon="@drawable/icon" android:label="@string/app_name">
    

    清单中的application元素没有使用android:name属性,因此它只是创建一个默认android.app.application类的实例来表示全局应用程序上下文。

    在我的应用程序中,我创建应用程序的一个子类(例如applicationex),并通过清单告诉我的应用程序,这是要实例化为我的全局应用程序上下文的类。例如:

    <application
        android:name="com.mycompany.myapp.app.ApplicationEx"
        android:icon="@drawable/app_icon"
        android:label="@string/app_name">
    

    我现在可以向applicationex中添加用于通信的活动和服务的方法。您的全局应用程序上下文始终只有一个实例,因此,如果您的应用程序需要全局性,则这是您的起点。

    第二点是,我没有从服务和活动派生我的服务和活动,而是使用getappcontext方法创建每个的子类,该方法将getapplicationcontext的返回值(这两个类中都已经存在,因为它们是从上下文派生的)强制转换为是applicationex类。

    所以…

    尽管如此,您还是向activity类型的applicationex类(或者activitybase,如果您像我一样对其进行子类化的话)添加了currentActivity属性。在activitybase的onresume方法中,您将自己传递给applicationex,以便它将currentactivity设置为该活动。现在,您可以在applicationex上公开方法,直接将信息传递给当前活动,而不依赖于意图机制。

    我已经尽可能清楚了

        2
  •  2
  •   MasterAM    10 年前

    您可以将广播意图发送到您自己的应用程序,而不是整个系统 LocalBroadcastManager :

    帮助程序注册意图广播并将其发送到进程中的本地对象。与使用SendBroadcast发送全局广播相比,它有许多优点(意图):

    你知道你正在广播的数据不会离开你的应用程序,所以不必担心泄露私人数据。

    其他应用程序不可能将这些广播发送到您的应用程序,因此您不必担心它们可能会利用安全漏洞。

    它比通过系统发送全球广播更有效。

    但是,我仍然建议您使用服务方法和本地绑定,并在必要时通过处理程序来更新ui组件以提高效率。