Android四大组件之Service必备知识点

onBind(…)函数是Service基类中的唯一抽象方法,子类都必须重写实现,此函数的返回值是针对Bound Service类型的Service才有用的,在Started Service类型中,此函数直接返回 null 即可。

1.service启动状态

主要用于执行后台计算

Intent intentService = new Intent(this, AService.class);
//启动
startService(intentService);//onCreate()-->onStartCommand()
//关闭
stopService(intentService);

onCreate():Service第一次被创建的时候调用,如果当前Service已经被创建过了,不管怎样调用startService()方法,onCreate()方法都不会再执行

int onStartCommand(Intent intent, int flags, int startId):每次启动都会调用,一般默认调用父类返回值,特殊情况有三种:

1>START_NOT_STICKY

如果系统在onStartCommand()方法返回之后杀死这个服务,那么直到接受到新的Intent对象,这个服务才会被重新创建。这是最安全的选项,用来避免在不需要的时候运行你的服务。

2>START_STICKY

如果系统在onStartCommand()返回后杀死了这个服务,系统就会重新创建这个服务并且调用onStartCommand()方法,但是它不会重新传递最后的Intent对象,系统会用一个null的Intent对象来调用onStartCommand()方法,在这个情况下,除非有一些被发送的Intent对象在等待启动服务。这适用于不执行命令的媒体播放器(或类似的服务),它只是无限期的运行着并等待工作的到来。

3>START_REDELIVER_INTENT

如果系统在onStartCommand()方法返回后,系统就会重新创建了这个服务,并且用发送给这个服务的最后的Intent对象调用了onStartCommand()方法。任意等待中的Intent对象会依次被发送。这适用于那些应该立即恢复正在执行的工作的服务,如下载文件。

需要注意的点

1>onStartCommand(..)可以多次被调用,onDestroy()与onCreate()想匹配,当用户强制kill掉进程时,onDestroy()是不会执行的。

2>对于同一类型的Service,Service实例一次永远只存在一个,而不管Client是否是相同的组件,也不管Client是否处于相同的进程中。

3>Service通过startService(..)启动Service后,此时Service的生命周期与Client本身的什么周期是没有任何关系的,只有Client调用stopService(..)或Service本身调用stopSelf(..)才能停止此Service。当然,当用户强制kill掉Service进程或系统因内存不足也可能kill掉此Service。

4>Client A 通过startService(..)启动Service后,可以在其他Client(如Client B、Client C)通过调用stopService(..)结束此Service。

5>Client调用stopService(..)时,如果当前Service没有启动,也不会出现任何报错或问题,也就是说,stopService(..)无需做当前Service是否有效的判断。

6>当Service需要运行在单独的进程中,AndroidManifest.xml声明时需要通过android:process指明此进程名称,当此Service需要对其他App开放时,android:exported属性值需要设置为true(当然,在有intent-filter时默认值就是true)。

<service
    android:name=".AService"
    android:exported="true"
    android:process=":MyCorn" >
    <intent-filter>
        <action android:name="com.dupeng.tsingda.AService" />
    </intent-filter>
</service>

2.service绑定状态

主要用于其他组件和service的交互

Intent intentService = new Intent(this, AService.class);
bindService(Intent service, ServiceConnection conn, int flags);

private ServiceConnection conn = new ServiceConnection(){
    //系统调用这个来传送在service的onBind()中返回的IBinder.
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

    }
    //Android系统在同service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了.当客户端解除绑定时,这个方法不会被调用.
    @Override
    public void onServiceDisconnected(ComponentName componentName) {

    }
};

flags:默认传1(Context.BIND_AUTO_CREATE); 传0则表示不再开启新的服务

在onServiceConnected中可以拿到Service中的iBinder对象,即可以调用其相应的方法,实现客户端和service的通信(分为:app间即跨进程,app内部通信)。

//XXXService内部类
public class MyBinder extends Binder{

    public TestService XXXService(){
        return XXX;
    }

}

跨进程不是此刻的重点,所以暂不深入
对了,别忘了解绑:unbindService(conn);

3.IntentService

在Service里面我们肯定不能直接进行耗时操作,一般都需要去开启子线程去做一些事情,自己去管理Service的生命周期以及子线程并非是个优雅的做法;好在Android给我们提供了一个类,叫做IntentService.

官方翻译:IntentService是一个基于Service的一个类,用来处理异步的请求。你可以通过startService(Intent)来提交请求,该Service会在需要的时候创建,当完成所有的任务以后自己关闭,且请求是在工作线程处理的。

使用了IntentService有两个好处,一方面不需要自己去new Thread了;另一方面不需要考虑在什么时候关闭该Service了。

源码解析:

1>IntentService源码

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() {
            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);
}


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

}

2>HandlerThread源码:

public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;

public HandlerThread(String name) {
    super(name);
    mPriority = Process.THREAD_PRIORITY_DEFAULT;
}

protected void onLooperPrepared() {
}

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}
}
源码解读: 当IntentService被第一次启动的时候,onCreate里面初始化了一个HandlerThread,然后使用它的Looper来构造一个Handler对象mServiceHandler,每次调用onStartCommand的时候,通过mServiceHandler发送一个消息,消息中包含我们的intent。然后在该mServiceHandler的handleMessage中去回调onHandleIntent(intent);即消息最终都会在HandlerThread中执行。

实际中的应用:如果存在多个后台任务,那么当onHandlerIntent执行完最后一个任务时,才会stopSelf(int startId);

stopSelf() 和stopSelf(int startId)区别:

stopSelf()会立刻停止服务,stopSelf(int startInd)则等待所有消息处理完才关闭服务。

初始化和启动了一个线程;然后我们看run()方法,可以看到该方法中调用了Looper.prepare(),Loop.loop();

全部评论

相关推荐

点赞 评论 收藏
分享
预计下个星期就能开奖吧,哪位老哥来给个准信
华孝子爱信等:对接人上周说的是这周
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务