《第一行代码》读书笔记(三)

Author Avatar
wshunli 12月 27, 2017
  • 在其它设备中阅读本文章

《第一行代码》读书笔记 — 应用组件之 Service

《第一行代码》读书笔记(一)— 平台架构 (第1章)
《第一行代码》读书笔记(二)— 应用组件之 Activity (第2、4章)
《第一行代码》读书笔记(三)— 应用组件之 Service (第10章)
《第一行代码》读书笔记(四)— 应用组件之 BroadcastReceiver (第5章)
《第一行代码》读书笔记(五)— 应用组件之 ContentProvider (第7章)
《第一行代码》读书笔记(六)— 数据存储方案 (第6章)
《第一行代码》读书笔记(七)— 多媒体资源 (第8章)
《第一行代码》读书笔记(八)— 网络编程 (第9章)

第10章 后台默默的劳动者

Service 是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。

服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。

Android 多线程编程

Android 多线程 和 Java 多线程基本相同。

定义一个线程只需要新建一个类继承自 Thread 或者 实现 Runnable 接口,然后重写或者实现 run() 方法。

new Thread(new Runnable() {
    @Override
    public void run() {
      // 异步操作
    }
}).start();

1、Service 与 Thread 的区别:

Service 是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。
服务在其托管进程的主线程中运行,它既不创建自己的线程,也不在单独的进程中运行(除非另行指定)。
Thread 是程序执行的最小单元,可以用 Thread 来执行一些异步的操作。

http://blog.csdn.net/wei_chong_chong/article/details/52251193

2、在子线程中更新 UI

(1) Activity 的 runOnUiThread() 方法

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        // 更新 UI 操作
    }
});

(2) View.post(Runnable r)

textView.post(new Runnable() {
    @Override
    public void run() {
        // 更新 UI 操作
    }
});

其中 textView 可替换为其他 View 。

(3) Handler

新建 Handler 对象,重写 handleMessage() 方法,对 Message 进行处理。

private Handler handler = new Handler() {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case UPDATE_TEXT:
                textView.setText("Nice to meet you!");
        }
    }
};

在子线程中使用 Hander 对象发送 Message 对象即可。

Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message);

3、异步消息处理机制

Message:消息,其中包含了消息ID,消息处理对象及处理的数据等,由MessageQueue统一列队,终由 Handler 处理。
Handler:处理者,负责 Message 的发送及处理。使用 Handler 时,需要实现 handleMessage(Message msg) 方法来对特定的 Message 进行处理,例如更新 UI 等。
MessageQueue:消息队列,用来存放 Handler 发送过来的消息,并按照 FIFO 规则执行。当然,存放 Message 并非实际意义的保存,而是将 Message 以链表的方式串联起来的,等待 Looper 的抽取。
Looper:消息泵,不断地从 MessageQueue 中抽取 Message 执行。因此,一个 MessageQueue 需要一个 Looper。

Handler 的工作机制简单来说是这样的:

首先在主线程中新建 Handler 对象,并重写 handleMessage() 方法。然后当子线程中想更新 UI 时,就创建一个 Message 对象,并通过 Handler 将消息发送出去。之后消息会被添加到 MessageQueue 中等待被处理,而 Looper 则会一直尝试从 MessageQueue 中取出待处理的消息,最后分发回 Handler 的 handlerMessage() 方法中。

Handler

https://www.jianshu.com/p/9e4d1fab0f36
http://blog.csdn.net/guolin_blog/article/details/9991569

4、AsyncTask 的基本用法

AsyncTask 是一个抽象类,我们创建一个子类继承它。

AsyncTask 可以指定三个泛型参数:

(1) Params,在执行 AsyncTask 时需要传入的参数。
(2) Progress,后台计算过程中的进度单元类型。
(3) Result,后台运行的结果类型。

private class AsyncTaskDemo extends AsyncTask<Void, Integer, Boolean> {

    @Override
    protected Boolean doInBackground(Void... voids) {
        return true;
    }
}

AsyncTask 常用的方法:

onPreExecute() 此方法会在后台任务执行前被调用,用于进行一些准备工作。
doInBackground(Params… params) 此方法中定义要执行的后台任务,在这个方法中可以调用 publishProgress() 来更新任务进度(publishProgress 内部会调用 onProgressUpdate 方法)。
onProgressUpdate(Progress… values) 由 publishProgress() 内部调用,表示任务进度更新。
onPostExecute(Result result) 后台任务执行完毕后,此方法会被调用,参数即为后台任务的返回结果。
onCancelled() 此方法会在后台任务被取消时被调用。

服务的基本用法

创建服务

要创建服务,您必须创建 Service 的子类(或使用它的一个现有子类),并且在使用清单文件声明服务。

