当前课程知识点:Android应用开发基础 >  第六章 Android服务 >  6.4 多线程 >  6.4 多线程

返回《Android应用开发基础》慕课在线视频课程列表

6.4 多线程在线视频

下一节:6.4.2 实践案例-MyService下载

返回《Android应用开发基础》慕课在线视频列表

6.4 多线程课程教案、知识点、字幕

本节我们介绍如何使多线程

应用程序启动后

系统会创建一个主线程 main thread

这个主线程负责向UI组件分发事件

主线程的应用

和Android的UI组件发生交互

所以主线程也称为UI线程

在UI线程中

如果做一些比较耗时的工作

比如访问网络或者数据库查询

都会阻塞UI线程

导致事件停止分发

用户体验感觉程序比较卡

没有反应

因此 主线程有两个原则

1 不要早应用程序中阻塞UI线程

2 不要在UI线程外访问UI组件

下面我们看一个

在UI线程中做一些比较耗时的工作

比如访问网络的实例

如图所示

比如常见的QQ登录程序

输入用户名和密码登录后

程序要访问服务器网络

由于需要从服务器下载好友列表

和一些消息

有时候网络速度也许不流畅

服务器的访问可能会比较耗时

如果在主线程中访问网络

会阻塞UI线程

程序会比较卡

用户体验就不好

怎么解决应用中的耗时问题呢

如图所示

android提供了多线程的模式

用新的线程myRun访问网络

但是它违反了主线程第二条原则

从非UI线程访问UI组件

会导致未定义和不能预料的行为

为了解决这个问题

Android提供了一些方法

实现其他线程访问UI线程

第一种方法是使用Handler机制

子线程获取子线程的Handler

将数据放入UI线程的消息队列

UI线程从消息队列中

获取消息后更新UI组件

这种方式的不足之处是代码冗余

子线程和UI线程需要耦合

第二种方法直接使用runOnUiThread机制

将子线程的内容放入runOnUiThread中

子线程在UI线程空闲的时候运行

这种机制的好处是代码简练

耦合度低

上一节我们学习了Service服务

那么服务是多线程吗

我们在服务的函数中使用Log标签

可以看到服务所处的线程

如图所示

通过Thread.currentThread().getId()

这个接口

可以看到日志

日志中可以看到

主视图MainActivity

与开启的服务Service的线程号是一致的

Service虽然在后台运行

但是服务与视图本质上处于同一个线程

如图所示

视图 服务以及服务启动的下载功能

本质上都还在同一个线程

如果在启动服务中

增加了一些耗时操作

如图所示

在服务的onStartCommand中

使用Thread.sleep(5000)阻塞线程5秒

结果如图所示

由于开始服务后

服务与主线程是同一个线程

服务最终会耗时5秒

UI主线程也阻塞了5秒

此时UI控件毫无反应

程序卡住了

因此

服务中不能完成耗时的操作

Android为了解决服务中

不能完成耗时的操作

引入了IntentService

支持异步任务的处理

如图所示

IntentService是继承并处理

异步请求的一个类

在IntentService内有一个工作线程

onHandleIntent来处理耗时操作

启动IntentService的方式

和启动传统的Service一样

同时

当任务执行完后

IntentService会自动停止

而不需要我们手动

或者去控制或stopSelf()去完成

另外

可以启动IntentService多次

而每一个耗时的操作

会以工作队列的方式

在IntentService的onHandleIntent

回调方法中执行

我们新建一个MyIntentService

继承于IntentService类

如图所示

在onHandleIntent方法中

使用Thread.sleep(5000)阻塞线程5秒

在主视图Activitiy中

启动MyIntentService

使用Thread.currentThread().getId()

获取主视图和服务的线程号

使用startService启动MyIntentService

Activitiy启动MyIntentService的效果

如图所示

在服务启动后

Activity与服务不在一个线程

onHandleIntent中

Thread.sleep(5000)耗时操作

并没有阻塞主线程

程序没有出现卡的现象

服务完成后自动注销

现在我们介绍AsyncTask

AsyncTask是一种轻量级的异步任务类

它可以在线程池中执行后台任务

然后把执行的进度和最终的结果

传递给主线程

并在主线程中更新UI

从实现上来说

AsyncTask封装了Thread和Handler

通过AsyncTask

可以更加方便的执行后台任务

以及在主线程中访问UI

但是不适合执行特别耗时的后台任务

对于特别耗时的任务来说

需要使用线程池

AsyncTask是一个抽象的泛型类

它提供了Params Progerss

和Result这三个泛型参数

其中Params表示参数的类型

Progress

表示后台任务执行进度的类型

而Result

则表示后台任务的返回结果的类型

如果不需要传递具体的参数

这三个泛型参数可以使用Void来代替

AsyncTask提供了4个核心方法

如图所示

onPreExecute ()

后台任务开始执行时调用

用于进行一些界面上的初始化操作

doInBackground

