Android组件系列——Service

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);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值