public class HelloService extends Service {
    public HelloService() {
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

启动及停止服务

通过将 Intent(指定要启动的服务)传递给 startService(),从 Activity 或其他应用组件启动服务。Android 系统调用服务的 onStartCommand() 方法,并向其传递 Intent。(切勿直接调用 onStartCommand()。)

Intent intent = new Intent(this, HelloService.class);
startService(intent);

服务必须通过调用 stopSelf() 自行停止运行,或者由另一个组件通过调用 stopService() 来停止它。
一旦请求使用 stopSelf() 或 stopService() 停止服务,系统就会尽快销毁服务。

Intent intent = new Intent(this, HelloService.class);
stopService(intent);

活动与服务进行通信

Activity 与 Service 进行通信可以通过创建 Binder 对象来实现。

创建 Bindler 的子类,然后在内部提供自定义的方法,在 Service 的 onBind() 方法中返回 Bindler 对象。

public class HelloService extends Service {

    private static final String TAG = "HelloService";
    private DownloadBinder mBinder = new DownloadBinder();

    public HelloService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return mBinder;
    }

    class DownloadBinder extends Binder {
        public void startDownlaod() {
            Log.d(TAG, "startDownlaod: ");
        }

        public int getProgress() {
            Log.d(TAG, "getProgress: ");
            return 0;
        }
    }
}

然后 绑定 Activity 和 Service ,就可以调用 Binder 提供的方法了。

1、首先创建 ServiceConnection 的匿名类,重写方法。

private HelloService.DownloadBinder downloadBinder;
private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        downloadBinder = (HelloService.DownloadBinder) iBinder;
        downloadBinder.startDownlaod();
        downloadBinder.getProgress();
    }
    @Override
    public void onServiceDisconnected(ComponentName componentName) {

    }
};

2、然后使用 bindService() 方法绑定 Service 。

bindService(new Intent(this, MyService.class), connection, BIND_AUTO_CREATE);

服务的声明周期

服务生命周期(从创建到销毁)可以遵循两条不同的路径:

  • 启动服务

该服务在其他组件调用 startService() 时创建,然后无限期运行,且必须通过调用 stopSelf() 来自行停止运行。此外,其他组件也可以通过调用 stopService() 来停止服务。服务停止后,系统会将其销毁。

  • 绑定服务

该服务在另一个组件(客户端)调用 bindService() 时创建。然后,客户端通过 IBinder 接口与服务进行通信。客户端可以通过调用 unbindService() 关闭连接。

3.service_lifecycle

前台服务

前台服务被认为是用户主动意识到的一种服务,因此在内存不足时,系统也不会考虑将其终止。 前台服务必须为状态栏提供通知,放在“正在进行”标题下方,这意味着除非服务停止或从前台移除,否则不能清除通知。

要请求让服务运行于前台,在 Service 中调用 startForeground()。此方法采用两个参数:唯一标识通知的整型数和状态栏的 Notification。例如:

Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text), System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);

IntentService

IntentService 是一种异步的、可以自动停止的服务。

IntentService 执行以下操作:

  • 创建默认的工作线程,用于在应用的主线程外执行传递给 onStartCommand() 的所有 Intent。
  • 创建工作队列,用于将 Intent 逐一传递给 onHandleIntent() 实现,这样您就永远不必担心多线程问题。
  • 在处理完所有启动请求后停止服务,因此您永远不必调用 stopSelf()。
  • 提供 onBind() 的默认实现(返回 null)。
  • 提供 onStartCommand() 的默认实现,可将 Intent 依次发送到工作队列和 onHandleIntent() 实现。

综上所述,您只需实现 onHandleIntent() 来完成客户端提供的工作即可。

public class HelloIntentService extends IntentService {

  /**
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * The IntentService calls this method from the default worker thread with
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // Normally we would do some work here, like download a file.
      // For our sample, we just sleep for 5 seconds.
      try {
          Thread.sleep(5000);
      } catch (InterruptedException e) {
          // Restore interrupt status.
          Thread.currentThread().interrupt();
      }
  }
}

参考资料
1、Service | Android Developers
https://developer.android.com/guide/components/services.html
2、Service与Thread区别 - CSDN博客
http://blog.csdn.net/wei_chong_chong/article/details/52251193
3、android的消息机制——Handler机制 - 简书
https://www.jianshu.com/p/9e4d1fab0f36
4、Android异步消息处理机制完全解析,带你从源码的角度彻底理解 - CSDN博客
http://blog.csdn.net/guolin_blog/article/details/9991569

如果本文对您有所帮助,且您手头还很宽裕,欢迎打赏赞助我,以支付网站服务器和域名费用。 https://paypal.me/wshunli 您的鼓励与支持是我更新的最大动力,我会铭记于心,倾于博客。
本文链接:https://www.wshunli.com/posts/fba26489.html