在子线程中运行

处理所有的耗时任务

onProgressUpdate

如果onPreExecute中调用了

publishProgress方法后

onPreExecute就会被调用

参数由后台任务中传递

可以对UI进行操作

利用参数中的数值

可以对界面元素进行相应的更新

onPostExecute

后台任务执行完后

通过return语句返回时被调用

返回的数据会作为参数传递到此方法中

可以利用返回的数据来进行UI操作

比如说提醒任务执行的结果

以及关闭掉进度条对话框等

下面我看一下AsyncTask的具体实现过程

我们新建一个MyAsyncTask

继承AsyncTask类

如图所示

AsyncTask的三个参数分别为

1 实现AsyncTask的onPreExecute

doInBackground

onPostExecute

onProgressUpdate的方法

并加上log标签

2 doInBackground中的参数strings

为启动MyAsyncTask的时候传入了参数

使用publishProgress后

会执行onProcessUpdate方法

3 onPostExecute参数args3

为doInBackground返回值

4 onProgressUpdate参数args2

为publishProgress返回值

AsyncTask启动方法如图所示

新建AsyncTask任务对象

使用AsyncTask的execute方法启动任务

并传入参数AsyncTask test1

我们最后看一下实现的AsyncTask效果

如图所示

MainActivity中启动AsyncTask

后台任务开始执行时

调用onPreExecute

在子线程中运行doInBackground

子线程中运行完publishProgress函数后

onProgressUpdate被调用

子线程结束后调用onPostExecute

这就是服务中使用多线程的例子

Android应用开发基础课程列表:

课程教案

-1 Android应用开发基础-课程标准

-2 Android应用开发基础-教案

第一章 Android概述

-讨论:Android应用开发基础资源下载地址

-讨论的问题:华为“鸿蒙系统”会取代安卓吗?

-Android Studio4.1.2安装常用问题汇总2021.3.15

-1.1 Android概述

--1.1 Android概述

--1.1 Android Studio安装与配置-实践案例

-1.1 Android概述--作业

-1.2 Android程序

--1.2 Android程序

--1.2 第一个Android应用程序-实践案例

-1.2 Android程序--作业

-1.3 Android程序调试

--1.3 Android程序调试

--1.3 Android程序调试-实践案例

-1.3 Android程序调试--作业

-讨论-完成第一个Android程序需要多长时间?

第二章 Android视图

-讨论-什么是Activity?

-2.1 Activity概述

--2.1 Activity概述

--2.1.1 实践案例-Activity生命周期

--2.1.2 实践案例-Activity跳转和数据传递

-2.1 Activity概述--作业

-2.2 Activity应用

--2.2 Activity应用

--2.2 实践案例-Activity四种启动模式

-第2章 Android视图--2.2 Activity应用

-讨论-怎么理解常用的四种启动模式?

第三章 Android组件

-讨论:Android在五个常用布局外还有哪几种布局方式?

-3.1 Activity布局

--3.1 Activity布局

--3.1 实践案例-Android布局

-3.1 Activity布局--作业

-3.2 Android基础组件

--3.2 Android基础组件

--3.2.1 实践案例-文本和按钮组件

--3.2.2 实践案例-编辑框和进度条组件

-3.2 Android基础组件--作业

-3.3 Android中级组件

--3.3 Android中级组件

--3.3.1 实践案例-复选框和开关组件

--3.3.2 实践案例-单选框和图像组件

-3.3 Android中级组件--作业

-3.4 Android适配器

--3.4.1 系统适配器

--3.4.2 自定义适配器

--3.4.1实践案例-系统适配器

--3.4.2 实践案例-自定义适配器

-3.4 Android适配器--作业

-讨论-如何解决Android的布局嵌套问题的?

第四章 Android Fragment

-讨论:Fragment的优点?

-4.1 Fragment碎片组件

--4.1.1 Fragment静态加载

--4.1.2 Fragment与Activity通讯

--4.1.3 Fragment动态加载

--4.1.1 实践案例-Fragment静态加载

--4.1.2 实践案例-Fragment的动态加载

-4.1 Fragment碎片组件--作业

-4.2 ViewPager翻页类组件

--4.2.1 ViewPager翻页类组件

--4.2.2 引导页和标题栏

--4.2 实践案例-引导页和选项卡

-4.2 ViewPager翻页类组件--作业

-讨论:fragment与activity的生命周期有哪些不同?

第五章 广播

-讨论:Android广播有什么作用?

-5.1 Android广播概述

--5.1 Android广播概述

--5.1.1 实践案例-手机电量显示

--5.1.2 实践案例-手机充电状态显示

-5.1 Android广播概述--作业

-5.2 Android广播工作原理

--5.2 Android广播工作原理

--5.2.1 实践案例-手机网络状态显示

--5.2.2 实践案例-短消息接收

-5.2 Android广播工作原理--作业

-5.3 自定义广播

--5.3 自定义广播

