Service
一种长生命周期的组件,不实现任何用户界面,一个没有界面的Activity
长期在后台运行,执行不关乎界面的一些操作比如:网易新闻服务,每隔1 分钟去服务查看是否有最新新闻
和Thread 有点相似,但是使用Thread 不安全,不严谨
运行在主线程中,因此不能用它来做耗时的操作
与Thread的区别
Service运行在主线程,不能进行耗时操作
Thread开启的子线程可以做好事操作,但不可对UI线程进行操作
生命周期
onBind onCreate onStartCommand onStart onDestroy onRebind onUnbind
标准开启模式
1 自定义Service
public class DemoService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() { //服务第一次被创建调用
super.onCreate();
}
@Override
public void onDestroy() { //服务被销毁
super.onDestroy();
}
}
2 启动Service
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,PhoneService.class); //创建一个Intent 对象
startService(intent); //启动服务
//stopService(service); //停止服务
}
}
3 在AndroidManifest.xml 中注册
注意添加权限,例如:保存录音文件到sdcard、监听电话状态、录音等
<service android:name="com.hengtang.DemoService" ></service>
绑定方式开启
生命周期
第一次开启:oncreate—>onbind,onstart和onstartcommand方法不会被执行
解除绑定服务 onunbind()—>ondetroy()
实际应用只绑定一次服务,多次绑定服务,服务只创建一次,oncreate方法只执行一次onbind方法不会被重复调用
服务只可以被解绑一次,如果用同一个conn对象多次解绑,服务会抛出异常
绑定服务调用服务方法
//核心,bindService()启动服务
bindService(new Intent(this,TestService.class), new MyConn(), BIND_AUTO_CREATE);
//TestService.java
public class TestService extends Service {
@Override public IBinder onBind(Intent intent) {/
//返回binder对象
return new MyBinder();
}
}
//MyBinder.java
//继承Binder,实现IService.Stub接口
pulbic class MyBinder extends Binder implements IService.Stub{
public void callMethodInService(String name, int money) {
。...
}
}
//定义IService接口,删除权限关键词,后缀改为.aidl
public interface IService {
//对外暴露的方法
public void callMethodInService(String name,int money);
}
//MyConn.java实现ServiceConnection接口
private class MyConn implements ServiceConnection{
@Override public void onServiceConnected(ComponentName name, IBinder service) {
//建立连接,获取myBinder对象,从而可调用其方法
myBinder = (IService) service;
//获取服务对象
iService = IService.Stub.asInterface(iBinder);
}
//断开连接
@Override public void onServiceDisconnected(ComponentName name) {}
}
1 创建远程服务工程,创建IService接口,定义callSafePay方法,改后缀名成.aidl(刷新工作空间),配置清单文件
2 创建AliPayService类继承Service,重写其中的IBinder,onCreate,onDestroy方法
3 在AliPayService类中创建私有类MyBinder类继承IService.Stub,重写接口IService中的方法callSafePay
public int callSafePay(String username, String password, float money)throws RemoteException {}
4 创建调用者工程,创建将远程服务中的IService.adil文件连同包一并复制到src文件下
5 动态绑定意图的方式使用bindService的方法
6 创建私有类MyConn实现ServiceConnection接口,重写onServiceConnected和onServiceDisconnected方法,在onServiceConnected方法中将传过来的service参数转换成IService类型,并获得其对象,再利用对象调用接口暴露的方法
bindService(intent, new MyConn(), BIND_AUTO_CREATE);
iService = IService.Stub.asInterface(iBinder);
两种开启方式比较
start的方式开启服务
服务一旦开启,长期后台运行,服务和开启者(Activity)没有任何的关系,开启者退出了,服务还是继续在后台长期运行, 开启者(Activity)不可以调用服务** 里面的方法. 在系统设置界面里面可以观察到。
bind的方式开启服务
不求同时生,但求同时死. 如果开启者(Activity)退出了, 服务也会跟着挂掉
开启者(Activity)可以间接的利用中间人调用服务里面的方法.在系统设置界面看不到的
服务如果被开启同时被绑定,服务就停不掉了.必须解除绑定服务才可以停止服务
混合的方式开启服务
好处:为了保证服务又能长期后台运行,又能调用到服务里面的方法.
步骤:
1 start的方式开启服务 (保证服务长期后台运行)
2 bind的方式绑定服务 (调用服务的方法)
3 unbind的方式解除绑定服务
4 stop的方式停止服务
应用场景:天气预报、股票软件,检测网络状态提交数据
总结
从启动,消除,实例,生命周期入手
startService()启动
即使使用bindService()、unbindService()方法,该Service均在后台运行
startService()被多次调用,OnCreat()之调用一次,onstart()调用多次,系统只创建一个Service实例,因此只需要调用一次stopService()
bindService()启动
多次调用bindService(),onCreate()只调用一次,onStart()始终不会调用
通过调用unbindService()方式解绑,或调用的上下文信息被销毁,此时系统会自动停止Service
混合启动
不管如何调用,onCreate()只调用一次,onStart()调用多次
应保证某处调用unbindService()解除绑定(尽管Activity被销毁时会自动解除)
停止服务必须通过调用unbindService()和【stopService()或stopSelf()】,不分先后。如解绑在后,调用bindService()的Context会被销毁,而导致服务停止
横竖屏切换
如进行横竖屏切换时,Activity被销毁,Context也会被销毁,即服务也会被销毁
清除服务
当一个Service被终止(1、调用stopService;2、调用stopSelf;3、不再有绑定的连接(没有被启动))时,onDestroy方法将会被调用
此时应当做一些清除工作,如停止在Service中创建并运行的线程
兼容性
SDK2.0及以后版本,onStart()被onStartCommand()替代
IntentService
继承自Service,优先级高于Service。启动方式同Service,可启动多次,但IntentService实例只有一个。任务完成后,会自动停止。
onCreate()中创建HandlerThread,其与Hanlder实现异步操作
特点
创建了一个独立的工作线程来处理所有的通过onStartCommand()传递给服务的intents
创建了一个工作队列,来逐个发送intent给onHandleIntent(),逐一执行任务,无需担心多线程问题
默认实现的onBind()返回null
默认实现的onStartCommand()的目的是将intent插入到工作队列中
使用
自定义类继承IntentService,实现onHandlerIntent()异步方法,可执行耗时操作
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
for (int i = 0; i < 1000; i++) {
Log.d(TAG,i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}}}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG,"服务结束");
}}
源码解析
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()中
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,其为一个带Looper的线程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
//启动线程
thread.start();
//Hanlder与Thread关联
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
//创建Message,并通过mServiceHandler发送
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
//内部调用onStart()
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
问题
为什么不使用后台进程而使用Service
1、Service可以放在独立的进程中,所以更安全
2、Service可以依赖现有的binder机制,不需要在应用层面上处理线程同步的繁杂工作
3、系统可以重新启动异常死去的Service
怎么在Service中创建Dialog
//添加权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
//给Dialog设置类型
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);