本博客为作者原创,若要转载请注明出处,谢谢。
我们知道Activity,ContentProvider,Service,Broadcast为android四大组件,主要用来做一些后台的操作,执行些长期运行的任务,有时候我们需要在程序退出的时候,让service继续执行服务。其实从名字就能看出来,它就是一个服务,但是在之前我并不很了解Service是个神码概念,在网上找了写资料,这次有所了解了,特意分享下,这是我第一篇绝对原创认真写的博客,因此有错误还请各位看客评论指正,感激不尽。
创建ServiceService最简单的创建,就是写一个类继承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的童鞋请看这篇文章:
xxx。sdsdsdsdsds。
接下来就是怎么启动这个Service了。
启动Service
启动Service有两种方式,第一种是像启动Broadcast一样使用Intent直接start和stop:
//启动Service Intent startIntent = new Intent(this, MyService.class); startService(startIntent); //停止Service Intent stopIntent = new Intent(this, MyService.class); stopService(stopIntent);
这种启动方式和Activity没有关联的,就是一个独立的服务,所有的操作逻辑都写在了Service里面,没有给外部提供接口。
第二种启动Service的方法就是绑定了Activity,说一个场景,比如我们要做一个基于XMPP的IM应用,需要在很多的界面都能使用这个IMService的一些功能,比如发送Message,发送Packet等,那么就需要在这个Activity通过绑定这个Service来拿到一个用于Activity和Service通讯的Binder驱动,通过这个Binder传递数据。在这里,Activity和Service是在同一个进程里面的,Linux的进程和android系统的进程是一个概念,每一个android应用程序都运行在一个自己的linux进程中,如果要在一个程序中调用另一个程序的Service怎么办?就像我们要调用微信支付,支付宝支付一样,这就是AIDL(androidinterface 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对象就能通过这个IBinder的getService()方法,拿到IMService对象操作Service里面的方法。
Service不管你怎么startService,它只创建一次,当启动一个Service的时候,会调用该Service中的onCreate()和onStartCommand()方法。但是再startService的时候,只执行onStartCommand()方法。
销毁Service
在没有绑定Service的情况下,只需要调用stopService()就好了,但是如果是绑定了的Service要想让执行onDestory()方法,必须既执行stopService又执行unbindServie方法,因为一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。
关于Service与Thread
以前在写一个程序的时候,一直以为Service就是一个新的线程,于是在里面做了一些耗时的操作,结果出现了ANR异常,开始特别奇怪,因为觉得Service不是处理后台事务的吗?查资料才发现Service和Broadcast也样也是运行在主线程里面的,要避免出现ANR就需要在Service里面把耗时的操作放在自线程里面,所谓Service的后台,就是相对用户来说,用户看不到Service运行的是啥,而且在程序退出后Service仍然可以继续运行。
android系统提供了一个异步的Service,叫做IntentService,IntentService在onCreate()函数中通过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); }
Android Service完全解析
最新推荐文章于 2024-09-21 14:23:15 发布