--5.3 实践案例-自定义广播与有序广播

-第5章 广播--5.3 自定义广播

-5.4 有序广播

--5.4有序广播

--5.4.2 实践案例-登录广播-记住密码

--5.4.2 实践案例-登录广播-强制退出

-第5章 广播--5.4 有序广播

-讨论:广播的动态注册和静态注册有什么区别?

第六章 Android服务

-讨论:Android的服务有什么作用?

-6.1 系统服务概述

--6.1 系统服务概述

-6.1 系统服务概述--作业

-6.2 访问系统服务

--6.2 访问系统服务

--6.2 实践案例-通知服务

-6.2 访问系统服务--作业

-6.3 自定义服务

--6.3 自定义服务

--6.3.1 实践案例-启动服务

--6.3.2 实践案例-绑定服务

--6.3.3 实践案例-后台服务

-第6章 Android服务--6.3 自定义服务

-6.4 多线程

--6.4 多线程

--6.4.2 实践案例-MyService下载

--6.4.3 实践案例-MyIntentService

--6.4.4 实践案例-AsyncTask实现对话框下载

--6.4.5 实践案例-下载精灵

-第6章 Android服务--6.4 多线程

-讨论:Android中怎么启动Service?

第七章 内容提供者ContentProvider

-讨论:ContentProvide的作用是什么?

-7.1 Android运行权限

--7.1 Android运行权限

--7.1 实践案例-拨打电话与发送短信

-7.1 Android运行权限--作业

-7.2 URL URI概述

--7.2 URL URI概述

-第7章 内容提供者ContentProvider--7.2 URL URI概述

-7.3 ContentProvider概述

--7.3 ContentProvider概述

--7.3 实践案例-读取联系人

-第7章 内容提供者ContentProvider--7.3 ContentProvider概述

-7.4 访问通讯录

--7.4 访问通讯录

--7.4.1 实践案例-读取通讯录

--7.4.2 实践案例-添加通讯录

--7.4.3 实践案例-删除更改通讯录

-第7章 内容提供者ContentProvider--7.4 访问通讯录

-7.5 课后作业案例

--7.5.1 实践案例-文件管理器-查看

--7.5.2 实践案例-文件管理器-播放

-讨论:ContentProvide如何使用?

第八章 多媒体

-讨论:Android多媒体主要应用于哪些场景?

-8.1 相机服务

--8.1 相机服务

--8.1.1实践案例-拍照服务

--8.1.2 实践案例-相册服务

-8.1 相机服务--作业

-8.2 音视频服务

--8.2 音视频服务

--8.2.1实践案例-音乐播放

--8.2.2 实践案例-视频播放

-8.2 音视频服务--作业

-讨论:Android视频组件的使用流程?

第九章 网络技术

-讨论:为什么使用Json作为网络的通讯格式?

-9.1 网络服务概述

--9.1 网络服务概述

--9.1 实践案例-WebView和Http服务

-9.1 网络服务概述--作业

-9.2 网络框架

--9.2 网络框架

--9.2 实践案例-okhttp框架

-9.2 网络框架--作业

-9.3 Json

--9.3 Json

--9.3 实践案例-json协议

-第9章 网络技术--9.3 Json

-9.4 Volley

--9.4 volley

--9.4 实践案例-volley框架

-第9章 网络技术--9.4 Volley

-讨论:OkHttp和Volley的有什么区别?

第十章 数据存储

-讨论:Android的存储方式有哪几种?

-10.1 文件存储

--10.1 文件存储

--10.1.1 实践案例-文件读写布局

--10.1.2 实践案例-文件读写

--10.1.3 实践案例-SharedPreference文件读写

-10.1 文件存储--作业

-10.2 数据库存储

--10.2 数据库存储

--10.2.1 实践案例-Sqlite数据库操作布局

--10.2.2 实践案例-Sqlite数据库操作

-10.2 数据库存储--作业

-讨论:SQLite的基础操作的流程是什么?

课程实训(不计入考核)

-第1章 实训简介以及开发环境配置

--实训项目简介PPT以及实训指导书

--1.1 实训项目简介

--1.2 项目开发环境配置

-第2章 在线音乐播放器整体设计以及服务端开发

--在线音乐播放器整体介绍PPT以及服务端开发实训指导书

--2.1 在线音乐播放器-整体设计

--2.2 在线音乐播放器-服务端开发

-第3章 在线音乐播放器-客户端开发

--3.1 客服端开发实训指导书以及PPT

--3.2 客户端开发-讲课视频

-第4章 在线音乐播放器-完整版

--4.1 实训指导书以及PPT

--4.2 在线音乐播放器-完整版授课视频

-第5章 QQ聊天项目

--5.1 实训指导书以及PPT

--5.2 QQ聊天项目授课视频

-第6章 在线点餐系统

--6.1 实训指导书以及PPT

--6.2 在线点餐系统授课视频

6.4 多线程笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。