服务
服务是什么
服务可以在后台运行而不依赖于任何用户界面
服务并不是运行在一个独立的进程中,而是依赖于创建服务时所在的应用程序进程
服务业不是运行在一个独立线程中,所有代码都是默认在主线程中运行
也就是说需要我们在服务内部手动创建子线程去执行耗时任务,否则将会阻塞主线程
安卓多线程编程
线程的基本用法
参考Java
在子线程中更新UI
GUI大都是线程不安全的,安卓的UI也一样
也就是说要更新应用程序里的UI元素必须在主线程中进行,否则就会出现异常
我们需要使用Handler来进行同步操作
public class mainActivity extends AppCompatActivity implements View.onClickListener {
public static final int UPDATE_TEXT = 1 ;
private TextView text ;
private Handler handler = new Handler(){
public void handleMessage(Message msg)
{
switch(msg.what)
{
case UPDATE_TEXT:
//进行UI操作
text.setText("Hello");
break;
}
}
}
@Override
public void onClick(View v)
{
switch(v.getId())
{
case R.id.change_text:
new Thread(new Runnable(){
@Override
public void run(){
Message message=new Message();
message.what=UPDATE_TEXT;
handler.sendMessage(message);
}
}).start();
}
}
}
解析异步消息处理机制
Message
message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在 不同线程之间交换数据,Message可以通过what携带数据外 可以使用arg1,arg2字段来携带一些整数型数据 使用obj字段可以携带一个object对象
Handler
消息处理着,用于发送消息和处理消息,发送消息一般用sendMessage(); 最终会传递到handleMessage()中
MessageQueue
消息队列,用于存放所有通过Handler发送的消息,等待被处理
Looper
消息循环,Looper是每个线程中消息队列的管家,调用Looper的loop() 方法后,会进入一个无限循环中,每当发现队列中存在一条消息就将它取出并 传递到Handler的handleMessage()中,每个线程也只会有一个Looper对象
使用AsyncTask
AsyncTask<Params,Progress,Result>
Params 执行Async时传入的参数类型,于后台任务中使用 Progress 可用于表示进度,如整数 Result 任务执行完毕的返回值(可以为void)
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
/*
在主线程中运行
这个方法会在任务开始执行之前调用
*/
@Override
protected void onPreExecute() {
progressDialog.show();
}
/*
将在子线程中运行
*/
@Override
protected Boolean doInBackground(Void... params) {
try {
while (true) {
int downloadPercent = doDownload();
publishProgress(downloadPercent);
if (downloadPercent >= 100) {
break;
}
}
} catch (Exception e) {
return false;
}
return true;
}
/*
在主线程中运行
publishProgress()执行之后,该方法在一会儿后被主线程调用
*/
@Override
protected void onProgressUpdate(Integer... values) {
progressDialog.setMessage("当前下载进度:" + values[0] + "%");
}
/*
在主线程中运行
后台任务完成后通过return返回时,这个方法就很快会被调用
返回的数据将传递到此方法中
*/
@Override
protected void onPostExecute(Boolean result) {
progressDialog.dismiss();
if (result) {
Toast.makeText(context, "下载成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();
}
}
}
启动这个任务
new DownloadTask().execute();
服务的基本用法
定义一个服务
服务必须实现Service类
IBinder onBind(Intent intent)是唯一抽象方法,必须实现
onCreate()是服务被创建时调用
onCommand()是服务每次被启动时调用
onDestory()是销毁服务时调用,用于回收资源
服务也必须在AndroidMainfest.xml中进行注册才能生效 但创建服务时Android Studio自动注册它
启动和停止服务
Intent startIntent = new Intentcontext,MyService.class);
startService(startIntent);
...
Intent stopIntent = new Intent(context,MyService.class);
stopService(stopIntent);
服务可以调用stopSelf();自己停止下来
startService第一次调用时服务的onCreate()会被调用 而onCommand在startService()任何一次调用时都会被调用
活动和服务通信
实现IBinder onBind(Intent intent)返回一个实现IBinder的对象,该对象 中可以自己定义一些公共方法暴露给外部
服务不是一个普通的对象,它是系统级的组件,要与调用者分离,它在第一次启动时 被系统创建,而以后的启动都只是使用相同的实例,所以它们仅仅通过 Binder与外部进行通讯而不是直接调用服务的
方法
private ABinder aBinder;
private ServiceConnection connection = new ServiceConnection()
{
@Override void onServiceDisconnected(ComponentName name)
{
}
@Override void onServiceConnected(ComponentName name,IBinder service)
{
aBinder=(ABinder)service;
aBinder.doSthX();
}
}
Intent bindIntent = new Intent(context,MyService.class);
bindService(bindIntent,connection,BIND_AUTO_CREATE));
//以bind方式启动服务不需要先调用startService();
//同样在服务未创建时,系统会创建服务
unbindService(connection);
aBinder.doSthY();
服务的生命周期
略
服务的更多技巧
使用前台服务
使用IntentService
public class MyService extends IntentService{
public MyService()
{
super("MyService");
}
@Override
protected void onHandleIntent(Intent intent)
{
}
}
IntentService的特殊之处在于,onHandleIntent会在子线程中运行 并且,方法结束时自动回调用onDestory并销毁服务