service

服务 Service 清单文件中可设置的属性:

<service 	
	android:enabled=["true" | "false"]  
	//是否这个service能被系统实例化,如果能则为true,否则为false。默认为true。
	android:exported=["true" | "false"]
	//是否其它应用组件能调用这个service或同它交互,能为true,默认值依赖于是否包含过滤器。
	android:icon="drawable resource"
	//服务呈现的图标。
	android:isolatedProcess=["true" | "false"]
	//如果设置为true,这个服务将运行在专门的进程中
	android:label="string resource"
	//这个服务给用户显示的名称。
	android:name="string"
	//实现这个service的Service子类名称。
	android:permission="string"
	//为了启动这个service或绑定到它一个实体必须要有的权限的名称。
	android:process="string"  
	//服务将要运行的进程名称。
	//当设置为android:process=”:remote”时,代表Service在单独的进程中运行。
	//注意“:”很重要,它的意思是指要在当前进程名称前面附加上当前的包名,
	//所以“remote”和”:remote”不是同一个意思,
	//前者的进程名称为:remote,而后者的进程名称为:App-packageName:remote。
/>

Activity与Service交互的三种方式:

1)startService的方式与Service交互:广播

Activity是不能很直接的与Service进行交互,需要借助与其它组件来完成。常见的就是利用广播接收器。Service发送广播,Activity接受广播。

通过广播实现Activity和Service的交互简单容易实现,缺点是发送不广播受系统制约,系统会优先发送系统级的广播,自定义的广播接收器可能会有延迟,在广播里也不能有耗时操作,否则会导致程序无响应(ANR)。

2)bindService的方式与Service交互:IBinder

需要在Service中准备一个IBinder接口的实现类。将该实现类的对象作为onBind方法的返回值
在Activity中需要一个ServiceConnection对象,他会有两个回调方法,在其中一个方法中获得Service内onBind方法返回的IBinder对象。通过IBinder 来实现与Service的交互。

3)AIDL的方式与Service交互(不常用)

Bind方式进行交互是有前提的,Activity和Service是出于同一个app中(同一个进程中)
通过AIDL可以实现跨进程的调用,一个APPA的Activity可以调用另一个APP的Service的方法
进行AIDL跨进程调用调用,必须使用Service的一个.aidl描述文件才可以进行

原理:
AIDL属于Android的IPC机制,常用于跨进程通信,主要实现原理基于底层Binder机制。
优缺点分析:
AIDL在Android中是进程间通信常用的方式,可能使用较為复杂,但效率高,扩展性好。同时很多系统服务就是以这种方式完成与应用程序通信的。

参考:与Service交互的三种方式

4)共享文件:SharedPreferences

使用SharedPreferences进行数据共享对文件格式没有要求,只要读写双方约定好数据格式即可。但是也有局限性,在面对高并发的读写时,这种方式就变得不可靠,很可能会导致读写的数据不一致,所以不建议使用这种方式来进行通信

Service概念的总结:

(1)Service在后台运行,不可以与用户直接交互;
(2)一个服务不是一个单独的进程。服务对象本身并不意味着它是在自己的进程中运行,除非另有规定,否则它与运行程序是同在一个进程中;
(3)一个服务不是一个单独的线程。Service和其他组件一样,默认情况下,Service中的所有代码都是运行在主线程中;
(4)Service存在的价值虽然不如Activity那么清晰。但是一般都让Service执行耗时较长的操作。例如:播放音乐、下载文件、上传文件等等。但是因为Service默认运行在主线程中,因此不能直接用它来做耗时的请求或者动作,最好在Service中启动新线程来运行耗时的任务;
(5)需要通过某一个Activity或其他Context对象来启动Service。context.startService() 或 context.bindService();
(6)Service很大程度上充当了应用程序后台线程管理器的角色。(如果Activity中新开启一个线程,当该Acitivyt关闭后,该线程依然在工作,但是与开启它的Activity失去联系。也就是说此时的这个线程处于失去管理的状态。但是使用Service,则可以对后台运行的线程有效地管理。)

