7.服务

1.多线程

1.1

启动多线程的两种方法:
1.class MyThread extends Thread {
@Override
    public void run() {
    // 处理具体的逻辑
    }
}

new MyThread.start();

2.class MyThread implements Runnable{
    @Override
    public void run() {
    // 处理具体的逻辑
    }
}

MyThread myThread = new MyThread();
new Thread(myThread).start();

或者匿名内部类:
new Thread(new Runnable{
    @Override
    public void run() {
    // 处理具体的逻辑
    }
}).start();

1.2.子线程中更新UI

不能直接在子线程中更改UI,可以通过异步消息处理机制。
//重写handleMessage()方法对接受的message进行处理
private Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what){
            case CHANGE_TEXT:
                text.setText("I am MQ");
        }
    }
};
//在点击事件中发送一条带信息的message
public void onClick(View view) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            Message message = new Message();
            message.what = CHANGE_TEXT;
            handler.sendMessage(message);
        }
    }).start();

}

1.3.解析异步消息处理机制

1. Message
Message 是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线
程之间交换数据。上一小节中我们使用到了Message 的what 字段,除此之外还可以使
用arg1 和arg2 字段来携带一些整型数据,使用obj 字段携带一个Object 对象。
2. Handler
Handler 顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消
息一般是使用Handler 的sendMessage()方法,而发出的消息经过一系列地辗转处理后,
最终会传递到Handler 的handleMessage()方法中。
3. MessageQueue
MessageQueue 是消息队列的意思,它主要用于存放所有通过Handler 发送的消息。
这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue
对象。
4. Looper
Looper 是每个线程中的MessageQueue 的管家,调用Looper 的loop()方法后,就会
进入到一个无限循环当中,然后每当发现MessageQueue 中存在一条消息,就会将它取
出,并传递到Handler 的handleMessage()方法中。每个线程中也只会有一个Looper 对象。

消息处理的流程:

Handler发送Message,在MessageQueue中等待,Looper把消息从MessageQueue中取出,
回调dispatchMessage()方法,发回Handler的handleMessage()方法中进行处理

1.4AsyncTask

创建一个类来继承AsyncTask类,继承时可以指定三个泛型参数:

1. Params
在执行AsyncTask 时需要传入的参数,可用于在后台任务中使用。
2. Progress
后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为
进度单位。
3. Result
当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
ex:class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
        ……
    }

并重写4个方法:

1. onPreExecute()
这个方法会在后台任务开始执行之前调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。
2. doInBackground(Params...)
这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务一旦完成就可以通过return 语句来将任务的执行结果返回,如果AsyncTask的
第三个泛型参数指定的是Void,就可以不返回任务执行结果。注意,在这个方法中是不
可以进行UI 操作的,如果需要更新UI 元素,比如说反馈当前任务的执行进度,可以调
用publishProgress(Progress...)方法来完成。
3. onProgressUpdate(Progress...)
当在后台任务中调用了publishProgress(Progress...)方法后,这个方法就会很快被调
用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI 进行操
作,利用参数中的数值就可以对界面元素进行相应地更新。
4. onPostExecute(Result)
当后台任务执行完毕并通过return 语句进行返回时,这个方法就很快会被调用。返
回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI 操作,比如
说提醒任务执行的结果,以及关闭掉进度条对话框等。

2.服务

新建一个类继承Service类,重写方法:

onCreate()方法会在服务创建的时候调用,
onStartCommand()方法会在每次服务启动的时候调用,
onDestroy()方法会在服务销毁的时候调用。
onBind()将你打包的Binder对象返回给Activity

3.活动和服务进行通信

//在Service的子类中,把你想要实现的封装到Binder的子类对象中,并用onBind()方法返回
class DownloadBinder extends Binder{
    public void startDownload(){
        Log.d("DownloadBinder","startDownload");
    }


    public void getProgress(){
        Log.d("DownloadBinder","getProgress");
    }
}

//在MainActivity中创建ServiceConnection对象,接受返回的对象
ServiceConnection serviceConnection = new ServiceConnection() {

    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        downloadBinder = (MyService.DownloadBinder) iBinder;
        downloadBinder.startDownload();
        downloadBinder.getProgress();
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {

    }
};
//调用bindService()和unbindService()方法让服务与活动绑定起来
Intent intent = new Intent(this,MyService.class);
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
unbindService(serviceConnection);

4.服务的生命周期

一旦在项目的任何位置调用了Context 的startService()方法,相应的服务就会启动起来,
并回调onStartCommand()方法。如果这个服务之前还没有创建过,onCreate()方法会先于
onStartCommand()方法执行。服务启动了之后会一直保持运行状态,直到stopService()或
stopSelf()方法被调用。注意虽然每调用一次startService()方法,onStartCommand()就会执行
一次,但实际上每个服务都只会存在一个实例。所以不管你调用了多少次startService()方法,
只需调用一次stopService()或stopSelf()方法,服务就会停止下来了。
另外,还可以调用Context 的bindService()来获取一个服务的持久连接,这时就会回调
服务中的onBind()方法。类似地,如果这个服务之前还没有创建过,onCreate()方法会先于
onBind()方法执行。之后,调用方可以获取到onBind()方法里返回的IBinder 对象的实例,这
样就能自由地和服务进行通信了。只要调用方和服务之间的连接没有断开,服务就会一直保
持运行状态。
当调用了startService()方法后,又去调用stopService()方法,这时服务中的onDestroy()
方法就会执行,表示服务已经销毁了。类似地,当调用了bindService()方法后,又去调用
unbindService()方法,onDestroy()方法也会执行,这两种情况都很好理解。但是需要注意,
我们是完全有可能对一个服务既调用了startService()方法,又调用了bindService()方法的,
这种情况下该如何才能让服务销毁掉呢?根据Android 系统的机制,一个服务只要被启动或
者被绑定了之后,就会一直处于运行状态,必须要让以上两种条件同时不满足,服务才能被
销毁。所以,这种情况下要同时调用stopService()和unbindService()方法,onDestroy()方法才会执行。

5.服务的更多技巧

5.1前台服务

在onCreate()方法中创建一个通知,最后调用startForeground()方法启动通知。

5.2IntentService

异步的、会自动停止的服务,多线程的服务
这里首先是要提供一个无参的构造函数,并且必须在其内部调用父类的有参构造函数。
然后要在子类中去实现onHandleIntent()这个抽象方法

6.Alarm机制计时

//获取AlarmManager实例对象
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
//调用set()方法设置定时任务
long triggerAtTime = SystemClock.elapsedRealtime() + 10 * 1000;
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent);

第一个参数是一个整型参数,用于指定AlarmManager 的
工作类型,有四种值可选,分别是
ELAPSED_REALTIME:   定时任务的触发时间从系统开机开始算起
ELAPSED_REALTIME:_WAKEUP    定时任务的触发时间从系统开机开始算起并唤醒CUP
RTC:    定时任务的触发时间从1970 年1月1日0点开始算起
RTC_WAKEUP: 定时任务的触发时间从1970年1月1日0点开始算起并唤醒CUP
使用SystemClock.elapsedRealtime()方法可以获取到系统开机至今所经历时间的毫秒数
使用System.currentTimeMillis()方法可以获取到1970 年1 月1 日0 点至今所经历时间的毫秒数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值