Android Service完全解析

本博客为作者原创,若要转载请注明出处,谢谢。

  我们知道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
//启动Service
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
//停止Service
Intent 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对象
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

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

@Override
protected 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);
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯人院的院长大人

给点实际性的支持不?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值