一篇就够了系列之Service全解析
2017-07-07 15:30
239 查看
前言:
一篇就够了系列之Activity全解析中详细介绍了Activity的相关知识点,感兴趣的同学可以看看。本篇文章主要介绍下Service的一些学习感悟,希望能对大家有所帮助。下面从以下四个部分开展:
Service基础
Service两种启动方式
IntentService
Service各种使用场景
Service基础
定义Service是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。(A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use)。相对于Activity可以进行操作而言,Service更像是一个在后台默默服务的角色,不可感知,但的的确确存在。作为Android四大组件之一,Service是需要在manifest中进行注册的。
作用
那么,Service可以用来做什么呢?App中最常用到Service的功能应该就是下载和音乐播放等了。包括我们集成第三方的推送服务等等。简单总结起来,Service主要是做不需要依赖UI,长时间运行的一些功能。
Service和Thread的区别
Thread:线程,程序执行的最小单位,是cpu分配资源的基本单位,每个进程可以有N个线程同时运行。
而通过Service的定义我们知道,它和Thread没有任何关联。更多的误解是来自于,Service这个单词的中文意义。实际上,和Activity一样,Service也是运行在主线程中(即UI线程),所以,虽然说,Service常用来执行长时间运行,耗时操作的代码,但是,此时的代码我们必须把其放在一个新的子线程中运行,这样才不回造成线程阻塞(ANR)。
Service的独特之处就在于其可以在程序处于后台的时候,仍然可以继续运行,此时的Activity会处于OnStop或者OnDestory状态,这样,我们的程序就达到了Activity无法执行的功能,Service的价值就体现了出来。
Service两种启动方式
Service的启动需要依赖Activity,并且有两种启动方式。startService:
Activity代码:
public class ServiceActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_service); //开启服务 findViewById(R.id.tv_start).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startService(new Intent(ServiceActivity.this,MyService.class)); } }); //停止服务 findViewById(R.id.tv_stop).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopService(new Intent(ServiceActivity.this,MyService.class)); } }); } }
Service代码:
public class MyService extends Service { //第一次进入会调用 @Override public void onCreate() { Log.i("wy","oncreate"); super.onCreate(); } //每次进入都会调用 @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("wy","onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { Log.i("wy","onDestroy"); super.onDestroy(); } //bind启动会调用 @Nullable @Override public IBinder onBind(Intent intent) { Log.i("wy","onBind"); return super.onBind(intent); } }
以上代码可以简单总结几点:
startService和stopService都是Activity中的方法,并且都是通过Intent进行的跳转。
startService调用后,Service中会走onCreate和onStartCommand,如果继续调用startService,此时只有onStartCommand的方法会走,onCreate表示创建,既然已将创建过了对象,此时该方法不会继续走,即使我们把该Activity杀死(注意,不是App杀死),再次进入,仍然如此,说明Service不依赖于该Activity的存在而存在。
只有调用stopService方法,才会走onDestroy,说明此时该Service已经杀死。
事实上,我们可以在其他Activity中调用stopService方法关闭该Service,这也说明了这种启动方式,Service和Activity除了开启和关闭,没有其他任何关心
bindService
Activity代码:
public class ServiceActivity extends AppCompatActivity { private MyService.MyBinder mBinder; private ServiceConnection mServiceConnection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mBinder= (MyService.MyBinder) service; } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_service); //开启服务 findViewById(R.id.tv_bind).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { bindService(new Intent(ServiceActivity.this,MyService.class) ,mServiceConnection,BIND_AUTO_CREATE); } }); //停止服务 findViewById(R.id.tv_unbind).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { unbindService(mServiceConnection); } }); } }
Service代码:
public class MyService extends Service { private MyBinder mBinder=new MyBinder(); public class MyBinder extends Binder{ public void someMethod(){ } } //第一次进入会调用 @Override public void onCreate() { Log.i("wy","oncreate"); super.onCreate(); } //每次进入都会调用 @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("wy","onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { Log.i("wy","onDestroy"); super.onDestroy(); } //bind启动会调用 @Nullable @Override public IBinder onBind(Intent intent) { Log.i("wy","onBind"); return mBinder; } }
仔细观察可以发现:
- bindService调用,首先会走:oncreate,然后调用onBind,而onStartCommand并不会走,说明这个方法是startActivity这种启动方式特有的。
- bindService(new Intent(ServiceActivity.this,MyService.class),mServiceConnection,BIND_AUTO_CREATE);需要传入三个参数,第一个是Intent,第二个是ServiceConnection,该对象是个interface,有两个抽象方法,其中会回调出IBinder对象,通过MyService代码可以发现,有了IBinder对象,就相当于获取到Service视力,可以调用其中的public的方法,实现了在Activity中调用Service的方法。
- 销毁Activity或者调用unbindService,都会走onDestory方法,这也就切合Bind(绑定)这个词汇,说明该Service和Activity已经绑定在一起,是一对一的关系。
IntentService
可以发现,上面两种方式,各有利弊,如果我们想开启一个任务在后台运行,执行完毕后结束该Service而不需要主动结束。Android中就要这个一个类:IntentService这是一继承自Service的借口,内部利用Handler机制实现不同线程间交流通信,然后调用stopSelf结束该Service,直接上源码:
public abstract class IntentService extends Service { private volatile Looper mServiceLooper; private volatile ServiceHandler mServiceHandler; private String mName; private boolean mRedelivery; //Handler对象 private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { //调用我们自己实现的方法,也是需要继承重写的方法 onHandleIntent((Intent)msg.obj); //结束对应startid的任务,全部结束后销毁该Service stopSelf(msg.arg1); } } //onStartCommand中调用 public void setIntentRedelivery(boolean enabled) { mRedelivery = enabled; } //初始化HandlerThread对象,代码是HanderThread对象的标准写法,意义是在子线程中创建了一个Handler,也就是ServiceHandler对象(一般默认生成的Handler对象都是在主线程中) @Override public void onCreate() { super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } //在onStartCommand中调用 @Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } //每次点击startService就会调用该方法 @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } //Service销毁调用,mServiceLooper.quit(),释放内存,必须 @Override public void onDestroy() { mServiceLooper.quit(); } @Override @Nullable public IBinder onBind(Intent intent) { return null; } //工作线程,可以进行耗时操作 @WorkerThread protected abstract void onHandleIntent(@Nullable Intent intent); }
我们的代码:
public class MyIntentService extends IntentService { /** * Creates an IntentService. Invoked by your subclass's constructor. * * @param name Used to name the worker thread, important only for debugging. */ public MyIntentService() { super("MyIntentService"); Log.i("intentservice","construct"); } @Override protected void onHandleIntent(@Nullable Intent intent) { Log.i("intentservice","onHandleIntent"); try { //模拟上传耗时 Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void onCreate() { Log.i("intentservice","onCreate"); super.onCreate(); } @Override public void onStart(@Nullable Intent intent, int startId) { Log.i("intentservice","onstart"+startId); super.onStart(intent, startId); } @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { Log.i("intentservice","onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); Log.i("intentservice","onDestroy"); } @Nullable @Override public IBinder onBind(Intent intent) { return super.onBind(intent); } }
连续6下点击startService,Log为:
construct onCreate onStartCommand onstart1 onHandleIntent onStartCommand onstart2 onStartCommand onstart3 onStartCommand onstart4 onStartCommand onstart5 onStartCommand onstart6 onHandleIntent onHandleIntent onHandleIntent onHandleIntent onHandleIntent onDestroy
大家可以尝试运行,打印Log加深理解
Service各种使用场景及tips
IntentService:很明显,这种service的用途会很广泛,比如我们进行图片下载,退出应用时一些状态的保存,甚至是启动页中需要初始化的一些耗时的代码startService和bindService可以混用,只需要记住一点:startService只是启动一个Service,与启动者没有关联,杀死必须要调用stopService或者是stopself,bindService依赖于调用者,当调用者销毁后,它也会跟着销毁。
service的调用者有Activity,Service和ContentProvider
在后台运行的service在系统资源紧张的情况下还是会被系统回收,为了提高优先级,我们可以使用前置Service,比如我们骑共享单车的的通知栏:
@Override public void onCreate() { Log.i("wy","oncreate"); super.onCreate(); //获取NotificationManager实例 NotificationManager notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); //实例化NotificationCompat.Builde并设置相关属性 NotificationCompat.Builder builder = new NotificationCompat.Builder(this) //设置小图标 .setSmallIcon(R.mipmap.ic_launcher) //设置通知标题 .setContentTitle("最简单的Notification") //设置通知内容 .setContentText("只有小图标、标题、内容"); //设置通知时间,默认为系统发出通知的时间,通常不用设置 //.setWhen(System.currentTimeMillis()); //通过builder.build()方法生成Notification对象,并发送通知,id=1 Notification notification=builder.build(); notifyManager.notify(1, notification); startForeground(1, notification); }
效果图为:
Notication的知识点可以翻墙看Google官方文档Notification,全中文
差不多就这些了,期待大家的留言!
一篇就够了系列之Activity全解析
相关文章推荐
- 一篇就够了系列之BroadcastReceiver全解析
- 一篇就够了系列之ContentProvider全解析
- 一篇就够了系列之Android Manifest全解析
- 一篇就够了系列之Activity全解析
- 一篇就够了系列之Handler全解析
- 【修真院“善良”系列之十八】WEB程序员从零开始到就业的全资料V1.0——只看这一篇就够了!
- Android学习系列(20)--App数据格式之解析Json--关于Json超棒的一篇文章
- 【Android源码系列】如何解析APK-PackageManagerService
- RxJava源码深度解析-就这一篇就够了
- 安卓Service详解,你需要知道的一切,这一篇就够了
- BlockingQueue深入解析-BlockingQueue看这一篇就够了
- Android源码解析四大组件系列(一)---Service的启动过程分析
- Java、安卓的线程理解系列一(一篇就够了)
- SOA & Webservice系列课程(1):面向服务的实质 -- 讲师: 吴延安
- Xml WebService完全实例解析
- 深入Atlas系列:探究Application Services(1) - Profile Service分析与使用
- SharePoint Web Service系列:进行列表的增删改
- 上传漏洞解析-小韩网站编程安全系列二
- SharePoint Web Service系列: Add或Update类型为User的项
- Xml WebService完全实例解析(转)