为什么不使用后台线程而使用Service?

1、Service可以放在独立的进程中,所以更安全;
2、使用Service可以依赖现有的binder机制,不需要在应用层面上处理线程同步的繁杂工作;
3、系统可以重新启动异常死去的Service。

Service 与 Activity 的相同点与不同点:

不同点:Activity是与用户交互的组件,即可以看到UI界面,而Service是在后台运行、无需界面;
相同点:使用Activity 时我们需要在配置文件中声明标签,同样的使用Service 也需要在配置文件中声明标签。都具有一定的生命周期。

使用方式

  • startService 启动的服务 主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService
  • bindService 启动的服务 该方法启动的服务要进行通信。停止服务使用unbindService
  • startService 同时也 bindService 启动的服务, 停止服务应同时使用stopService与unbindService

生命周期:

生命周期

Service启动服务

1、创建 Service 的子类(或使用它的一个现有子类如IntentService)。在实现中,我们需要重写一些回调方法,以处理服务生命周期的某些关键过程.

/**
 * 创建服务,必须创建 Service 的子类(或使用它的一个现有子类如IntentService)。
 * 在实现中,我们需要重写一些回调方法,以处理服务生命周期的某些关键过程
 * Created by xuqiang on 2017/1/13 10:53.
 */
public class SimpleService extends Service {

    /**
     * 绑定服务时才会调用
     * 无论是启动状态还是绑定状态,此方法必须重写,但在启动状态的情况下直接返回 null。
     * 只有在绑定状态的情况下才需要实现该方法并返回一个IBinder的实现类
     *
     * @param intent
     * @return
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * 首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。
     * 如果服务已在运行,则不会调用此方法。该方法只被调用一次
     */
    @Override
    public void onCreate() {
        System.out.println("onCreate invoke");
        super.onCreate();
    }

    /**
     * 每次通过startService()方法启动Service时都会被回调。
     * 当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。
     * 一旦执行此方法,服务即会启动并可在后台无限期运行。 如果自己实现此方法,
     * 则需要在服务工作完成后,通过调用 stopSelf() 或 stopService() 来停止服务。
     * (在绑定状态下,无需实现此方法。)
     *
     * @param intent
     * @param flags
     * @param startId
     * @return
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("onStartCommand invoke");
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 服务销毁时的回调
     * 当服务不再使用且将被销毁时,系统将调用此方法。
     * 服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等,这是服务接收的最后一个调用。
     */
    @Override
    public void onDestroy() {
        System.out.println("onDestroy invoke");
        super.onDestroy();
    }


}

2、清单配置文件中声明Service(声明方式跟Activity相似):

<manifest ... >
  ...
  <application ... >
      <service android:name=".service.SimpleService" />
      ...
  </application>
</manifest>

3、启动或停止服务的测试

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button startBtn;
    private Button stopBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startBtn= (Button) findViewById(R.id.startService);
        stopBtn= (Button) findViewById(R.id.stopService);
        startBtn.setOnClickListener(this);
        assert stopBtn != null;
        stopBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Intent it=new Intent(this, SimpleService.class);
        switch (v.getId()){
            case R.id.startService:
                startService(it);
                break;
            case R.id.stopService:
                stopService(it);
                break;
        }
    }
}

从代码看出,启动服务使用startService(Intent intent)方法,仅需要传递一个Intent对象即可,在Intent对象中指定需要启动的服务。而使用startService()方法启动的服务,在服务的外部,必须使用stopService()方法停止,在服务的内部可以调用stopSelf()方法停止当前服务。如果使用startService()或者stopSelf()方法请求停止服务,系统会就会尽快销毁这个服务。值得注意的是对于启动服务,一旦启动将与访问它的组件无任何关联,即使访问它的组件被销毁了,这个服务也一直运行下去,直到手动调用停止服务才被销毁.
我们运行程序并多次调用startService方法,最后调用stopService方法。Log截图如下:
startservice
从Log可以看出,第一次调用startService方法时,onCreate方法、onStartCommand方法将依次被调用,而多次调用startService时,只有onStartCommand方法被调用,最后我们调用stopService方法停止服务时onDestory方法被回调,这就是启动状态下Service的执行周期。

