Android Service

Service 简介

ServiceAndroid四大组件之一,一般而言,Activity 用于提供一个可供交互的屏幕界面,以此完成一些任务。而Service则与 Activity 不同,它主要用于执行一些不需要与用户进行交互且需要长时间运行的任务。值得注意是,Service虽然是处理后台任务的,但它仍然运行在主线程中,所以,如果需要执行耗时任务,还需要开启一个子线程,不然会出现 ANR(Application Not Responding)现象。庆幸的是,Android中存在一个 IntentService类,它拥有自己的线程,是独立于 主线程的,所以我们需要使用Service的时候可以直接继承自 IntentService

Service 的两种启动方法

  1. Context.startService()

如果我们需要程序在后台执行一项任务,即使当前用户并没有与程序发生交互,而且这项任务的执行并不需要用户的干预,即不需要与用户发生过多的交互,我们可以选择该方法。

Context.startService()方法调用后,系统会首先调用 ServiceonCreate()方法(第一次运行调用该方法,之后就不再调用),然后调用 onStartCommand(Intent, int, int)。该Service 会一直运行下去,直到 Context.stopService()或者 StopSelf()被调用。

onStartCommand(Intent, int, int) 方法会返回一个整形常量,该常量用于告诉系统如何处理 Service的重启操作,其中三个返回值为

返回 START_STICKY 代表当前系统出于某些原因关闭Service 时,Service 会被重新启动。但是,当系统重启 Service 时, onStartCommand()参数中的Intent会被置为 null

返回START_NOT_STICKY 意味着 Service不会在系统关闭它时重新启动,适合执行一次性的操作 。

返回 START_REDELIVER_INTENT的效果和 START_STICKY 基本一样,但是 onStartCommand()会接收到Service 被销毁之前接收到的最后一个 Intent

  1. Context.bindService()

对应于上一个方法,如果该后台任务需要与用户发生频繁的交互,可以采用该方法,当然这种方法比上一种方法复杂些。

Context.bindService() 方法调用后,如果该 Service 还不存在,那么 首先调用onCreate()方法,然后调用onBind(Intent)方法。 该 Service会一直运行只要Connection 是建立着的。

Service 的使用

1.如果采用的是Context.startService(),简单用法如下:

public class MyService extends Service{

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

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

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

然后在Activity 中调用startService(Intent) 即可。

这种方法,我们可以在onCreate()方法中初始化一些我们需要的变量,在 onStartCommand()方法中执行任务,因为该方法 在每次启动服务时都会被调用,而onCreate() 只在服务创建时执行一次。
使用这种方法,当服务完成时,可以使用发送 Broadcast的方法通知Activity已经完成,然后停止该服务。

2.使用 Context.bindService(),简单用法如下

public class MyLocalService extends Service {

    private LocalBinder mLocalBinder = new LocalBinder();

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

    public void doLongRunningOperation() {
        //执行耗时任务
    }

    public class LocalBinder extends Binder {
        public MyLocalService getService() {
            return MyLocalService.this;
        }
    }
}

public class MainActivity extends AppCompatActivity implements ServiceConnection{

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

    @Override
    protected void onResume() {
        super.onResume();
        Intent intent = new Intent(this,MyLocalService.class);
        bindService(intent,this,BIND_AUTO_CREATE);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mLocalService != null){
            unbindService(this);
        }
    }

    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        mLocalService = ((MyLocalService.LocalBinder)iBinder).getService();
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        mLocalService = null;
    }
}

如图示,当在Activity 中调用 bindService() 之后,接着就会调用 Service 中的onBind() 方法,该方法会返回一个IBinderonServiceConnected()方法,然后就可以通过 IBinder 获得该 Service对象,接着就可以像使用一个 普通 Java对象使用它了。

请注意,以上两种方法在执行耗时任务时,都需要手动的去开启一个子线程,为了方便和高效,我们可以使用 IntentService工具类。

IntentService 的使用

IntentServiceService中包装了一个处理后台线程的 Handler,多个调用会被内部的Hnadler放到队列中,所以能确保在同一时间只能有一个 Intent被处理,基于IntentServiceService 会一直处于启动状态,直到队列中没有要处理的任务。

public class MyIntentService extends IntentService{

    public static String ACTION_DOWNLOAD = "com.example.myintentservice.download"; 
public MyIntentService(String name) {
        super(name);
        setIntentRedelivery(false);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        String action = intent.getAction();
        if (ACTION_DOWNLOAD.equals(action)){
            download();
        }
    }

    private void download(){
        //Download
    }
}

这个时候,我们需要在清单文件中为 Service 添加相应的intent-filter,然后以带有特定actionIntent调用 Context.startService()方法。

Service 的通信

上面已经提到过很多次,如果使用Context.startService(),和 Activity 交互是很不方便的,就好像Activity 提醒 Service你可以运行了,然后Service就开始自顾自的运行,直到运行结束,通过 Broadcast Receiver发送一条广播,告诉Activity我完成任务了,你可以调用 stopService()了。如果仅仅是这样,是很不利于ServiceActivity 之间进行大规模快速更新操作的。那么该怎么办呢?

Context.bindService 天生就是解决这个问题的,谁让咱在创建的时候还能返回一个IBinder呢。 下面就来使用它完成一个下载任务

public class MyLocalService extends Service {

    private LocalBinder mLocalBinder = new LocalBinder();
    private Callback mCallback;

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

    public void doLongRunningOperation() {
        new MyAsyncTask().execute();
    }

    public class LocalBinder extends Binder {
        public MyLocalService getService() {
            return MyLocalService.this;
        }
    }

    public interface Callback{
        public void onOperationProgress(int progress);
        public void onOperationCompleted(boolean complete);
    }

    public void setCallback(Callback callback){
        mCallback = callback;
    }

    private final class MyAsyncTask extends AsyncTask{

        @Override
        protected Boolean doInBackground(Void... voids) {
            int progress = 0;
            for (progress = 0;progress<=100;progress+=25) {
                publishProgress(progress);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return true;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            if (mCallback != null){
                mCallback.onOperationProgress(values[0]);
            }
        }

        @Override
        protected void onPostExecute(Boolean aBoolean) {
            if (mCallback != null && aBoolean){
                mCallback.onOperationCompleted(true);
            }
        }
    }
}

public class MainActivity extends AppCompatActivity implements ServiceConnection,MyLocalService.Callback{

    private MyLocalService mLocalService;
    private Button mButton;
    private ProgressDialog mDialog;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton = (Button) findViewById(R.id.start);
        mDialog = new ProgressDialog(this);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mDialog.setTitle("Download");
                mDialog.show();
                mLocalService.doLongRunningOperation();
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        Intent intent = new Intent(this,MyLocalService.class);
        bindService(intent,this,BIND_AUTO_CREATE);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mLocalService != null){
            mLocalService.setCallback(null);
            unbindService(this);
        }
    }

    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        mLocalService = ((MyLocalService.LocalBinder)iBinder).getService();
        mLocalService.setCallback(this);
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        mLocalService = null;
    }

    @Override
    public void onOperationProgress(int progress) {
        mDialog.setMessage(progress+"%");
    }

    @Override
    public void onOperationCompleted(boolean complete) {
        if (complete){
            mDialog.dismiss();
            Toast.makeText(this, "Download success", Toast.LENGTH_SHORT).show();
        }
    }
}

你可能感兴趣的:(Android Service)