服务是android实现程序后台运行的解决方案,适合去执行那些不需要和用户交互,而需要长期运行的任务。服务的运行不依赖于任何用户的界面,服务并不是在一个独立的进程中,而是依赖创建服务时所在的应用程序进程,当应用程序进程被杀掉,服务终止。
服务不会自动开启线程,所有的代码都是默认在主线程中进行的。我们需要在服务的内部手动创建子线程,并在这里执行具体的任务,否则有可能出现主线程被阻塞的情况

一.定义一个服务

直接在项目的com.example.*包中直接右击新建New→Service。有两个属性需要选择
Exported:是否允许其他程序访问这个服务。
Enabled:表示是否启用这个服务。
服务是继承了service类的,一般要重写以下方法;
onCreate()
在服务创建的时候被调用,一般先于onStartCommand
onStartCommand()
每次服务启动的时候调用
onDestory()
在服务销毁的时候绑定
onBind()
常用于活动与服务的绑定等。。。

其他方法:
stopService()和stopSelf():停止服务
服务的生命周期:
1.在项目的任何位置调用Context的startService()方法,相应的服务就会启动,并回调onStartCommand()方法,如果这个服务之前没有创建过,则需要先调用onCreate.没调用一次startService(), onStartCommand()就会被调用一次,实际上每个服务只会存在一个实例。最后只需要调用一次stopService()或stopSelf()就可以停止服务。
2.Context的binService()用来获取一个服务的持久连接,这时就会回调服务中的onBind()方法,类似的,如果没创建过要先onCreate();之后方可调用onBind()方法里面返回的Ibinder对象的实例,就能自由的和服务进行通信了。
3.调用startService()方法之后,又调用stopService()方法,这时候服务中的onDestory()方法就会被执行;当调用bindService()之后,调用unbindSevice(),onDestory()方法也会被执行;、
注意当对一个服务即调用startService又调用bindService,要同时调用stopService和unBindService,onDestory()方法才会被执行;

二.服务的使用

活动与服务之间通信的实例:
xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
>

    <Button
        android:id="@+id/start_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start Service"
    />
    <Button
        android:id="@+id/stop_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop Service"/>
    <Button
        android:id="@+id/bind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Bind Service"
        />
    <Button
        android:id="@+id/unbind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Unbind Service"/>
    <Button
        android:id="@+id/start_intent_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start IntentService"/>

</LinearLayout>

MyService服务类:

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;
        }

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

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

    @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);

    }

    @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");

    }
}

DownloadBinder类继承自Binder,然后在里面提供了两个模拟的方法,接着在MyService中创建了DownloadBinder的实例,然后在onBind()方法里返回这个实例。

MainActivity类

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private  MyService.DownloadBinder downloadBinder;
    private ServiceConnection connection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            downloadBinder=(MyService.DownloadBinder) service;
            downloadBinder.startDownload();
            downloadBinder.getProgress();
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startService=(Button) findViewById(R.id.start_service);
        Button stopService=(Button) findViewById(R.id.stop_service);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
        Button bindService=(Button) findViewById(R.id.bind_service);
        Button unbindService=(Button) findViewById(R.id.unbind_service);
        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
        Button startIntentService =(Button) findViewById(R.id.start_intent_service);
        startIntentService.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.start_service:
                Intent startIntent = new Intent(this,MyService.class);
                startService(startIntent);
                break;
            case R.id.stop_service:
                Intent stopIntent=new Intent(this,MyService.class);
                stopService(stopIntent);
                break;
            case R.id.bind_service:
                Intent bindIntent=new Intent(this,MyService.class);
                bindService(bindIntent,connection,BIND_AUTO_CREATE);//绑定服务
                break;
            case R.id.unbind_service:
                unbindService(connection);//解绑服务
                break;
            case R.id.start_intent_service:
                Log.d("MainActivity","Thread id is"+Thread.currentThread().getId());
                Intent intentService =new Intent(this,MyIntentService.class);
                startService(intentService);
                break;
            default:
                break;
        }

    }
}

创建了一个ServiceConnection匿名类,在里面重写了onServiceConnected()和onServiceDisconnected()方法,分别在活动与服务成功绑定与断开的时候调用。在onServiceConnected()中,向下转型的得到了DownloadBinder的实例。可以在活动中,通过这个实例来指挥服务区干什么工作。

活动与服务要进行绑定与解绑:首先构建出一个Intent对象,然后调用bindService()方法将MainActivity和MyService进行绑定。bindService方法接收三个参数,第一个是构建的Intent对象,第二个是前面创建的ServiceConnection实例,第三个是标志位,这里传入BIND_AUTO_CREATE表示活动和服务在进行绑定之后自动创建服务,这会让Myservice中的onCreate方法执行,但是onStartCommand方法不会执行。
与bindService()对应的是unbindService()解绑,使用如上。

IntentService类

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

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

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

一般为了防止忘记调用stopSelf(),Android提供了一个异步的,会自动终止服务的IntentService类。onHandleIntent()是在子线程中运行的,可以去处理一些具体的逻辑。

3.服务的多线程

注意:服务的代码默认实在主线程中运行,如果直接在服务里去处理一些逻辑,一般容易出现ANR(Application Not Responding).这个时候就要用到多线程技术。应该为服务的每个具体的方法开启一个子线程去处理耗时的逻辑,标准的写法如下:

public class Myservice extends Service(){
    ...
    @Override
    public int OnstartCommand(Intent intent,int flags,int startId){
        new Thread(new Runnable(){
            public void run(){
                //处理具体的逻辑
            }
        }).start();
    }
}