1. 服务的基本用法

1.1 定义一个服务

继承 Service 类

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("MyService", "onCreate executed");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("MyService", "onStartCommand executed");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyService", "onDestroy executed");
    }
}
  • onBind 用于活动和服务的绑定
  • onCreate 在服务被创建的时候调用,只会被调用一次
  • onStartCommand 在每次服务启动的时候调用,每次启动服务都会被调用
  • onDestroy 在服务销毁的时候调用

在 AndroidMainfest.xml 中注册

<application>
    <service
        android:name=".MyService"
        android:enabled="true"
        android:exported="true" />
</application>
  • enabled 是否启用这个服务
  • exported 是否允许其他应用访问此服务

1.2 启动和暂停服务

// 启动服务
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); 

// 停止服务
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);

// 停止服务,在 MyService 的任何位置调用 stopSelf() 即可

1.3 活动和服务进行通信

在 Service 中实现 Binder 并通过 onBind 返回

public class MyService extends Service {

    public MyService() {
    }

    private DownloadBinder mBinder = new DownloadBinder();

    class DownloadBinder extends Binder {

        public void startDownload() {
            Log.d("MyService", "startDownload executed");
        }

        public int getProgress() {
            Log.d("MyService", "getProgress executed");
            return 0;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

创建 ServiceConnection 类,重写 onServiceDisconnected 和 onServiceConnected 方法。

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private MyService.DownloadBinder downloadBinder;

    private ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            downloadBinder = (MyService.DownloadBinder) service;
            downloadBinder.startDownload();
            downloadBinder.getProgress();
        }
    };

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bind_service:
                Intent bindIntent = new Intent(this, MyService.class);
                // 第三个参数为一个标志位,表示在活动与服务绑定后自动创建服务,会使得 onCreate 方法执行,但 onStartCommand 方法不会执行
                bindService(bindIntent, connection, BIND_AUTO_CREATE); // 绑定服务
                break;
            case R.id.unbind_service:
                unbindService(connection); // 解绑服务
                break;
        }
    }

}
  • onServiceConnected 会在活动与服务绑定的时候调用,我们在这里面写逻辑
  • onServiceDisconnected 会在活动与服务解除绑定的时候调用

1.4 服务的生命周期

一旦在项目的任何位置调用了 startService() 方法,相应的 Service 就会启动,并回调 onStartCommand() 方法。如果这个 Service 服务之前还没有创建过,onCreate() 方法会先于 onStartCommand() 方法执行。

Service 启动了之后会一直保持运行状态,直到 stopService() 或 stopSelf() 方法被调用,或者被系统回收。注意,虽然每调用一次 startService() 方法,onStartCommand () 方法就会执行一次,但实际上每个 Service 只会存在一个实例。所以不管你调用了多少次 startService() 方法,只需调用一次 stopService() 或 stopSelf()方法,Service 就会停止。

另外,还可以调用 Context 的 bindService() 来获取一个 Service 的持久连接,这是就会回调 Service 中的 onBind() 方法。类似地,如果这个 Service 之前还没有被创建过,onCreate() 方法会先于 onBind() 方法执行。之后,调用方可以获取到 onBind() 方法里返回的 IBinder 对象的实例,这样就能自由地和 Service 进行通信了。只要调用方和 Service 之间的连接没有断开,Service 就会一直报纸运行状态,直到被系统回收。

当调用了 startServicer() 方法之后,再去调用 stopService() 方法。这时 Service 中的 onDestroy() 方法就会执行,表示 Service 已经销毁了。类似地,当调用了 bindServicer() 方法后,再去调用 unbindService() 方法,onDestroy() 方法也会执行,这两种情况都很好理解。但是需要注意,我们是完全有可能对一个 Service 既调用了 startServicer() 方法,又调用了 bindServicer() 方法的,在这种情况下该如何让 Service 销毁呢?根据 Android 系统的机制,一个 Service 只要被启动或者绑定了之后,就会处于运行状态,必须要让以上两种条件同时不满足,Service 才能被销毁。所以,这种情况下要同时调用 stopService() 和 unbindService() 方法,onDestroy() 方法才会执行。

2. 服务的更多技巧

2.1 前台服务

服务的优先级较低,很可能会被回收,前台服务会一直有一个正在运行的图标在系统的状态栏,类似于通知。

首先创建一个通知,然后调用 startForeground 让服务变成一个前台服务。

public class MyService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("MyService", "onCreate executed");
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
        Notification notification = new NotificationCompat.Builder(this)
                .setContentTitle("This is content title")
                .setContentText("This is content text")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                .setContentIntent(pi)
                .build();
        startForeground(1, notification);
    }
}

2.2 IntentService

服务默认在主线程运行,容易出现 anr, 我们也可以自动创建子线程,但官方给我们提供了一个 IntentService 类,会自动开启主线程并自动调用 stopSelf() 方法,集开启线程和自动停止与一身。

public class MyIntentService extends IntentService {

    public MyIntentService() {
        super("MyIntentService"); // 调用父类的有参构造函数
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // 打印当前线程的id
        Log.d("MyIntentService", "Thread id is " + Thread.currentThread(). getId());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyIntentService", "onDestroy executed");
    }

}

我们去实现 onHandleIntent() 方法,可以在此方法中处理一些具体逻辑,无需担心 anr 问题。

调用

Intent intentService = new Intent(this, MyIntentService.class);
startService(intentService);