Service绑定服务

绑定服务是Service的另一种变形,当Service处于绑定状态时,其代表着客户端-服务器接口中的服务器。当其他组件(如 Activity)绑定到服务时(有时我们可能需要从Activity组建中去调用Service中的方法,此时Activity以绑定的方式挂靠到Service后,我们就可以轻松地方法到Service中的指定方法),组件(如Activity)可以向Service(也就是服务端)发送请求,或者调用Service(服务端)的方法,此时被绑定的Service(服务端)会接收信息并响应,甚至可以通过绑定服务进行执行进程间通信 (即IPC,这个后面再单独分析)。与启动服务不同的是绑定服务的生命周期通常只在为其他应用组件(如Activity)服务时处于活动状态,不会无限期在后台运行,也就是说宿主(如Activity)解除绑定后,绑定服务就会被销毁。那么在提供绑定的服务时,该如何实现呢?实际上我们必须提供一个 IBinder接口的实现类,该类用以提供客户端用来与服务进行交互的编程接口,该接口可以通过三种方法定义接口:

  • 扩展 Binder 类

如果服务是提供给自有应用专用的,并且Service(服务端)与客户端相同的进程中运行(常见情况),则应通过扩展 Binder 类并从 onBind() 返回它的一个实例来创建接口。客户端收到 Binder 后,可利用它直接访问 Binder 实现中以及Service 中可用的公共方法。如果我们的服务只是自有应用的后台工作线程,则优先采用这种方法。 不采用该方式创建接口的唯一原因是,服务被其他应用或不同的进程调用。

  • 使用 Messenger

Messenger可以翻译为信使,通过它可以在不同的进程中共传递Message对象(Handler中的Messager,因此 Handler 是 Messenger 的基础),在Message中可以存放我们需要传递的数据,然后在进程间传递。如果需要让接口跨不同的进程工作,则可使用 Messenger 为服务创建接口,客户端就可利用 Message 对象向服务发送命令。同时客户端也可定义自有 Messenger,以便服务回传消息。这是执行进程间通信 (IPC) 的最简单方法,因为 Messenger 会在单一线程中创建包含所有请求的队列,也就是说Messenger是以串行的方式处理客户端发来的消息,这样我们就不必对服务进行线程安全设计了。

  • 使用 AIDL

由于Messenger是以串行的方式处理客户端发来的消息,如果当前有大量消息同时发送到Service(服务端),Service仍然只能一个个处理,这也就是Messenger跨进程通信的缺点了,因此如果有大量并发请求,Messenger就会显得力不从心了,这时AIDL(Android 接口定义语言)就派上用场了, 但实际上Messenger 的跨进程方式其底层实现 就是AIDL,只不过android系统帮我们封装成透明的Messenger罢了 。因此,如果我们想让服务同时处理多个请求,则应该使用 AIDL。 在此情况下,服务必须具备多线程处理能力,并采用线程安全式设计。使用AIDL必须创建一个定义编程接口的 .aidl 文件。Android SDK 工具利用该文件生成一个实现接口并处理 IPC 的抽象类,随后可在服务内对其进行扩展。
  
  以上3种实现方式,我们可以根据需求自由的选择,但需要注意的是大多数应用“都不会”使用 AIDL 来创建绑定服务,因为它可能要求具备多线程处理能力,并可能导致实现的复杂性增加。因此,AIDL 并不适合大多数应用,本篇中也不打算阐述如何使用AIDL(后面会另开一篇分析AIDL),接下来我们分别针对扩展 Binder 类和Messenger的使用进行分析。

扩展 Binder 类

1、注册
在清单配置文件中声明Service(声明方式跟Activity相似):

