服务(service)是Android中实现程序后台运行的解决方案。服务并不是运行在一个独立的进程中,而是依赖于创建服务所在的应用程序的进程。实际上,服务并不会自动开启线程。

android多线程编程

线程的基本用法

  • 新建一个类继承自Thread,重写父类的run()方法,在里面写耗时的逻辑。
    class MyThread extends Thread{
    @override
    public void run(){
    //写耗时的逻辑
    }
    }
    new MyThread().start();
  • 实现Runnable接口,匿名内部类的形式。
        new Thread(new Runnable() {            @Override            public void run() {            }        }).start();

在子线程中更新UI

想要更新应用程序里的UI,必须在主线程中进行。android提供了一套异步消息处理机制,完美地解决了在子线程中进行UI操作的问题。

  • 异步消息处理机制
    • 用匿名内部类的形式,实例化一个重写了handleMessage(Message msg)方法的Handler对象,在handleMessage(Message msg)方法中利用传过来的Message更新UI。
    • 当子线程有更新的需要时,将数据存在Message对象当中,调用Handler的sendMessage(message)发送到主线程。
private Handler handler = new Handler() {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            switch (msg.what) {                case UPDATA_TEXT:                    textView.setText("Hello Android!");                    break;                default:                    break;            }        }    };new Thread(new Thread() {                    @Override                    public void run() {                        //textView.setText("Hello Android!");                        Message msg = new Message();                        msg.what = UPDATA_TEXT;                        handler.sendMessage(msg);                        new downtask().execute();                    }                }).start();

深入异步消息处理机制
1、组成部分:
何为handler:异步消息处理者。handler扮演了往MessageQueue上添加消息和处理消息的角色(只处理由自己发出的,由looper分发过来(dispatch)的消息),即通知MQ它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
何为message:后台进程返回的数据,里面可以存储bundle等数据格式。
何为messageQueue:是线程对应looper的一部分,以队列的形式负责存储从后台进程中抛回的和当前handler绑定的message。
何为looper:looper相当于一个messageQueue的管理人员,同时还是“电报分发员”,它会不停的循环的遍历队列,然后将符合条件的message一个个的拿出来分发特定的handler进行处理。首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
2、过程:我们通常在UI线程中创建一个handler。这里要明确Handler、线程、looper的关系,每一个线程都绑定有一个looper,而每个Handler都要关联一个looper,所以Handler就间接绑定到了一个线程上。一个线程只能有一个looper,但可以有多个Handler。此外,线程中looper负责从其内部的messageQueue中拿出一个个的message,调用dispatchMessage()方法把Message分发给特定的Handler进行处理。handler可以在任意线程中,往它所绑定的looper内部的MQ添加消息,handler在它所绑定的线程中处理消息。因为我们这里handler是在UI线程中实现的,所以经过这么一个handler异步消息处理大师之手,就实现了跨线程间的通信了,那么UI线程更新UI就不是什么问题了。
《第一行代码--Android》读书笔记之多线程与服务_第1张图片
另外有几个值得关注的点:
1、调用handler的post(Runnable r)或者postDelayed(Runnable r,long t)方法里传进去一个Runnable的匿名类,其实这样写并不能创建一个线程,Runnable内部重写的run()方法也只是在主线程中执行。因为handler只负责发送消息和处理消息,并不是负责新建一个线程。而且,所谓的子线程的start()自始至终都没有被调用。怎样解决这个问题呢?
上文提到,handler创建时会关联一个looper,默认的构造方法将关联当前线程的looper,当然handler也可以关联到其他线程的looper啦。
可以写成如下代码:
//创建一个包含Looper的线程,这里如果没有HandlerThread的调用,会直接将后边的MyThread放到UI线程队列
HandlerThread myHandlerThread = new HandlerThread("chenzheng_java");
// 启动新线程
myHandlerThread.start();
// 将handler绑定到新线程,自定义MyHandler类需要定义自己的构造方法
handler = new MyHandler(myHandlerThread.getLooper());
// 在新线程中执行任务,MyRunnableTask是实现了Runnable接口的自定义类
handler.post(new MyRunnableTask());

2、有了handler之后,我们就可以使用 post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long)和 sendMessageDelayed(Message, long)这些方法向MQ上发送消息了。光看这些API你可能会觉得handler能发两种消息,一种是Runnable对象,一种是message对象,这是直观的理解,但其实post发出的Runnable对象最后都被封装成message对象了。
最后来张总结性的好图:
《第一行代码--Android》读书笔记之多线程与服务_第2张图片
要真正理解android的异步消息处理机制,《第一行代码》并没有做很详细的讲解,毕竟是入门书,但这个知识点是比较重要的,面试当中也会经常考到。另外推荐两篇结合android框架源码分析异步消息处理机制的博文,写得非常好的。
Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系:
http://blog.csdn.net/lmj623565791/article/details/38377229
android的消息处理机制(图+源码分析)——Looper,Handler,Message:
http://www.cnblogs.com/codingmyworld/archive/2011/09/14/2174255.html

  • 使用AsyncTask

    为了更加方便我们在子线程中对UI进行操作,android提供了一个工具类AsyncTask,把异步消息处理机制封装其中。

    • 由于AsyncTask是一个抽象类,我们需要创建一个子类去继承它。继承时,我们可以指定三个泛型参数。
      1.Params 在执行AsyncTask时需要传入的参数,doInBackground(Params,…)。
      2.Progress 在后台任务执行时,如需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位
      3.Result 指定返回值类型
    • 重写onPreExecute(),doInBackground(Params,…),onPrpgressUpdate(Progress,…),onPostExecute(Result,…)方法
    • 启动自定义任务,new DownloadTask().execute();
class downtask extends AsyncTask<Void,Integer,Boolean>{        @Override        protected void onPreExecute() {//后台任务开始执行前调用,用于进行一些界面上的初始化操作            super.onPreExecute();            ProgressDialog.show(MainActivity.this,"Downloading","Loading...");        }        @Override        protected Boolean doInBackground(Void... params) {//在子线程中进行一些耗时的操作            int downloadProgress=0;            publishProgress(downloadProgress);//传入更新ui的数据            return true;        }        @Override        protected void onProgressUpdate(Integer... values) {//更新ui操作            super.onProgressUpdate(values);        }        @Override        protected void onPostExecute(Boolean aBoolean) {//任务结束            super.onPostExecute(aBoolean);        }    }

参考博文:详解Android中AsyncTask的使用

服务的基本用法

  • 当然要自定义一个子类继承Service类,重写
    public IBinder onBind(Intent intent),与活动通信的关键方法,与活动绑定的时候调用。
    public void onCreate(),当服务被创建的时候调用
    public int onStartCommand(Intent intent, int flags, int startId),当服务被启动的时候被调用
    public void onDestroy(),当服务被销毁的时候被调用。
  • 作为android四大组件之一,要启动和停止服务当然要借助intent了,
                Intent startIntent=new Intent(this,MyService.class);                startService(startIntent);                Intent stopIntent=new Intent(this,MyService.class);                stopService(stopIntent);
  • 最后一定要在AndroidManifest文件中进行注册。

服务与活动通信

  • 在自定义的Service子类中,定义一个内部类,继承自Binder。在子类内部,定义给关联组件访问的接口方法。我把它比喻成电话线。
  • 实例化这个内部类,在onBind()方法中返回Binder子类实例。
    public IBinder onBind(Intent intent) {
    return downloadBinder;
    }
  • 在活动中,建造一条桥梁,创建一个ServiceConnection的匿名类,重写onServiceDisconnected()和onServiceConnected(),并在onServiceConnected()中得到Binder实例,即当桥梁架好后在onServiceConnected()可获得来自Service的电话线实例。
    private MyService.DownloadBinder downloadBinder;    private ServiceConnection serviceConnection=new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            downloadBinder=(MyService.DownloadBinder)service;        }        @Override        public void onServiceDisconnected(ComponentName name) {        }    };
  • 桥梁建好了,接下来就可调用bindService()和unbindService()绑定和解绑服务了,把桥梁架在Activity与Service之间。
                Intent bindIntent=new Intent(this,MyService.class);                bindService(bindIntent,serviceConnection,BIND_AUTO_CREATE);     //BIND_AUTO_CREATE表示绑定服务后自动启动服务
  • 接下来在活动中就可以调用返回的在Service内部的Binder子类实例的方法了。任何一个服务在整个应用程序都是通用的,它可以与其他活动绑定。不管服务是如何被创建的,它都允许客户绑定它。所以一个通过onStartCommand()方法启动的服务(started service)依然会收到onBind()调用(当客户调用了bindService())。

服务的生命周期

《第一行代码--Android》读书笔记之多线程与服务_第3张图片
活跃的生命时间,开始于onStartCommand()或onBind()函数被调用。如果是被启动的服务,他的活跃生命时间会和整个生命时间一同结束(在onStartCommand()函数返回后,服务依然是活跃状态)。如果是被绑定的服务,活跃生命时间会在onUnbind()函数返回后结束。当调用了startService()又去调用bindService()方法,要调用unbindService()和stopService()方法,onDestroy()方法才会执行。

服务的更多技巧

前台服务

如果希望服务一直保持运行状态,而不会由于系统的内存不足而被回收,可以考虑使用前台服务。
方法很简单,在Service的onCreate()方法中,使用通知(Notification),所不同的是调用startForground()启动通知。

    @Override    public void onCreate() {        super.onCreate();        Intent intent=new Intent(this,MainActivity.class);        PendingIntent pendingIntent=PendingIntent.getActivity(this,0,intent,0);        Notification notification=new Notification.Builder(this)                .setSmallIcon(R.mipmap.ic_launcher)                .setContentTitle("Front Service")                .setContentText("this is content")                .setWhen(System.currentTimeMillis())                .setContentIntent(pendingIntent)                .getNotification();        startForeground(1,notification);        Log.d("MyService","onCreate");    }

使用IntentService

不要被后台服务的后台所迷惑,其实服务中的代码都是默认运行渣主线程当中的,如果直接在服务中去处理一些耗时的逻辑就很容易出现ANR(Application Not Response)。
我们应该在服务的每个具体方法中开启一个子线程,在子线程中处理那些耗时的逻辑。
服务一旦启动之后,就会一直处于运行状态,必须调用StopService()或stopSelf()方法才能停止服务。为了方便创建一个异步的,会自动停止的服务,Android提供了一个IntentService类(方便的服务),它有点像Activity,能够响应intent,从onHandleIntent(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(String name) {        super(name);    }    public MyIntentService() {        super("MyIntentService");    }    @Override    protected void onHandleIntent(Intent intent) {        //子线程代码    }}

AlarmManager

AlarmManager是可以发送Intent的系统服务,既然是系统服务,当然调用(AlarmManager)getSystemService(ALARM_SERVICE);方法得到Manager实例啦。发送什么样的intent呢,我们使用PendingIntent打包Intent。
AlarmManager的set()方法可以设置一个定时任务。(涉及PendingIntent和BroadcastReceiver)

        Intent intent1=new Intent(this,AlarmReceiver.class);        PendingIntent pendingIntent=PendingIntent.getBroadcast(this,0,intent1,0);        AlarmManager alarmManager=(AlarmManager)getSystemService(ALARM_SERVICE);        long triggerAtTime= SystemClock.elapsedRealtime()+30*1000;       alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pendingIntent);

参考博客和文献:
Android管理服务(Service)的生命周期(lifecycle)
http://blog.csdn.net/oracleot/article/details/18818575

更多相关文章

  1. Android异步机制一:使用Thread+Handler实现非UI线程更新UI界面
  2. Android主线程消息循环
  3. 下载Android Sdk源码方法
  4. android 多任务多线程断点下载
  5. [Android]Thread线程入门3--多线程
  6. Android 自定义属性时TypedArray的使用方法
  7. Android TV 智能电视/盒子 APP 开发焦点控制 两种方法实例
  8. android v7包 正常导入使用方法

随机推荐

  1. android手机QQ界面设计
  2. android的消息处理机制(图+源码分析)——Lo
  3. Google Android操作系统内核编译图文教程
  4. Android(安卓)App开发基础篇—四大组件之
  5. Android网络收音机项目
  6. android:绘图
  7. Android快速入门(一):Android介绍
  8. Android(安卓)3.0发布了
  9. Android(安卓)源码解析-AsyncTask
  10. Android(安卓)HAL 开发 (1)