Android Service完全解析

来源:互联网 发布:农村淘宝下载安装2017 编辑:程序博客网 时间:2024/04/30 06:18
本博客为作者原创,若要转载请注明出处,谢谢。
  我们知道ActivityContentProvider,Service,Broadcastandroid四大组件,主要用来做一些后台的操作,执行些长期运行的任务,有时候我们需要在程序退出的时候,让service继续执行服务。其实从名字就能看出来,它就是一个服务,但是在之前我并不很了解Service是个神码概念,在网上找了写资料,这次有所了解了,特意分享下,这是我第一篇绝对原创认真写的博客,因此有错误还请各位看客评论指正,感激不尽。
创建Service
  Service最简单的创建,就是写一个类继承Service,我们看Service的源码是这样的
class Service extends ContextWrapper implements ComponentCallbacks2
我看了下其他三大组件也是继承自ContextWrapper并且实现了ComponentCallbacks。这个子类写好了,我们自己定义的一个Service就写好了,我们可以在子类里面复写父类的方法自定义自己的功能。如下:
public class IMService extends Service {public static final String TAG = "IMService";private IMService mBinder = new IMService();    @Override    public void onCreate() {        super.onCreate();        Log.d(TAG, "onCreate() executed");    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.d(TAG, "onStartCommand() executed");        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onDestroy() {        super.onDestroy();        Log.d(TAG, "onDestroy() executed");    }    @Override    public IBinder onBind(Intent intent) {        return null;    }       class IMBinder extends Binder {        public void getService() {            Log.d("TAG", "IMBinder() executed");           return IMService.this;      }    }}

  我们注意到里面有一onBind方法,不了解Binder的童鞋请看这篇文章:
xxxsdsdsdsdsds
接下来就是怎么启动这个Service了。
启动Service
  启动Service有两种方式,第一种是像启动Broadcast一样使用Intent直接startstop
//启动ServiceIntent startIntent = new Intent(this, MyService.class);startService(startIntent);//停止ServiceIntent stopIntent = new Intent(this, MyService.class);stopService(stopIntent);
这种启动方式和Activity没有关联的,就是一个独立的服务,所有的操作逻辑都写在了Service里面,没有给外部提供接口。
  第二种启动Service的方法就是绑定了Activity,说一个场景,比如我们要做一个基于XMPPIM应用,需要在很多的界面都能使用这个IMService的一些功能,比如发送Message,发送Packet等,那么就需要在这个Activity通过绑定这个Service来拿到一个用于ActivityService通讯的Binder驱动,通过这个Binder传递数据。在这里,ActivityService是在同一个进程里面的,Linux的进程和android系统的进程是一个概念,每一个android应用程序都运行在一个自己的linux进程中,如果要在一个程序中调用另一个程序的Service怎么办?就像我们要调用微信支付,支付宝支付一样,这就是AIDLandroidinterface define language 安卓接口定义语言)。
  这里我简单写一个activity绑定Service,假设我们需要在界面可见和不可见的时候绑定和解绑IMService
