我正在编写我的第一个Android应用程序,试图弄清楚服务和活动之间的通信。我有一个服务,将在后台运行,并做一些gps和基于时间的日志记录。我将有一个活动,将用于启动和停止服务。

因此,首先,我需要能够确定当活动启动时服务是否正在运行。这里还有一些其他的问题,所以我想我可以解决(但请随意提供建议)。

My real problem: if the Activity is running and the Service is started, I need a way for the Service to send messages to the Activity. Simple Strings and integers at this point - status messages mostly. The messages will not happen regularly, so I don't think polling the service is a good way to go if there is another way. I only want this communication when the Activity has been started by the user - I don't want to start the Activity from the Service. In other words, if you start the Activity and the Service is running, you will see some status messages in the Activity UI when something interesting happens. If you don't start the Activity, you will not see these messages (they're not that interesting).

似乎我应该能够确定服务是否正在运行,如果是的话,将活动添加为侦听器。然后在Activity暂停或停止时删除Activity作为监听器。这真的可能吗?我能想出的唯一方法是让活动实现Parcelable并构建一个AIDL文件,这样我就可以通过服务的远程接口传递它。这似乎是多余的,但我不知道活动应该如何实现writeToParcel() / readFromParcel()。

有没有更简单或更好的方法?谢谢你的帮助。

编辑:

对于稍后对此感兴趣的人来说,在示例目录:/apis/app/RemoteService.java中有来自谷歌的通过AIDL处理此问题的示例代码


当前回答

提问者可能早就跳过了这个,但以防其他人搜索这个…

还有另一种处理方法,我认为可能是最简单的。

为您的活动添加一个BroadcastReceiver。注册它来接收一些自定义意图在onResume和取消注册它在onPause。然后当你想要发送状态更新或其他信息时,从你的服务中发送意图。

确保如果其他应用程序监听了你的意图(有人会做任何恶意的事情吗?),你不会不高兴,但除此之外,你应该没问题。

代码示例:

在我的工作中,我有这个:

// Do stuff that alters the content of my local SQLite Database
sendBroadcast(new Intent(RefreshTask.REFRESH_DATA_INTENT));

(RefreshTask。REFRESH_DATA_INTENT只是一个常量字符串。)

在我的监听活动中,我定义了BroadcastReceiver:

private class DataUpdateReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(RefreshTask.REFRESH_DATA_INTENT)) {
          // Do stuff - maybe update my view based on the changed DB contents
        }
    }
}

我在类的顶部声明了我的接收者:

private DataUpdateReceiver dataUpdateReceiver;

我覆盖onResume添加这个:

if (dataUpdateReceiver == null) dataUpdateReceiver = new DataUpdateReceiver();
IntentFilter intentFilter = new IntentFilter(RefreshTask.REFRESH_DATA_INTENT);
registerReceiver(dataUpdateReceiver, intentFilter);

我重写onPause添加:

if (dataUpdateReceiver != null) unregisterReceiver(dataUpdateReceiver);

现在我的活动正在监听我的服务说“嘿,去更新你自己。”我可以在Intent中传递数据,而不是更新数据库表,然后返回到我的活动中寻找更改,但由于我希望更改始终存在,因此通过DB传递数据是有意义的。

其他回答

提问者可能早就跳过了这个,但以防其他人搜索这个…

还有另一种处理方法,我认为可能是最简单的。

为您的活动添加一个BroadcastReceiver。注册它来接收一些自定义意图在onResume和取消注册它在onPause。然后当你想要发送状态更新或其他信息时,从你的服务中发送意图。

确保如果其他应用程序监听了你的意图(有人会做任何恶意的事情吗?),你不会不高兴,但除此之外,你应该没问题。

代码示例:

在我的工作中,我有这个:

// Do stuff that alters the content of my local SQLite Database
sendBroadcast(new Intent(RefreshTask.REFRESH_DATA_INTENT));

(RefreshTask。REFRESH_DATA_INTENT只是一个常量字符串。)

在我的监听活动中,我定义了BroadcastReceiver:

private class DataUpdateReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(RefreshTask.REFRESH_DATA_INTENT)) {
          // Do stuff - maybe update my view based on the changed DB contents
        }
    }
}

我在类的顶部声明了我的接收者:

private DataUpdateReceiver dataUpdateReceiver;

我覆盖onResume添加这个:

if (dataUpdateReceiver == null) dataUpdateReceiver = new DataUpdateReceiver();
IntentFilter intentFilter = new IntentFilter(RefreshTask.REFRESH_DATA_INTENT);
registerReceiver(dataUpdateReceiver, intentFilter);

我重写onPause添加:

if (dataUpdateReceiver != null) unregisterReceiver(dataUpdateReceiver);

现在我的活动正在监听我的服务说“嘿,去更新你自己。”我可以在Intent中传递数据,而不是更新数据库表,然后返回到我的活动中寻找更改,但由于我希望更改始终存在,因此通过DB传递数据是有意义的。

