Android(安卓)Service 浅析(生命周期,启动方式,前台Service)
Service是android中四大组件之一,重要性仅次于Activity,Android文档对他的描述如下:
Service组件表示在不影响用户的情况下执行耗时操作或者提供其他应用使用的功能。
在android中所有的组件都运行在主线程,使用service的时候,还需要吧耗时的操作另开启一个线程。但是使用Service,更适合管理耗时的操作,因为service有着不同的生命周期。比如说应用中播放音乐,通常由Service控制。
启动Service
Service 可以通过两种方式启动:Context.startService()或者Context.bindService();
Context.startService()和启动activity的方法类似:
Intent i = new Intent(ServiceActivity.this, ServiceA.class); startService(i);
使用这种方式启动Service后,Service分别会调用onCreate()和onStartCommand()方法。
停止Service的方法:
Intent i = new Intent(ServiceTestActivity.this, ServiceA.class);stopService(i);
也可以调用Service的stopSelf()方法进行停止。
service销毁的时候会调用他的onDestory()方法,在这里进行释放资源的操作。
需要注意的是多次启动Service,onCreate()方法不会多次调用,只有在第一次启动的时候会调用(或者把Service销毁重新start),但是onStartCommand()方法会多次调用。
第二种方式:Context.bindService()
Intent i = new Intent(ServiceTestActivity.this, ServiceA.class);bindService(i,connection,BIND_AUTO_CREATE);
解除绑定方法:
Intent i = new Intent(ServiceTestActivity.this, ServiceA.class);unbindService(connection);
这种方式启动Service的时候,生命周期方法如下:
bindService->onCreate->onBind->unbindService->onUnbind->onDestroy
如果没有调用unbindService方法,当activity销毁的时候此Service也能销毁,但是会发生内存泄露,会报如下错误:
Activity example.ylh.com.service_demo.ServiceTestActivity has leaked ServiceConnection example.ylh.com.service_demo.ServiceTestActivity$1@513a0eb that was originally bound here······
所以为了防止内存泄露,还是老老实实的unbind吧。
bindService启动的时候,需要传两个参数,第一个是intent,第二个是ServiceConnection,这个是什么东西呢?
我们知道Service启动之后,Service额就开始运行了,但是怎么和Activity交互呢,这个时候就需要ServiceConnection了,ServiceConnection是一个接口:
private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e(TAG,"onServiceConnected"); } @Override public void onServiceDisconnected(ComponentName name) { Log.e(TAG, "onServiceDisconnected"); } };
onServiceConnected方法的调用时机是在Service的onBind之后,表示service和activity绑定成功,建立关联。
onServiceDisconnected方法表示Service和activity关联失败,没有绑定,一般不会调用。
onServiceConnected方法有两个参数,第二个参数是一个IBinder,这个IBinder就是Service的onBind方法的返回值,所以我们可以通过onBind的返回值和onServiceConnected方法,让activity和Service关联起来,下边是一个典型案例:
activity的xml:
<?xml version="1.0" encoding="utf-8"?>
activity代码:
package example.ylh.com.service_demo;import android.app.Activity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.View;import example.ylh.com.R;/** * Created by yanglihai on 2017/8/17. */public class ServiceTestActivity extends Activity { public static final String TAG = ServiceTestActivity.class.getSimpleName(); private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = ((ServiceA.MyBinder) service).getService(); Log.e(TAG,"onServiceConnected"); } @Override public void onServiceDisconnected(ComponentName name) { Log.e(TAG, "onServiceDisconnected"); } }; private ServiceA mService ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.service_test_activity); findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(ServiceTestActivity.this, ServiceA.class); bindService(i,connection,BIND_AUTO_CREATE); } }); findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(ServiceTestActivity.this, ServiceA.class); unbindService(connection); } }); findViewById(R.id.btn3).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mService.doSomething(); } }); }}
service的代码:
package example.ylh.com.service_demo;import android.app.Service;import android.content.Intent;import android.content.ServiceConnection;import android.os.Binder;import android.os.IBinder;import android.support.annotation.Nullable;import android.util.Log;/** * Created by yanglihai on 2017/8/17. */public class ServiceA extends Service { static final String TAG = ServiceA.class.getSimpleName(); @Override public void onCreate() { super.onCreate(); Log.e(TAG, "oncreate"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e(TAG, "onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); Log.e(TAG, "onDestroy"); } @Override public boolean bindService(Intent service, ServiceConnection conn, int flags) { Log.e(TAG, "bindService"); return super.bindService(service, conn, flags); } @Override public void unbindService(ServiceConnection conn) { super.unbindService(conn); Log.e(TAG, "unBindService"); } @Override public boolean onUnbind(Intent intent) { Log.e(TAG, "onUnbind"); return super.onUnbind(intent); } @Nullable @Override public IBinder onBind(Intent intent) { Log.e(TAG, "onBind" ); return mbinder; } public void doSomething(){ Log.e(TAG, "doSomething"); } private MyBinder mbinder = new MyBinder(); public class MyBinder extends Binder{ public ServiceA getService(){ return ServiceA.this; } } }
在onServiceConnected方法中,通过强转拿到binder,在通过getService()拿到Service的实例,就可以进行你想要的操作了。
前台Service
当Service启动之后,如果我们不去调用停止方法,Service会一直运行在后台,但是当系统内存不足的时候可能会杀死我们的Service,为了避免被系统杀死,可以把Service设置成前台服务,通过调用Service.startForeground()来实现。
先上代码:
package example.ylh.com.service_demo;import android.app.Notification;import android.app.Service;import android.content.Intent;import android.content.ServiceConnection;import android.os.Binder;import android.os.IBinder;import android.support.annotation.Nullable;import android.util.Log;import example.ylh.com.R;/** * Created by yanglihai on 2017/8/17. */public class ServiceA extends Service { static final String TAG = ServiceA.class.getSimpleName(); @Override public void onCreate() { super.onCreate(); Log.e(TAG, "oncreate"); Notification.Builder builder = new Notification.Builder(this); builder.setSmallIcon(R.mipmap.btn_home_vedio); builder.setContentTitle("视频通知"); builder.setContentText("someone send you a video"); Notification notification = builder.build(); startForeground(2,notification); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e(TAG, "onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); Log.e(TAG, "onDestroy"); }}
在onCreate中,创建了一个通知,用来告诉用户后台有操作在运行。startForeground()的第一个参数是一个int型的id,需要注意的是这个id不能为0,否则不能创建前台服务。
在这个Service运行期间,通知栏会有一个通知,直到Service停止或者调用StopForeground(true),通知就能消失。
补充一点,不论哪种启动方式,Service也需要在manifest文件中声明:
<?xml version="1.0" encoding="utf-8"?>
更多相关文章
- android的socket程序中conn.getResponseCode() 为405
- Android4.0 input touch解析
- Eclipse开发Android常用快捷键
- Android应用的跨语言调用小结
- Android(安卓)TextView使用HTML处理字体样式、显示图片等
- Android应用程序框架层和系统运行库层日志系统源代码分析
- Android应用AsyncTask处理机制详解及源码分析
- 浅谈Java中Collections.sort对List排序的两种方法
- Python list sort方法的具体使用