Example: Communication between Activity and Service using Messaging
我找不到任何关于如何在活动和服务之间发送消息的示例,我花了太多时间来解决这个问题。下面是一个供其他人参考的示例项目。
此示例允许您直接启动或停止服务,并分别从服务绑定/取消绑定。当服务运行时,它以10赫兹的频率递增一个数字。如果活动绑定到
截图:
androidmanifest.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.exampleservice" android:versionCode="1" android:versionName="1.0"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".MyService"></service> </application> <uses-sdk android:minSdkVersion="8" /> </manifest> |
resvaluesstrings.xml:
1 2 3 4 5 6 | <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">ExampleService</string> <string name="service_started">Example Service started</string> <string name="service_label">Example Service Label</string> </resources> |
reslayoutmain.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | <RelativeLayout android:id="@+id/RelativeLayout01" android:layout_width="fill_parent" android:layout_height="wrap_content"> <Button android:id="@+id/btnStart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Service"> </Button> <Button android:id="@+id/btnStop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="Stop Service"> </Button> </RelativeLayout> <RelativeLayout android:id="@+id/RelativeLayout02" android:layout_width="fill_parent" android:layout_height="wrap_content"> <Button android:id="@+id/btnBind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Bind to Service"> </Button> <Button android:id="@+id/btnUnbind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="Unbind from Service"> </Button> </RelativeLayout> <TextView android:id="@+id/textStatus" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Status Goes Here" android:textSize="24sp" /> <TextView android:id="@+id/textIntValue" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Integer Value Goes Here" android:textSize="24sp" /> <TextView android:id="@+id/textStrValue" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="String Value Goes Here" android:textSize="24sp" /> <RelativeLayout android:id="@+id/RelativeLayout03" android:layout_width="fill_parent" android:layout_height="wrap_content"> <Button android:id="@+id/btnUpby1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Increment by 1"> </Button> <Button android:id="@+id/btnUpby10" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="Increment by 10"> </Button> </RelativeLayout> |
srccom.exampleservicemainactivity.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | package com.exampleservice; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { Button btnStart, btnStop, btnBind, btnUnbind, btnUpby1, btnUpby10; TextView textStatus, textIntValue, textStrValue; Messenger mService = null; boolean mIsBound; final Messenger mMessenger = new Messenger(new IncomingHandler()); class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MyService.MSG_SET_INT_VALUE: textIntValue.setText("Int Message:" + msg.arg1); break; case MyService.MSG_SET_STRING_VALUE: String str1 = msg.getData().getString("str1"); textStrValue.setText("Str Message:" + str1); break; default: super.handleMessage(msg); } } } private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { mService = new Messenger(service); textStatus.setText("Attached."); try { Message msg = Message.obtain(null, MyService.MSG_REGISTER_CLIENT); msg.replyTo = mMessenger; mService.send(msg); } catch (RemoteException e) { // In this case the service has crashed before we could even do anything with it } } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been unexpectedly disconnected - process crashed. mService = null; textStatus.setText("Disconnected."); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btnStart = (Button)findViewById(R.id.btnStart); btnStop = (Button)findViewById(R.id.btnStop); btnBind = (Button)findViewById(R.id.btnBind); btnUnbind = (Button)findViewById(R.id.btnUnbind); textStatus = (TextView)findViewById(R.id.textStatus); textIntValue = (TextView)findViewById(R.id.textIntValue); textStrValue = (TextView)findViewById(R.id.textStrValue); btnUpby1 = (Button)findViewById(R.id.btnUpby1); btnUpby10 = (Button)findViewById(R.id.btnUpby10); btnStart.setOnClickListener(btnStartListener); btnStop.setOnClickListener(btnStopListener); btnBind.setOnClickListener(btnBindListener); btnUnbind.setOnClickListener(btnUnbindListener); btnUpby1.setOnClickListener(btnUpby1Listener); btnUpby10.setOnClickListener(btnUpby10Listener); restoreMe(savedInstanceState); CheckIfServiceIsRunning(); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("textStatus", textStatus.getText().toString()); outState.putString("textIntValue", textIntValue.getText().toString()); outState.putString("textStrValue", textStrValue.getText().toString()); } private void restoreMe(Bundle state) { if (state!=null) { textStatus.setText(state.getString("textStatus")); textIntValue.setText(state.getString("textIntValue")); textStrValue.setText(state.getString("textStrValue")); } } private void CheckIfServiceIsRunning() { //If the service is running when the activity starts, we want to automatically bind to it. if (MyService.isRunning()) { doBindService(); } } private OnClickListener btnStartListener = new OnClickListener() { public void onClick(View v){ startService(new Intent(MainActivity.this, MyService.class)); } }; private OnClickListener btnStopListener = new OnClickListener() { public void onClick(View v){ doUnbindService(); stopService(new Intent(MainActivity.this, MyService.class)); } }; private OnClickListener btnBindListener = new OnClickListener() { public void onClick(View v){ doBindService(); } }; private OnClickListener btnUnbindListener = new OnClickListener() { public void onClick(View v){ doUnbindService(); } }; private OnClickListener btnUpby1Listener = new OnClickListener() { public void onClick(View v){ sendMessageToService(1); } }; private OnClickListener btnUpby10Listener = new OnClickListener() { public void onClick(View v){ sendMessageToService(10); } }; private void sendMessageToService(int intvaluetosend) { if (mIsBound) { if (mService != null) { try { Message msg = Message.obtain(null, MyService.MSG_SET_INT_VALUE, intvaluetosend, 0); msg.replyTo = mMessenger; mService.send(msg); } catch (RemoteException e) { } } } } void doBindService() { bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE); mIsBound = true; textStatus.setText("Binding."); } void doUnbindService() { if (mIsBound) { // If we have received the service, and hence registered with it, then now is the time to unregister. if (mService != null) { try { Message msg = Message.obtain(null, MyService.MSG_UNREGISTER_CLIENT); msg.replyTo = mMessenger; mService.send(msg); } catch (RemoteException e) { // There is nothing special we need to do if the service has crashed. } } // Detach our existing connection. unbindService(mConnection); mIsBound = false; textStatus.setText("Unbinding."); } } @Override protected void onDestroy() { super.onDestroy(); try { doUnbindService(); } catch (Throwable t) { Log.e("MainActivity","Failed to unbind from the service", t); } } } |
srccom.exampleservicemyservice.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | package com.exampleservice; import java.util.ArrayList; import java.util.Timer; import java.util.TimerTask; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; public class MyService extends Service { private NotificationManager nm; private Timer timer = new Timer(); private int counter = 0, incrementby = 1; private static boolean isRunning = false; ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients. int mValue = 0; // Holds last value set by a client. static final int MSG_REGISTER_CLIENT = 1; static final int MSG_UNREGISTER_CLIENT = 2; static final int MSG_SET_INT_VALUE = 3; static final int MSG_SET_STRING_VALUE = 4; final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler. @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } class IncomingHandler extends Handler { // Handler of incoming messages from clients. @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_REGISTER_CLIENT: mClients.add(msg.replyTo); break; case MSG_UNREGISTER_CLIENT: mClients.remove(msg.replyTo); break; case MSG_SET_INT_VALUE: incrementby = msg.arg1; break; default: super.handleMessage(msg); } } } private void sendMessageToUI(int intvaluetosend) { for (int i=mClients.size()-1; i>=0; i--) { try { // Send data as an Integer mClients.get(i).send(Message.obtain(null, MSG_SET_INT_VALUE, intvaluetosend, 0)); //Send data as a String Bundle b = new Bundle(); b.putString("str1","ab" + intvaluetosend +"cd"); Message msg = Message.obtain(null, MSG_SET_STRING_VALUE); msg.setData(b); mClients.get(i).send(msg); } catch (RemoteException e) { // The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop. mClients.remove(i); } } } @Override public void onCreate() { super.onCreate(); Log.i("MyService","Service Started."); showNotification(); timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 0, 100L); isRunning = true; } private void showNotification() { nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); // In this sample, we'll use the same text for the ticker and the expanded notification CharSequence text = getText(R.string.service_started); // Set the icon, scrolling text and timestamp Notification notification = new Notification(R.drawable.icon, text, System.currentTimeMillis()); // The PendingIntent to launch our activity if the user selects this notification PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0); // Set the info for the views that show in the notification panel. notification.setLatestEventInfo(this, getText(R.string.service_label), text, contentIntent); // Send the notification. // We use a layout id because it is a unique number. We use it later to cancel. nm.notify(R.string.service_started, notification); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("MyService","Received start id" + startId +":" + intent); return START_STICKY; // run until explicitly stopped. } public static boolean isRunning() { return isRunning; } private void onTimerTick() { Log.i("TimerTick","Timer doing work." + counter); try { counter += incrementby; sendMessageToUI(counter); } catch (Throwable t) { //you should always ultimately catch all exceptions in timer tasks. Log.e("TimerTick","Timer Tick Failed.", t); } } @Override public void onDestroy() { super.onDestroy(); if (timer != null) {timer.cancel();} counter=0; nm.cancel(R.string.service_started); // Cancel the persistent notification. Log.i("MyService","Service Stopped."); isRunning = false; } } |
查看localservice示例。
您的
对于向服务发送数据,您可以使用:
1 2 3 | Intent intent = new Intent(getApplicationContext(), YourService.class); intent.putExtra("SomeData","ItValue"); startService(intent); |
在onStartCommand()中服务之后,从intent中获取数据。
用于将数据或事件从服务发送到应用程序(对于一个或多个活动):
1 2 3 4 5 6 7 | private void sendBroadcastMessage(String intentFilterName, int arg1, String extraKey) { Intent intent = new Intent(intentFilterName); if (arg1 != -1 && extraKey != null) { intent.putExtra(extraKey, arg1); } sendBroadcast(intent); } |
此方法正在从您的服务调用。您可以简单地为您的活动发送数据。
1 2 3 4 5 6 7 | private void someTaskInYourService(){ //For example you downloading from server 1000 files for(int i = 0; i < 1000; i++) { Thread.sleep(5000) // 5 seconds. Catch in try-catch block sendBroadCastMessage(Events.UPDATE_DOWNLOADING_PROGRESSBAR, i,0,"up_download_progress"); } |
要接收带有数据的事件,请在活动中创建并注册方法registerBroadcastReceivers():
1 2 3 4 5 6 7 8 9 10 | private void registerBroadcastReceivers(){ broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int arg1 = intent.getIntExtra("up_download_progress",0); progressBar.setProgress(arg1); } }; IntentFilter progressfilter = new IntentFilter(Events.UPDATE_DOWNLOADING_PROGRESS); registerReceiver(broadcastReceiver,progressfilter); |
为了发送更多的数据,您可以修改方法
更新
请不要在活动和服务之间使用我的通信类型。这是错误的方法。为了获得更好的体验,请使用特殊的libs,例如:
1)来自GreenRobot的事件总线
2)Otto From Square公司
另外,我只在我的项目中使用绿色机器人的eventbus,
注意:你不需要检查你的服务是否在运行,
另外:如果你转动手机,你就不想再把它转到
一切都很好。很好的例子就是使用messenger进行
一条注释:方法
如果myservice运行在不同的进程中,那么静态函数
1 2 3 4 5 6 | Message msg = Message.obtain(null, 2, 0, 0); Bundle bundle = new Bundle(); bundle.putString("url", url); bundle.putString("names", names); bundle.putString("captions",captions); msg.setData(bundle); |
所以你把它送到服务中心。之后接收。
这就是我如何实现活动->服务通信:在我的活动中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | private static class MyResultReciever extends ResultReceiver { /** * Create a new ResultReceive to receive results. Your * {@link #onReceiveResult} method will be called from the thread running * <var>handler</var> if given, or from an arbitrary thread if null. * * @param handler */ public MyResultReciever(Handler handler) { super(handler); } @Override protected void onReceiveResult(int resultCode, Bundle resultData) { if (resultCode == 100) { //dostuff } } |
然后我用这个开始服务
1 2 3 4 5 6 | protected void onCreate(Bundle savedInstanceState) { MyResultReciever resultReciever = new MyResultReciever(handler); service = new Intent(this, MyService.class); service.putExtra("receiver", resultReciever); startService(service); } |
在我的服务中
1 2 3 4 5 | public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) resultReceiver = intent.getParcelableExtra("receiver"); return Service.START_STICKY; } |
希望这有帮助
我看到了所有的答案。我想说一天中最有力的方法。这将使您在
事件总线
我在项目中使用的这个lib具有与消息传递相关的强大功能。
事件总线分三步
定义事件:
准备订阅服务器:
声明和注释订阅方法,可以选择指定线程模式:
1 2 | @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) {/* Do something */}; |
注册并注销订阅服务器。例如,在Android上,活动和片段通常应根据其生命周期进行注册:
1 2 3 4 5 6 7 8 9 10 11 | @Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop() { super.onStop(); EventBus.getDefault().unregister(this); } |
事后事件:
只需在应用程序级别的渐变中添加此依赖项
1 | compile 'org.greenrobot:eventbus:3.1.1' |
很好的教程,精彩的演示。整洁、简单、简短、解释性强。不过,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | private static final int NOTIFICATION_ID = 45349; private void showNotification() { NotificationCompat.Builder builder = new NotificationCompat.Builder(this) .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle("My Notification Title") .setContentText("Something interesting happened"); Intent targetIntent = new Intent(this, MainActivity.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, targetIntent, PendingIntent.FLAG_UPDATE_CURRENT); builder.setContentIntent(contentIntent); _nManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); _nManager.notify(NOTIFICATION_ID, builder.build()); } @Override public void onDestroy() { super.onDestroy(); if (_timer != null) {_timer.cancel();} _counter=0; _nManager.cancel(NOTIFICATION_ID); // Cancel the persistent notification. Log.i("PlaybackService","Service Stopped."); _isRunning = false; } |
我检查过,一切都像是一个魅力(活动和服务名称可能与原来不同)。
在我看来,通过使用"implements handler.callback"声明活动,可以节省一些内存。