绑定是另一种通信方式

创建回调

public interface MyCallBack{

   public void getResult(String result);

}

活动方面:

Implement the interface in the Activity Provide the implementation for the method Bind the Activity to Service Register and Unregister Callback when the Service gets bound and unbound with Activity. public class YourActivity extends AppCompatActivity implements MyCallBack{ private Intent notifyMeIntent; private GPSService gpsService; private boolean bound = false; @Override public void onCreate(Bundle sis){ // activity code ... startGPSService(); } @Override public void getResult(String result){ // show in textView textView.setText(result); } @Override protected void onStart() { super.onStart(); bindService(); } @Override protected void onStop() { super.onStop(); unbindService(); } private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { GPSService.GPSBinder binder = (GPSService.GPSBinder) service; gpsService= binder.getService(); bound = true; gpsService.registerCallBack(YourActivity.this); // register } @Override public void onServiceDisconnected(ComponentName arg0) { bound = false; } }; private void bindService() { bindService(notifyMeIntent, serviceConnection, Context.BIND_AUTO_CREATE); } private void unbindService(){ if (bound) { gpsService.registerCallBack(null); // unregister unbindService(serviceConnection); bound = false; } } // Call this method somewhere to start Your GPSService private void startGPSService(){ notifyMeIntent = new Intent(this, GPSService.class); startService(myIntent ); } }

服务端:

Initialize callback Invoke the callback method whenever needed public class GPSService extends Service{ private MyCallBack myCallback; private IBinder serviceBinder = new GPSBinder(); public void registerCallBack(MyCallBack myCallback){ this.myCallback= myCallback; } public class GPSBinder extends Binder{ public GPSService getService(){ return GPSService.this; } } @Nullable @Override public IBinder onBind(Intent intent){ return serviceBinder; } }

使用信使是在服务和活动之间进行通信的另一种简单方法。

在Activity中,创建带有相应Messenger的Handler。这将处理来自服务的消息。

class ResponseHandler extends Handler {
    @Override public void handleMessage(Message message) {
            Toast.makeText(this, "message from service",
                    Toast.LENGTH_SHORT).show();
    }
}
Messenger messenger = new Messenger(new ResponseHandler());

Messenger可以通过将其附加到Message来传递给服务:

Message message = Message.obtain(null, MyService.ADD_RESPONSE_HANDLER);
message.replyTo = messenger;
try {
    myService.send(message);
catch (RemoteException e) {
    e.printStackTrace();
}

在API演示中可以找到完整的示例:MessengerService和MessengerServiceActivity。关于MyService如何工作,请参阅完整的示例。

除了LocalBroadcastManager,事件总线和信使已经回答了这个问题,我们可以使用未决意图从服务通信。

正如我在博客中提到的

Communication between service and Activity can be done using PendingIntent.For that we can use createPendingResult().createPendingResult() creates a new PendingIntent object which you can hand to service to use and to send result data back to your activity inside onActivityResult(int, int, Intent) callback.Since a PendingIntent is Parcelable , and can therefore be put into an Intent extra,your activity can pass this PendingIntent to the service.The service, in turn, can call send() method on the PendingIntent to notify the activity via onActivityResult of an event. Activity public class PendingIntentActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); PendingIntent pendingResult = createPendingResult( 100, new Intent(), 0); Intent intent = new Intent(getApplicationContext(), PendingIntentService.class); intent.putExtra("pendingIntent", pendingResult); startService(intent); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 100 && resultCode==200) { Toast.makeText(this,data.getStringExtra("name"),Toast.LENGTH_LONG).show(); } super.onActivityResult(requestCode, resultCode, data); } } Service public class PendingIntentService extends Service { private static final String[] items= { "lorem", "ipsum", "dolor", "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi", "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", "vel", "erat", "placerat", "ante", "porttitor", "sodales", "pellentesque", "augue", "purus" }; private PendingIntent data; @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { data = intent.getParcelableExtra("pendingIntent"); new LoadWordsThread().start(); return START_NOT_STICKY; } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { super.onDestroy(); } class LoadWordsThread extends Thread { @Override public void run() { for (String item : items) { if (!isInterrupted()) { Intent result = new Intent(); result.putExtra("name", item); try { data.send(PendingIntentService.this,200,result); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } SystemClock.sleep(400); } } } } }

To follow up on @MrSnowflake answer with a code example. This is the XABBER now open source Application class. The Application class is centralising and coordinating Listeners and ManagerInterfaces and more. Managers of all sorts are dynamically loaded. Activity´s started in the Xabber will report in what type of Listener they are. And when a Service start it report in to the Application class as started. Now to send a message to an Activity all you have to do is make your Activity become a listener of what type you need. In the OnStart() OnPause() register/unreg. The Service can ask the Application class for just that listener it need to speak to and if it's there then the Activity is ready to receive.

通过应用程序类,你会看到比这个更多的战利品。