<manifest ... >
  ...
  <application ... >
      <service android:name=".service.LocalService" />
      ...
  </application>
</manifest>

2、创建service服务端

/**
 * 如果我们的服务仅供本地应用使用,不需要跨进程工作,则可以实现自有 Binder 类,让客户端通过该类直接访问服务中的公共方法。
 * 其使用开发步骤如下
 * 1.创建BindService服务端,继承自Service并在类中,创建一个实现IBinder 接口的实例对象并提供公共方法给客户端调用
 * 2.从 onBind() 回调方法返回此 Binder 实例。
 * 3.在客户端中,从 onServiceConnected() 回调方法接收 Binder,并使用提供的方法调用绑定服务。
 *
 * 注意:此方式只有在客户端和服务位于同一应用和进程内才有效,如对于需要将 Activity 绑定到在后台播放音乐的自有服务的音乐应用,
 * 此方式非常有效。另一点之所以要求服务和客户端必须在同一应用内,是为了便于客户端转换返回的对象和正确调用其 API。
 * 服务和客户端还必须在同一进程内,因为此方式不执行任何跨进程编组。
 * Created by xuqiang on 2017/1/13 11:11.
 */
public class LocalService extends Service {

    private final static String TAG = "wzj";
    private int count;
    private boolean quit;
    private Thread thread;
    private LocalBinder binder = new LocalBinder();

    /**
     * 创建Binder对象,返回给客户端即Activity使用,提供数据交换的接口
     */
    public class LocalBinder extends Binder {
        // 声明一个方法,getService。(提供给客户端调用)
        LocalService getService() {
            // 返回当前对象LocalService,这样我们就可在客户端端调用Service的公共方法了
            return LocalService.this;
        }
    }

    /**
     * 把Binder类返回给客户端
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }


    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "Service is invoke Created");
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                // 每间隔一秒count加1 ,直到quit为true。
                while (!quit) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count++;
                }
            }
        });
        thread.start();
    }

    /**
     * 公共方法
     *
     * @return
     */
    public int getCount() {
        return count;
    }

    /**
     * 解除绑定时调用
     *
     * @return
     */
    @Override
    public boolean onUnbind(Intent intent) {
        Log.i(TAG, "Service is invoke onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        Log.i(TAG, "Service is invoke Destroyed");
        this.quit = true;
        super.onDestroy();
    }


}

3、创建客户端调用

public class BindActivity extends AppCompatActivity {

    protected static final String TAG = "wzj";
    Button btnBind;
    Button btnUnBind;
    Button btnGetDatas;
    /**
     * ServiceConnection代表与服务的连接,它只有两个方法,
     * onServiceConnected和onServiceDisconnected,
     * 前者是在操作者在连接一个服务成功时被调用,而后者是在服务崩溃或被杀死导致的连接中断时被调用
     */
    private ServiceConnection conn;
    private LocalService mService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bind);
        btnBind = (Button) findViewById(R.id.BindService);
        btnUnBind = (Button) findViewById(R.id.unBindService);
        btnGetDatas = (Button) findViewById(R.id.getServiceDatas);
        //创建绑定对象
        final Intent intent = new Intent(this, LocalService.class);

