绑定/解绑服务示例(Android)

63

你能给我一个使用绑定/解绑方法启动和停止其后台服务的简单示例应用程序吗?我在谷歌上搜了半个小时,但那些示例都使用startService / stopService方法或太难理解了。谢谢。


你可以在以下线程中了解这个问题:https://dev59.com/bnI-5IYBdhLWcg3wTWn4 - Dawid Sajdak
2
是的,我已经读了三遍,但是很抱歉 - 我还是不明白。我需要一个包含主活动和服务活动的示例。 - user1049280
3个回答

63

你可以尝试使用这段代码:

protected ServiceConnection mServerConn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder binder) {
        Log.d(LOG_TAG, "onServiceConnected");
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.d(LOG_TAG, "onServiceDisconnected");
    }
}

public void start() {
    // mContext is defined upper in code, I think it is not necessary to explain what is it 
    mContext.bindService(intent, mServerConn, Context.BIND_AUTO_CREATE);
    mContext.startService(intent);
}

public void stop() {
    mContext.stopService(new Intent(mContext, ServiceRemote.class));
    mContext.unbindService(mServerConn);
}

8
请告诉我,变量 i 是什么意思? - user1049280
我创建了一个新的Intent,就像这样:new Intent(this, YourService.class)。 - Dawid Sajdak
谢谢你的回复,Dawid。你能看一下这个链接吗:http://stackoverflow.com/questions/8341782/good-practise-for-services-on-android。我遇到了一个关于服务和高级服务生命周期管理的问题,但是还没有得到答案。:'( - Camille R
1
我怀疑上面的答案是匆忙写成的。要查看绑定Service的完整示例和详细说明,请参见这里 - ChuongPham
您应该记住,如果活动因内存不足而被杀死,onStop()可能不会被调用。 - dephinera
显示剩余2条评论

47
请将以下文本翻译为中文:

Add these methods to your Activity:

将以下方法添加到你的Activity中:
private MyService myServiceBinder;
public ServiceConnection myConnection = new ServiceConnection() {

    public void onServiceConnected(ComponentName className, IBinder binder) {
        myServiceBinder = ((MyService.MyBinder) binder).getService();
        Log.d("ServiceConnection","connected");
        showServiceData();
    }

    public void onServiceDisconnected(ComponentName className) {
        Log.d("ServiceConnection","disconnected");
        myService = null;
    }
};

public Handler myHandler = new Handler() {
    public void handleMessage(Message message) {
        Bundle data = message.getData();
    }
};

public void doBindService() {
    Intent intent = null;
    intent = new Intent(this, BTService.class);
    // Create a new Messenger for the communication back
    // From the Service to the Activity
    Messenger messenger = new Messenger(myHandler);
    intent.putExtra("MESSENGER", messenger);

    bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
}

你可以通过覆盖你的 Activity 类中的 onResume()onPause() 方法来绑定服务。

@Override
protected void onResume() {

    Log.d("activity", "onResume");
    if (myService == null) {
        doBindService();
    }
    super.onResume();
}

@Override
protected void onPause() {
    //FIXME put back

    Log.d("activity", "onPause");
    if (myService != null) {
        unbindService(myConnection);
        myService = null;
    }
    super.onPause();
}

请注意,当绑定到服务时,服务类中仅调用onCreate()方法。在您的服务类中,您需要定义myBinder方法:

private final IBinder mBinder = new MyBinder();
private Messenger outMessenger;

@Override
public IBinder onBind(Intent arg0) {
    Bundle extras = arg0.getExtras();
    Log.d("service","onBind");
    // Get messager from the Activity
    if (extras != null) {
        Log.d("service","onBind with extra");
        outMessenger = (Messenger) extras.get("MESSENGER");
    }
    return mBinder;
}

public class MyBinder extends Binder {
    MyService getService() {
        return MyService.this;
    }
}
在定义这些方法之后,您可以在Activity中访问您的服务的方法。
private void showServiceData() {  
    myServiceBinder.myMethod();
}

最后,当某个事件发生时,比如“_BOOT_COMPLETED_”,您可以启动服务。

public class MyReciever  extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equals("android.intent.action.BOOT_COMPLETED")) {
            Intent service = new Intent(context, myService.class);
            context.startService(service);
        }
    }
}

请注意,在启动服务时,onCreate()onStartCommand()会在服务类中被调用,您可以使用stopService()在发生其他事件时停止服务。

请注意,您的事件监听器应在Android清单文件中注册:

<receiver android:name="MyReciever" android:enabled="true" android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
</receiver>

1
@Hib 为什么在暂停/恢复时解除绑定?Google文档链接强烈反对这种做法。他们建议使用启动/停止方式。 - hannunehg
@hannunehg 当我写这个答案时,start stop 不存在 - 请编辑我的答案,否则我稍后会进行编辑。 - laplasz
1
非常好的答案 - 至今仍然有用 - Someone Somewhere
发送消息到处理程序之前,我需要检查该活动是否仍然可用吗? - Maor Hadad

17

首先,有两件事情我们需要理解:

客户端

  • 它向特定的服务器发送请求

bindService(new Intent("com.android.vending.billing.InAppBillingService.BIND"), mServiceConn, Context.BIND_AUTO_CREATE);

这里的mServiceConnServiceConnection类(内置)的实例,它实际上是一个接口, 我们需要实现其中的两个方法(第一个用于网络已连接状态,第二个用于网络未连接状态)来监视网络连接状态。

服务器

  • 它处理客户端的请求,并制作自己的副本,仅对发送请求的客户端私有,此服务器副本在不同线程上运行。

现在,在客户端如何访问服务器的所有方法?

  • 服务器使用IBinder对象发送响应。因此,IBinder对象是我们的处理程序,通过使用(.)运算符访问Service的所有方法。

.

MyService myService;
public ServiceConnection myConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder binder) {
        Log.d("ServiceConnection","connected");
        myService = binder;
    }
    //binder comes from server to communicate with method's of 

    public void onServiceDisconnected(ComponentName className) {
        Log.d("ServiceConnection","disconnected");
        myService = null;
    }
}

现在如何调用位于服务中的方法

myservice.serviceMethod();

这里myService是对象,而serviceMethod是服务中的方法。 通过这种方式建立了客户端和服务器之间的通信。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接