`

BIND_AUTO_CREATE的问题

阅读更多

先看下面两段非常简单的代码,功能是通过一个Activity启动并绑定一个本地服务,然后马上调用停止服务

 

MainActivity.java

package com.example.servicetest2;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;

public class MainActivity extends ActionBarActivity {

    private static final String LOG_TAG = "MainActivity";

    private ServiceConnection conn = new TestConnection();

    private Intent i;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        i = new Intent(this, TestService.class);
        startService(i);// 新建服务
        bindService(i, conn, 0);// 该Activity bind到该服务,0表示不新建服务
    }

    protected void onConnected() {
        stopService(i);// bind到服务后,马上stop掉
    }

    private class TestConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(final ComponentName name, final IBinder service) {
            Log.d(LOG_TAG, "onServiceConnected");
            onConnected();
        }

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

    }

}

 

TestService.java

package com.example.servicetest2;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class TestService extends Service {

    private static final String LOG_TAG = "TestService";

    @Override
    public void onCreate() {
        Log.d(LOG_TAG, "onCreate");
    }

    @Override
    public IBinder onBind(final Intent intent) {
        Log.d(LOG_TAG, "onBind");
        return new TestBinder();
    }

    @Override
    public boolean onUnbind(final Intent intent) {
        Log.d(LOG_TAG, "onUnbind");
        return false;
    }

    @Override
    public void onDestroy() {
        Log.d(LOG_TAG, "onDestroy");
    }

    public static class TestBinder extends Binder {}

}

 

按照安卓官方文档(http://developer.android.com/guide/components/services.htmlhttp://developer.android.com/guide/components/bound-services.html)的说法,如果一个服务既被startService启动又被其他组件bind到,那么调用stopService时该服务不会被销毁,直到所有的client都unbind。事实是否如此呢?上述代码执行结果如下:

 

11-14 22:18:17.507: D/TestService(2481): onCreate
11-14 22:18:17.527: D/TestService(2481): onBind
11-14 22:18:17.547: D/MainActivity(2481): onServiceConnected
11-14 22:18:17.607: D/MainActivity(2481): onServiceDisconnected
11-14 22:18:17.607: D/TestService(2481): onUnbind
11-14 22:18:17.607: D/TestService(2481): onDestroy

 

可以看到虽然在代码中并未unbind该服务,但当调用stopService时服务马上就被销毁,而且触发了onServiceDisconnected回调,明显和官方文档以及网上各种说法不一致。为什么会这样呢?去翻关闭服务的源代码:

 

ActivityManagerService.java

 

private final void bringDownServiceLocked(final ServiceRecord r, final boolean force) {
        // Slog.i(TAG, "Bring down service:");
        // r.dump(" ");
        // Does it still need to run?
        if (!force &&
            r.startRequested) {// 检查stopService或stopSelf是否被调用
            return;
        }
        if (r.connections.size() > 0) {
            if (!force) {
                // XXX should probably keep a count of the number of auto-create
                // connections directly in the service.
                final Iterator<ArrayList<ConnectionRecord>> it = r.connections.values().iterator();
                while (it.hasNext()) {// 遍历所有绑定到服务的连接记录
                    final ArrayList<ConnectionRecord> cr = it.next();
                    for (int i = 0; i < cr.size(); i++) {
                        if ((cr.get(i).flags & Context.BIND_AUTO_CREATE) != 0) {// 检查连接是否设置了BIND_AUTO_CREATE
                            return;// 如果存在设置了BIND_AUTO_CREATE的连接,那么就不销毁服务直接返回
                        }
                    }
                }
            }
            // Report to all of the connections that the service is no longer
            // available.
            final Iterator<ArrayList<ConnectionRecord>> it = r.connections.values().iterator();
            while (it.hasNext()) {
                final ArrayList<ConnectionRecord> c = it.next();
                for (int i = 0; i < c.size(); i++) {
                    final ConnectionRecord cr = c.get(i);
                    // There is still a connection to the service that is
                    // being brought down. Mark it as dead.
                    cr.serviceDead = true;
                    try {
                        cr.conn.connected(r.name, null);// 回调ServiceConnection.onServiceDisconnected
                    } catch (final Exception e) {
                        Slog.w(TAG, "Failure disconnecting service " +
                                    r.name +
                                    " to connection " + c.get(i).conn.asBinder() +
                                    " (in " + c.get(i).binding.client.processName + ")", e);
                    }
                }
            }

        }

        // ...
        // 销毁服务
    }
 

 

ActivityManagerService.bringDownServiceLocked方法负责销毁服务,无论stopService或unbindService最终都可能会调用该方法。可以从代码中看到,在真正销毁服务前,会检查和该服务绑定的连接信息(调用该次unbindService的连接在前面已经被过滤掉),如果扔有设置过BIND_AUTO_CREATE的链接存在,就不进行销毁。换句话说,一个BoundService是否被销毁,取决于当前带有BIND_AUTO_CREATE标志的连接数目,不带有BIND_AUTO_CREATE标志的连接会在服务销毁前收到onServiceDisconnected回调。

 

个人认为,销毁服务的代码实现逻辑和开发设想是有出入的,本应该有特殊的标志位决定是否在有client绑定的情况下销毁服务而不是简单粗暴的“重用”BIND_AUTO_CREATE标志。不过BIND_AUTO_CREATE和startService同时使用并无副作用(同名服务在安卓里头是单例),我们可以根据业务需求灵活设置bindService方法的flags参数。比如一个多client连接的短时间执行的共享服务,当client指定bindService的flags为0时,服务在执行完毕可以及时stopSelf销毁,而不需要等待client unbind,可以有效的节省资源。

分享到:
评论

相关推荐

    方式二:Context.bindService()源码

    bindService(serviceIntent, serviceConnection, BIND_AUTO_CREATE); ``` **步骤4**:解绑服务 当不再需要服务时,必须调用`unbindService()`来释放资源。 ```java unbindService(serviceConnection); ``` ### 3....

    Classes.rar

    tolua_function(tolua_S,"create",tolua_bind_MyClass_create); tolua_function(tolua_S,"myMethod",tolua_bind_MyClass_myMethod); #ifdef __cplusplus } #endif ``` 这里`tolua_bind_MyClass_create`和`...

    绑定本地和远程Service的Demo.zip

    bindService(intent, connection, BIND_AUTO_CREATE); // 创建ServiceConnection ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, ...

    Android代码-Android

    Services App : Creating and Managing the lifecycle of android services using Context.BIND_AUTO_CREATE. Sensor App : The purpose of this app is to work with Android Sensors (Timer and Camera). Torch ...

    Android编程实现设置TabHost当中字体的方法

    本文实例讲述了Android编程设置TabHost当中字体的方法。分享给大家供大家参考,具体如下: TabWidget tw=this.getTabWidget();//设置TabHost当中的... tv.setGravity(BIND_AUTO_CREATE); tv.setPadding(10, 10, 10

    Android 绑定service小demo

    `BIND_AUTO_CREATE` 是一个标志位,告诉系统在需要时自动创建服务。`onServiceConnected()` 方法会在服务绑定成功后被调用,此时我们可以通过 `service` 参数访问服务的 `Binder` 对象,并调用其方法。当不再需要...

    绑定服务调用服务里的方法

    这里,`YourService.class`是你自定义的服务类,`connection`是一个实现了`ServiceConnection`接口的对象,`BIND_AUTO_CREATE`是常量,表示服务在绑定时自动创建。 ### 3. 实现`ServiceConnection` `...

    Android 的 Remote Service 开发实例RemoteService

    - `BIND_AUTO_CREATE`:绑定时自动创建服务。 - `BIND_ADJUST_WITH_ACTIVITY`:与Activity的生命周期同步。 五、安全性考虑 由于Remote Service允许其他应用访问,因此需要考虑权限控制。在`AndroidManifest.xml`...

    service和acivity之间通信

    `BIND_AUTO_CREATE`是一个标志,告诉系统在连接服务时自动创建它。当`onServiceConnected()`被调用时,说明`Activity`已经成功连接到`Service`,此时可以通过`MyBinder`对象调用`Service`的方法。 **解绑`Service`*...

    利用Bind DLZ MySQL 构建智能DNS V2

    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, domain VARCHAR(255) NOT NULL, ip_address VARCHAR(15) NOT NULL, view_type VARCHAR(20) NOT NULL ); ``` - 插入DNS记录: ```sql INSERT INTO records ...

    AIDLDemo的代码示例

    bindService(intent, connection, BIND_AUTO_CREATE); ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { ...

    使用AIDL实现进程间通讯简单案例

    IBinder binder = bindService(new Intent(this, AidlService.class), connection, Context.BIND_AUTO_CREATE); IAidlService service = IAidlService.Stub.asInterface(binder); service.sendData("Hello from ...

    android AIDL简介

    bindService(intent, mConnection, Context.BIND_AUTO_CREATE); private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder ...

    android开发使用aidl进行跨进程通信demo

    bindService(intent, connection, Context.BIND_AUTO_CREATE); ``` 然后,我们需要创建一个`ServiceConnection`,在连接成功后,我们可以获取到`IAidlService`的实例: ```java private ServiceConnection ...

    android 绑定服务客户端

    bindService(intent, connection, Context.BIND_AUTO_CREATE); private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder ...

    AIDL进程间通信

    bindService(new Intent(this, ArithmeticService.class), connection, BIND_AUTO_CREATE); } private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected...

    Android应用程序的Life Cycle

    例如,当进程 A 使用 Context.BIND_AUTO_CREATE 标记绑定了一个 Service 或者在 B 进程中使用一个 ContentProvider 时,那么 B 进程的重要级别不会低于 A 进程的级别。 了解 Android 应用程序的生命周期是非常重要...

    简单计算器

    bindService(serviceIntent,mConnection,Context.BIND_AUTO_CREATE); System.out.println("123565"); System.out.println("qwwq"); System.out.println("www"); System.out.println("123ww565"); System...

    Android Service Demo

    bindService(intent, connection, BIND_AUTO_CREATE); ``` 其中,`connection`是一个实现了`ServiceConnection`接口的对象,用于处理服务连接的状态变化。 服务的生命周期管理是非常重要的,因为它可以影响到设备...

    安卓高版本AIDL的使用

    bindService(intent, conn, BIND_AUTO_CREATE); ``` 在使用 AIDL 的过程中,需要注意权限问题,在 AndroidManifest.xml 文件中,需要添加相关权限,以便允许应用程序之间的通信。 三、AIDL 的优缺点 AIDL 是一种...

Global site tag (gtag.js) - Google Analytics