        // 开启绑定
        btnBind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "绑定调用:bindService");
                //调用绑定方法
                bindService(intent, conn, Service.BIND_AUTO_CREATE);
                //参数分别为
                //intent
                //ServiceConnection
                //flags则是指定绑定时是否自动创建Service。0代表不自动创建、BIND_AUTO_CREATE则代表自动创建。
            }
        });
        // 解除绑定
        btnUnBind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "解除绑定调用:unbindService");
                // 解除绑定
                if (mService != null) {
                    mService = null;
                    unbindService(conn);
                }
            }
        });

        // 获取数据
        btnGetDatas.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mService != null) {
                    // 通过绑定服务传递的Binder对象,获取Service暴露出来的数据

                    Log.d(TAG, "从服务端获取数据:" + mService.getCount());
                } else {

                    Log.d(TAG, "还没绑定呢,先绑定,无法从服务端获取数据");
                }
            }
        });


        conn = new ServiceConnection() {
            /**
             * 与服务器端交互的接口方法 绑定服务的时候被回调,在这个方法获取绑定Service传递过来的IBinder对象,
             * 通过这个IBinder对象,实现宿主和Service的交互。
             */
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.d(TAG, "绑定成功调用:onServiceConnected");
                // 获取Binder
                LocalService.LocalBinder binder = (LocalService.LocalBinder) service;
                mService = binder.getService();
            }

            /**
             * 当取消绑定的时候被回调。但正常情况下是不被调用的,它的调用时机是当Service服务被意外销毁时,
             * 例如内存的资源不足时这个方法才被自动调用。
             */
            @Override
            public void onServiceDisconnected(ComponentName name) {
                mService = null;
            }
        };
    }

}

我们运行程序,点击绑定服务并多次点击绑定服务接着多次调用LocalService中的getCount()获取数据,最后调用解除绑定的方法移除服务,其结果如下:
local

通过Log可知,当我们第一次点击绑定服务时,LocalService服务端的onCreate()、onBind方法会依次被调用,此时客户端的ServiceConnection#onServiceConnected()被调用并返回LocalBinder对象,接着调用LocalBinder#getService方法返回LocalService实例对象,此时客户端便持有了LocalService的实例对象,也就可以任意调用LocalService类中的声明公共方法了。更值得注意的是,我们多次调用bindService方法绑定LocalService服务端,而LocalService得onBind方法只调用了一次,那就是在第一次调用bindService时才会回调onBind方法。接着我们点击获取服务端的数据,从Log中看出我们点击了3次通过getCount()获取了服务端的3个不同数据,最后点击解除绑定,此时LocalService的onUnBind、onDestroy方法依次被回调,并且多次绑定只需一次解绑即可。此情景也就说明了绑定状态下的Service生命周期方法的调用依次为onCreate()、onBind、onUnBind、onDestroy。以上便是同一应用同一进程中客户端与服务端的绑定回调方式。

使用Messenger

前面了解了如何使用IBinder应用内同一进程的通信后,我们接着来了解服务与远程进程(即不同进程间)通信,而不同进程间的通信,最简单的方式就是使用 Messenger 服务提供通信接口,利用此方式,我们无需使用 AIDL 便可执行进程间通信 (IPC)。
1、注册

由于要测试不同进程的交互,则需要将Service放在单独的进程中,因此Service声明如下:

<service android:name=".messenger.MessengerService"
         android:process=":remote"
        />

其中android:process=":remote"代表该Service在单独的进程中创建
2、服务端

/**
 *  Messenger 使用的主要步骤:
 1.服务实现一个 Handler,由其接收来自客户端的每个调用的回调
 2.Handler 用于创建 Messenger 对象(对 Handler 的引用)
 3.Messenger 创建一个 IBinder,服务通过 onBind() 使其返回客户端
 4.客户端使用 IBinder 将 Messenger(引用服务的 Handler)实例化,然后使用Messenger将 Message 对象发送给服务
 5.服务在其 Handler 中(在 handleMessage() 方法中)接收每个 Message
 *
 * Created by xuqiang on 2017/1/13 11:28.
 */
public class MessengerService extends Service {


    /**
     * Command to the service to display a message
     */
    static final int MSG_SAY_HELLO = 1;
    private static final String TAG = "wzj";

    /**
     * 用于接收从客户端传递过来的数据
     */
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Log.i(TAG, "thanks,Service had receiver message from client!");
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * 创建Messenger并传入Handler实例对象
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    /**
     * 当绑定Service时,该方法被调用,将通过mMessenger返回一个实现
     * IBinder接口的实例对象
     */
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "Service is invoke onBind");
        return mMessenger.getBinder();
    }


}

3、客户端

