今天来总结一下Android四大组件中Service的使用。Service是为了实现程序的后台运行而存在的,它依赖于应用程序进程,当Service所对应的程序进程被杀掉后,此服务也会停止运行。当我们需要在服务中进行一些耗时的操作时,通常需要创建一个子线程,因为服务默认是运行在主线程的,一旦有耗时操作阻塞了主线程,可能就会发生ANR的情况。

创建和停止服务

通常应该定义一个类继承Service,并在其中重写onBind(Intent intent)onCreate()onStartCommand(Intent intent, int flags, int startId)onDestroy()这几个方法,其中onBind(Intent intent)是为了绑定服务和活动所需要的等下再说。

public class TestService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "start service", Toast.LENGTH_SHORT).show();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "stop service", Toast.LENGTH_SHORT).show();
    }
}

然后在xml文件中定义两个按钮,分别为启动服务和停止服务。

    <Button
        android:id="@+id/btn_start_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start Service" />

    <Button
        android:id="@+id/btn_stop_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop Service" />

接着在MainActivity中书写主要逻辑。

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Button btnStartService, btnStopService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnStartService = (Button) findViewById(R.id.btn_start_service);
        btnStopService = (Button) findViewById(R.id.btn_stop_service);
        btnStartService.setOnClickListener(this);
        btnStopService.setOnClickListener(this);
    }

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

最后在AndroidManifest中注册。

<service android:name=".TestService" />

至此一个简单的创建结束服务程序就完成了。

绑定和解绑服务

通常我们在使用服务的时候都是配合着活动来使用的,而此时就需要将活动和服务绑定起来。我们接着在上一个程序的基础上修改。

首先创建一个类继承Binder。

public class TestBind extends Binder {

    private Context context;

    public TestBind(Context context) {
        this.context = context;
    }

    public void showMessage() {
        Toast.makeText(context, "It's a message from Binder", Toast.LENGTH_SHORT).show();
    }
}

接着修改TestService中的方法。

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new TestBind(this);
    }

然后增加两个按钮分别绑定和解绑服务。

    <Button
        android:id="@+id/btn_bind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Bind Service" />

    <Button
        android:id="@+id/btn_unbind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Unbind Service" />

最后修改MainActivity文件,先增加一个新的对象

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            ((TestBind) service).showMessage();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

然后引入两个按钮,并实现逻辑,这里省略引入按钮的代码,直接展示实现逻辑的代码。

            case R.id.btn_bind_service:
                Intent bindIntent = new Intent(this, TestService.class);
                bindService(bindIntent, serviceConnection, BIND_AUTO_CREATE);
                break;
            case  R.id.btn_unbind_service:
                unbindService(serviceConnection);
                break;

至此就完成了绑定和解绑服务功能。

通知栏服务

我们在使用程序的时候总是有一些“通知”常驻在通知栏,其实那是一个在通知栏的服务,也就属于在前台的可视化的服务,接下来我们就来实现这个服务。

首先修改TestService中的代码,它的本质其实也是创建一个通知。我们修改一下onCreate()中的代码。

    @Override
    public void onCreate() {
        super.onCreate();
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Service Title")
                .setContentText("Service Text");

        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        startForeground(1, builder.build());
    }

然后直接运行程序开始一个服务就可以看到效果了。

服务和子线程

在Android中系统提供了一种非常方便的方式让我们能够直接使用运行在子线程中的服务,那就是使用IntentService,这个服务在执行完毕相应的逻辑之后会自动停止。

我们也像之前一样实现一个类,不过这次继承的是IntentService

public class TestIntentService extends IntentService {

    public TestIntentService(){
        super("TestIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        //这里执行具体的逻辑,我们输出一下线程查看是否本服务运行在和主线程不同的线程中
        Log.d("test", "Service Thread -> " + Thread.currentThread().getId());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //这里在服务自动销毁时会被调用,我们输出一个Toast查看服务是否被自动销毁了
        Toast.makeText(this, "Service was Destroied", Toast.LENGTH_SHORT).show();
    }
}

然后在布局中增加一个按钮启动服务。

    <Button
        android:id="@+id/btn_start_intentservice"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start IntentService" />

然后在MainActivity中引入按钮,这里同样隐藏引入代码,只放上具体的实现逻辑代码。

            case R.id.btn_start_intentservice:
                //这里输入主线程ID与服务中的子线程ID进行对比
                Log.d("test", "Main Thread -> " + Thread.currentThread().getId());
                Intent startIntentService = new Intent(this, TestIntentService.class);
                startService(startIntentService);
                break;

最后在AndroidManifest中注册。

        <service android:name=".TestIntentService" />

然后就可以运行程序了。


至此Service的总结就全部结束了。