private IMService.MyBinder myBinder;private ServiceConnection connection = new ServiceConnection() {    @Override    public void onServiceDisconnected(ComponentName name) {    }    @Override    public void onServiceConnected(ComponentName name, IBinder service) {        myBinder = (MyService.MyBinder) service;        IMService imService = ((IMService.XXBinder) service).getService();  //imService.getxxx();拿到了这个service对象    }};@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);}@Overrideprotected void onResume() {    super.onResume();    Intent bindIntent = new Intent(this, IMService.class);    bindService(bindIntent, connection, BIND_AUTO_CREATE);}@Overrideprotected void onStop() {    super.onStop();    Intent stopIntent = new Intent(this, IMService.class);    stopService(stopIntent);}
我们发现这种绑定方式需要一个ServiceConnection,在这个onServiceConnected()方法里面,让Activity拿到了Service对外提供的Binder,于是乎,拿到这个binder就能通讯拉。我们要拿到这个service对象就能通过这个IBindergetService()方法,拿到IMService对象操作Service里面的方法。
Service不管你怎么startService,它只创建一次,当启动一个Service的时候,会调用该Service中的onCreate()onStartCommand()方法。但是再startService的时候,只执行onStartCommand()方法
销毁Service
  在没有绑定Service的情况下,只需要调用stopService()就好了,但是如果是绑定了的Service要想让执行onDestory()方法,必须既执行stopService又执行unbindServie方法,因为一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。
关于ServiceThread
  以前在写一个程序的时候,一直以为Service就是一个新的线程,于是在里面做了一些耗时的操作,结果出现了ANR异常,开始特别奇怪,因为觉得Service不是处理后台事务的吗?查资料才发现ServiceBroadcast也样也是运行在主线程里面的,要避免出现ANR就需要在Service里面把耗时的操作放在自线程里面,所谓Service的后台,就是相对用户来说,用户看不到Service运行的是啥,而且在程序退出后Service仍然可以继续运行。
android系统提供了一个异步的Service,叫做IntentServiceIntentServiceonCreate()函数中通过HandlerThread单独开启一个线程来处理所有Intent请求对象(通过startService的方式发送过来的)所对应的任,这样以免事务处理阻塞主线程。执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;否则执行下一个Intent请求所对应的任务。使用IntentService需要写构造函数和复写onHandleIntent();这个onHandleIntent里面处理那些耗时的操作。IntentService其实很简单,想要了解详情请查看末尾附上的IntentService源码;
注意IntentService的构造函数一定是参数为空的构造函数,然后再在其中调用super("name")这种形式的构造函数。
有后台的Service,必然有前台的Service,我们知道android系统在回收的时候,用户可见的会相对不可见的难回收,要想让Service不那么容易被回收,一种就是和Activity绑定,当前显示的这个Activity绑定了这个Service,那么这个Service优先级别最高,最后回收,这里的Service还是后台的Service,前台的Service就是像一些天气类软件,在任务栏固定了一个item,类似于通知。这样,他在后台更新数据的同时也能实时显示天气数据。
  创建一个前台Service很简单,就是先创建一个Notification,把这个notification设置startForeground()就搞定了,在Service里面这么些
Notification notification = new Notification(R.drawable.ic_launcher,       "有通知到来", System.currentTimeMillis());Intent notificationIntent = new Intent(this, MainActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,        notificationIntent, 0);notification.setLatestEventInfo(this, "这是通知的标题", "这是通知的内容",pendingIntent);startForeground(1, notification);


IntentService源码:
package android.app;       import android.content.Intent;        import android.os.Handler;        import android.os.HandlerThread;        import android.os.IBinder;        import android.os.Looper;        import android.os.Message;public abstract class IntentService extends Service {    private volatile Looper mServiceLooper;    private volatile ServiceHandler mServiceHandler;    private String mName;    private boolean mRedelivery;    private final class ServiceHandler extends Handler {        public ServiceHandler(Looper looper) {            super(looper);        }        @Override        public void handleMessage(Message msg) {            onHandleIntent((Intent)msg.obj);            stopSelf(msg.arg1);        }    }    public IntentService(String name) {        super();        mName = name;    }    public void setIntentRedelivery(boolean enabled) {        mRedelivery = enabled;    }    @Override    public void onCreate() {        // TODO: It would be nice to have an option to hold a partial wakelock        // during processing, and to have a static startService(Context, Intent)        // method that would launch the service & hand off a wakelock.        super.onCreate();        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");        thread.start();        mServiceLooper = thread.getLooper();        mServiceHandler = new ServiceHandler(mServiceLooper);    }    @Override    public void onStart(Intent intent, int startId) {        Message msg = mServiceHandler.obtainMessage();        msg.arg1 = startId;        msg.obj = intent;        mServiceHandler.sendMessage(msg);    }    /**     * You should not override this method for your IntentService. Instead,     * override {@link #onHandleIntent}, which the system calls when the IntentService     * receives a start request.     * @see android.app.Service#onStartCommand     */    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        onStart(intent, startId);        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;    }    @Override    public void onDestroy() {        mServiceLooper.quit();    }    @Override    public IBinder onBind(Intent intent) {        return null;    }    protected abstract void onHandleIntent(Intent intent);}




0 0
原创粉丝点击