/**
 * Created by xuqiang on 2017/1/13 11:30.
 */
public class ActivityMessenger extends AppCompatActivity {

    /**
     * 与服务端交互的Messenger
     */
    Messenger mService = null;

    /**
     * Flag indicating whether we have called bind on the service.
     */
    boolean mBound;

    /**
     * 实现与服务端链接的对象
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            /**
             * 通过服务端传递的IBinder对象,创建相应的Messenger
             * 通过该Messenger对象与服务端进行交互
             */
            mService = new Messenger(service);
            mBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mService = null;
            mBound = false;
        }
    };

    public void sayHello(View v) {
        if (!mBound) return;
        // 创建与服务交互的消息实体Message
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            //发送消息
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenager);
        Button bindService = (Button) findViewById(R.id.bindService);
        Button unbindService = (Button) findViewById(R.id.unbindService);
        Button sendMsg = (Button) findViewById(R.id.sendMsgToService);

        bindService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("zj", "onClick-->bindService");
                //当前Activity绑定服务端
                bindService(new Intent(ActivityMessenger.this, MessengerService.class), mConnection,
                        Context.BIND_AUTO_CREATE);
            }
        });

        //发送消息给服务端
        sendMsg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sayHello(v);
            }
        });


        unbindService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Unbind from the service
                if (mBound) {
                    Log.d("zj", "onClick-->unbindService");
                    unbindService(mConnection);
                    mBound = false;
                }
            }
        });
    }


}

多次点击绑定服务,然后发送信息给服务端,最后解除绑定,Log打印如下:

messenger

关于绑定服务的注意点

1.多个客户端可同时连接到一个服务。不过,只有在第一个客户端绑定时,系统才会调用服务的 onBind() 方法来检索 IBinder。系统随后无需再次调用 onBind(),便可将同一 IBinder 传递至任何其他绑定的客户端。当最后一个客户端取消与服务的绑定时,系统会将服务销毁(除非 startService() 也启动了该服务)。

2.通常情况下我们应该在客户端生命周期(如Activity的生命周期)的引入 (bring-up) 和退出 (tear-down) 时刻设置绑定和取消绑定操作,以便控制绑定状态下的Service,一般有以下两种情况:

如果只需要在 Activity 可见时与服务交互,则应在 onStart() 期间绑定,在 onStop() 期间取消绑定。

如果希望 Activity 在后台停止运行状态下仍可接收响应,则可在 onCreate() 期间绑定,在 onDestroy() 期间取消绑定。需要注意的是,这意味着 Activity 在其整个运行过程中(甚至包括后台运行期间)都需要使用服务,因此如果服务位于其他进程内,那么当提高该进程的权重时,系统很可能会终止该进程。

3.通常情况下(注意),切勿在 Activity 的 onResume() 和 onPause() 期间绑定和取消绑定,因为每一次生命周期转换都会发生这些回调,这样反复绑定与解绑是不合理的。此外,如果应用内的多个 Activity 绑定到同一服务,并且其中两个 Activity 之间发生了转换,则如果当前 Activity 在下一次绑定(恢复期间)之前取消绑定(暂停期间),系统可能会销毁服务并重建服务,因此服务的绑定不应该发生在 Activity 的 onResume() 和 onPause()中。

4.我们应该始终捕获 DeadObjectException DeadObjectException 异常,该异常是在连接中断时引发的,表示调用的对象已死亡,也就是Service对象已销毁,这是远程方法引发的唯一异常,DeadObjectException继承自RemoteException,因此我们也可以捕获RemoteException异常。

5.应用组件(客户端)可通过调用 bindService() 绑定到服务,Android 系统随后调用服务的 onBind() 方法,该方法返回用于与服务交互的 IBinder,而该绑定是异步执行的。

参考:

关于Android Service真正的完全详解,你需要知道的一切
基础总结篇之四:Service完全解析
使用AIDL实现进程间的通信
使用AIDL实现进程间的通信之复杂类型传递

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值