如何有安卓服务与活动
-
20-09-2019 - |
题
我在写我的简单的应用程序,并试图把我的头周围的通信之间的服务和活动。我有一个服务,将运行的背景和做一些gps和基于时间的日志记录。我将有一个活动,将用于启动和停止服务。
因此,首先,我需要的是能够弄清楚,如果该服务是在运行时的活动是开始。还有一些其他的问题在这里,所以我想我可以认出来(但感到免费提供咨询意见).
我真正的问题:如果该活动是运行和服务开始时,我需要的一种方式用于服务发送消息的活动。简单的字符串整数和在这一点上的状况的消息。消息不会经常发生,因此我不认为询服务是一个良好的路要走,如果有另一种方式。我只想要这个的通信活动已经开始通过用户-我不想开始的活动的服务。换句话说,如果你开始的活动和服务的运行时,你会看到一些消息的状态在活动时一些有趣的事情发生。如果你不开始的活动,将看不到这些消息(他们是不是很有趣).
好像我应该能够确定,如果服务的运行,如果是,增加的活动作为一个听众。然后删除的活动作为一个听众时的活动暂停或停止。是,实际上可能吗?只有这样我可以找到这样做是有的活动执行Parcelable和建立一个AIDL文件,因此我可以通过它通过服务的远程接口。这似乎是矫枉过正,虽然,我也不知道怎么的活动应该实现writeToParcel()/readFromParcel().
是有一个容易的或更好的办法?谢谢你任何帮助。
编辑:
任何人感兴趣的在这之后,有样品代码为处理这个通过AIDL在的样品目录:/apis/app/RemoteService.java
解决方案
有三个明显的方式向通信服务:
- 使用意图
- 使用AIDL
- 使用服务对象本身(作为单独)
在你的情况,我去与选项3。做一个静态的参考服务,它自和填充它在onCreate():
void onCreate(Intent i) {
sInstance = this;
}
做一个静态功能 MyService getInstance()
, 返回静 sInstance
.
然后在 Activity.onCreate()
你开始服务、异步等待直到服务实际开始(你可能有你的服务的通知程序,它准备通过发送一个意图的活动。) 并获得它的实例。当你的实例时,登记册服务听众对象为你服务,你是设置。注:当编辑的风景内的活动应该修改它们在UI线,服务可能会运行其自己的线,所以你需要电话 Activity.runOnUiThread()
.
最后一件事你需要做的是删除的参考你的听众对象 Activity.onPause()
, 否则的一个实例您的活动方面将泄漏、不良好。
注:这种方法只是有用的,当应用程序/活动/任务是唯一的过程,这将访问您的服务。如果不是这种情况下你必须使用选项1。或2。
其他提示
提问者可能已经早已移过这一点,但如果别人搜索这个...
有另一种方式来处理这个问题,我认为这可能是最简单的。
一BroadcastReceiver
添加到您的活动。用它来接收在onResume
一些自定义的意图,并在onPause
注销它。然后从你的服务发出这一意图,当你想送你的状态更新或者你有什么。
请确保你不会不高兴,如果一些其他应用程序听了您的Intent
(任何人都可以做任何恶意的?),但除此之外,你应该是好的。
代码示例:
在我的服务,我有这样的:
// 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来传递数据。
使用LocalBroadcastManager
注册一个接收器监听来自本地服务发送应用内的广播,引用放在这里:
http://developer.android.com/reference /android/support/v4/content/LocalBroadcastManager.html
使用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());
信使可通过将其连接到一个消息被传递给服务:
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是如何工作的完整的例子。
,这不是在其他意见中提到的另一种方法是从使用bindService(活性绑定到服务),并在ServiceConnection回调获得服务的一个实例。如这里所描述的 http://developer.android.com/guide/components/bound- services.html
您也可以使用LiveData
其工作类似于EventBus
。
class MyService : LifecycleService() {
companion object {
var BUS = MutableLiveData<Object>()
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
val testItem : Object
// expose your data
if (BUS.hasActiveObservers()) {
BUS.postValue(testItem)
}
return START_NOT_STICKY
}
}
然后从Activity
添加观察者。
MyService.BUS.observe(this, Observer {
it?.let {
// Do what you need to do here
}
})
您可以阅读这篇更多博客。
的另一种方式可以是使用观察者通过所述活性的假模型类和服务本身,实施MVC模式的变化。我不知道这是否是做到这一点的最好办法,但它是为我工作的方式。如果你需要一些例如要求它,我会发布一些东西。
要跟进@MrSnowflake答案与一个代码示例。
这是XABBER现在开源Application
类。该Application
类是集中和协调Listeners
和ManagerInterfaces多。各种管理动态加载。 Activity´s
在Xabber开始将它们是什么类型的Listener
的报告。而当Service
启动它报告给Application
类作为开始。现在将消息发送到Activity
所有你需要做的就是让你的Activity
成为你需要什么类型listener
。在OnStart()
OnPause()
寄存器/ UNREG。该Service
可以要求Application
类只是listener
它需要跟,如果它的存在,则活动已准备好接收。
通过Application
类,你会看到有一个战利品更多事情,然后这是怎么回事。
我的方法:
类来管理发送和接收来自/到服务/活动接收消息:
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 java.util.ArrayList;
import java.util.List;
public class MessageManager {
public interface IOnHandleMessage{
// Messages
int MSG_HANDSHAKE = 0x1;
void onHandleMessage(Message msg);
}
private static final String LOGCAT = MessageManager.class.getSimpleName();
private Messenger mMsgSender;
private Messenger mMsgReceiver;
private List<Message> mMessages;
public MessageManager(IOnHandleMessage callback, IBinder target){
mMsgReceiver = new Messenger(new MessageHandler(callback, MessageHandler.TYPE_ACTIVITY));
mMsgSender = new Messenger(target);
mMessages = new ArrayList<>();
}
public MessageManager(IOnHandleMessage callback){
mMsgReceiver = new Messenger(new MessageHandler(callback, MessageHandler.TYPE_SERVICE));
mMsgSender = null;
mMessages = new ArrayList<>();
}
/* START Getter & Setter Methods */
public Messenger getMsgSender() {
return mMsgSender;
}
public void setMsgSender(Messenger sender) {
this.mMsgSender = sender;
}
public Messenger getMsgReceiver() {
return mMsgReceiver;
}
public void setMsgReceiver(Messenger receiver) {
this.mMsgReceiver = receiver;
}
public List<Message> getLastMessages() {
return mMessages;
}
public void addMessage(Message message) {
this.mMessages.add(message);
}
/* END Getter & Setter Methods */
/* START Public Methods */
public void sendMessage(int what, int arg1, int arg2, Bundle msgData){
if(mMsgSender != null && mMsgReceiver != null) {
try {
Message msg = Message.obtain(null, what, arg1, arg2);
msg.replyTo = mMsgReceiver;
if(msgData != null){
msg.setData(msgData);
}
mMsgSender.send(msg);
} catch (RemoteException rE) {
onException(rE);
}
}
}
public void sendHandshake(){
if(mMsgSender != null && mMsgReceiver != null){
sendMessage(IOnHandleMessage.MSG_HANDSHAKE, 0, 0, null);
}
}
/* END Public Methods */
/* START Private Methods */
private void onException(Exception e){
Log.e(LOGCAT, e.getMessage());
e.printStackTrace();
}
/* END Private Methods */
/** START Private Classes **/
private class MessageHandler extends Handler {
// Types
final static int TYPE_SERVICE = 0x1;
final static int TYPE_ACTIVITY = 0x2;
private IOnHandleMessage mCallback;
private int mType;
public MessageHandler(IOnHandleMessage callback, int type){
mCallback = callback;
mType = type;
}
@Override
public void handleMessage(Message msg){
addMessage(msg);
switch(msg.what){
case IOnHandleMessage.MSG_HANDSHAKE:
switch(mType){
case TYPE_SERVICE:
setMsgSender(msg.replyTo);
sendHandshake();
break;
case TYPE_ACTIVITY:
Log.v(LOGCAT, "HERE");
break;
}
break;
default:
if(mCallback != null){
mCallback.onHandleMessage(msg);
}
break;
}
}
}
/** END Private Classes **/
}
在活性实施例:
public class activity extends AppCompatActivity
implements ServiceConnection,
MessageManager.IOnHandleMessage {
[....]
private MessageManager mMessenger;
private void initMyMessenger(IBinder iBinder){
mMessenger = new MessageManager(this, iBinder);
mMessenger.sendHandshake();
}
private void bindToService(){
Intent intent = new Intent(this, TagScanService.class);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
/* START THE SERVICE IF NEEDED */
}
private void unbindToService(){
/* UNBIND when you want (onDestroy, after operation...)
if(mBound) {
unbindService(mServiceConnection);
mBound = false;
}
}
/* START Override MessageManager.IOnHandleMessage Methods */
@Override
public void onHandleMessage(Message msg) {
switch(msg.what){
case Constants.MSG_SYNC_PROGRESS:
Bundle data = msg.getData();
String text = data.getString(Constants.KEY_MSG_TEXT);
setMessageProgress(text);
break;
case Constants.MSG_START_SYNC:
onStartSync();
break;
case Constants.MSG_END_SYNC:
onEndSync(msg.arg1 == Constants.ARG1_SUCCESS);
mBound = false;
break;
}
}
/* END Override MessageManager.IOnHandleMessage Methods */
/** START Override ServiceConnection Methods **/
private class BLEScanServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
initMyMessenger(iBinder);
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mMessenger = null;
mBound = false;
}
}
/** END Override ServiceConnection Methods **/
在服务示例:
public class Blablabla extends Service
implements MessageManager.IOnHandleMessage {
[...]
private MessageManager mMessenger;
@Nullable
@Override
public IBinder onBind(Intent intent) {
super.onBind(intent);
initMessageManager();
return mMessenger.getMsgReceiver().getBinder();
}
private void initMessageManager(){
mMessenger = new MessageManager(this);
}
/* START Override IOnHandleMessage Methods */
@Override
public void onHandleMessage(Message msg) {
/* Do what you want when u get a message looking the "what" attribute */
}
/* END Override IOnHandleMessage Methods */
从活动/服务发送消息:
mMessenger.sendMessage(what, arg1, arg2, dataBundle);
这是如何工作:
上的活动启动或绑定的服务。 服务“OnBind”方法通过“服务连接”接口方法的实现返回粘结剂他给messageManager,中活动“OnServiceConnected”你得到这个的IBinder,并用它初始化你给messageManager。 该活动已初始化他给messageManager后MessageHandler的发送和握手的服务,因此它可以设置自己的“的MessageHandler”发送者(以下简称“私人信使mMsgSender,”在给messageManager)。这样做的服务知道谁送他的消息。
您也可以实现这在给messageManager使用列表/队列使者的“寄件人”这样你就可以发送多条消息,以不同的活动/服务,或者你可以在给messageManager所以你用一个列表/队列使者的“接收器”可以从不同的活动/服务接收多个消息。
在“给messageManager”实例你有接收的所有消息的列表。
正如可以看到“活动的信使”和“服务信使”使用该“给messageManager”实例是自动的,它是通过“OnServiceConnected”方法,并通过使用“握手”的完成之间的连接。
希望这是对你有帮助:)非常感谢你! 再见:d
结合是另一个沟通方式
创建一个回调
public interface MyCallBack{
public void getResult(String result);
}
活动的侧:
- 实现接口的活动
- 提供执行的方法
- 绑定的活动以服务
注册并取消注册的回调当的服务得到的约束,并未与 的活动。
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 ); } }
服务面:
- 回初始化
调用回调的方法,只要需要
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; } }
正如Madhur提到的,可以使用总线来进行通信。
在使用总线的情况下,你有一些选择:
奥托事件总线库(淘汰,RxJava的)
绿色机器人的EventBus
http://greenrobot.org/eventbus/
NYBus(RxBus,使用RxJava。非常类似于EventBus实现)
除了 LocalBroadcastManager,事件总线和Messenger 在这个问题已经回答了,我们可以使用待意图从服务进行通信。
如前所述这里在我的博客文章
服务和活动之间的通信可以使用进行 PendingIntent.For,我们可以使用 的 createPendingResult 强>()。createPendingResult()创建一个新的 的PendingIntent对象,它可以用手来服务使用,并送 里面onActivityResult(INT,INT结果数据返回到您的活动, 意图)callback.Since一个的PendingIntent是Parcelable,并能 因此投入的额外意图,你的活动可以通过这个 的PendingIntent到的服务。服务,反过来,可以调用send() 上的PendingIntent方法经由通知活动 onActivityResult事件的
活动
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); } }
服务
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); } } } } }