Android笔记分享

本文介绍了作者今日的学习内容,包括使用runOnUiThread控制界面、工作管理器WorkManager的运用、移动数据格式JSON的处理以及HTTP接口的okhttp调用。解决了post操作的问题,并概述了AndroidUI更新机制和后台任务的管理。
摘要由CSDN通过智能技术生成

今日计划:

1.学习runOnUiThread来快速操控界面

2.学习工作管理器WorkManager

3.学习Http访问的移动数据格式JSON

4.学习okhttp调用HTTP接口

上周五遗留问题已解决,见Day28

那么有了新的问题:

点击暂停后再次点击开始会闪退,下面这行报错:

thread.start();

一个线程在创建的时候会指定一个线程任务,当执行完这个线程任务之后,线程自动销毁。

那么点完暂停他应该就销毁了

去看了作者源码,发现它重写了一个类继承Thread并重写run方法,这样使用的时候直接类名+start

所以我认为是第一次销毁之后没办法再初始化了

我的方法:

Thread thread = initThread();

thread.start();

把原来初始化thread封装到方法里然后用的时候调用

成功解决

新的问题:post可以修改UI吗

可以实现

还有一个问题:

为什么setText没有成功执行

textView.setText(news);

while (true){

long i = -99999999;

while (i < 555555555){

i++;

}

String word = Util.getNowTime() + "这是主线程的消息"+"\n";

news += word;

Log.d(TAG, "onClick: "+ word);

textView.setText(news);

}

界面刷新是异步的,需要时间,也需要占用CPU的,死循环把CPU占用了

当一个TextView的实例调用setText()方法后,会执行以下步骤:

  1. 更新TextView的内部存储的文本内容。

  2. 调用requestLayout()方法,请求重新测量TextView的大小。

  3. 在下一个绘制周期中,系统会调用TextView的onMeasure()方法,确定TextView的大小。

  4. 然后,系统会调用TextView的onLayout()方法,确定TextView的位置。

  5. 最后,系统会调用TextView的onDraw()方法,绘制TextView的文本内容。

这是Android View绘制流程中TextView更新文本内容后的简要描述。

据此我想理解掌握TextView刷新的过程,到底怎么刷新的

于是找到了:

Android 绘制流程(从Activity创建 -> 内容展示)

由此找到了

ActivityThread的理解和APP的启动过程

然后又找到了:

Looper与Handler机制

大概的流程如上图所示,具体的细节我们结合源代码进行分析。思路是这样的:

  • 消费者部分:我们先从程序的入口开始,看看Looper循环是如何初始化和开始循环的,它如何获得消息,如何对消息进行处理。

  • 生产者部分:我们以自己平时是如何生产消息为例子,然后分析消息是如何推入队列的。

  • 消息队列:MessageQueue,消息队列并不会按照顺序单独分为一个部分来讲解,因为它的逻辑是糅合在生产-消费的过程中的。所以只要把上面的部分理解了,消息队列的部分自然就理解了。这里我们可以先补充一些概念:

    • 消息队列是用链表实现的

    • 它包含了数据、对应的Handler、期待它被处理的时间

Handler处理信息的优先级:

  • 1.callback:优先级最高,这是一个Runable,当我们调用post(Runable r)时其实就是用这个变量。

  • 2.mCallback:优先级次之,我们在初始化Handler时可以传进去:

    它是一个Callback接口,只有一个方法:handleMessage(@NonNull Message msg)

    注意:if (mCallback.handleMessage(msg)) { return; },所以当该接口返回true时则不希望Handler.handleMessage()再进行处理。

  • 3.handleMessage():优先级最低,我们继承该Handler时,通过重写该方法来处理消息。在Handler中默认不作任何处理:

在performLaunchActivity方法中,可以看到:

  • 执行了Activity所属Context的真正执行类ContextImpl的创建

  • 创建完了Activity之后,在Instrumentation中通过newInstance方式,反射创建了Activity

  • 创建完Activity之后,在onCreate方法执行之前先调用了关键方法:attach

  • 在执行完attach方法后,通过层层调用,最终执行Activity的onCreate生命周期方法

执行流程: performLaunchActivity - >  Activity创建    ->     Activtiy.attach    ->    Activity.onCreate

在performLaunchActivity的过程中,先后执行了

1.Activity创建

2.Activity的attch

  • 创建了PhoneWindow以及对应的WindowManager

3.Activity的onCreate

  • 执行setContentView,完成了DerView的创建

在performLaunchActivity过程中,完成Activity中设置resId对应的布局文件的从DecorView到最后子View的加载(过程中涉及xml解析,递归以及反射,详细细节可以看看这篇,但到Activity的onCreate位置,视图还并未显示,需要再执行performResumeActivity方式。

在handleResumeActivity之前,DecorView已经被创建但未绘制,在handleResumeActivity中,先执行了onResume生命周期,后创建了ViewRootImpl作为DecorView的父类,配置Choreography进行刷新以及ViewTree的绘制工作。

由此可见:

在Activity首次创建的过程中,在执行onResume生命周期时,控件树已经被创建,即我们可以通过findViewById获取到UI控件,但这个时期,内容并未展示,而是去向系统申请刷新信号,当信号到来之时,才进行绘制(measure,layout,draw)工作。

在performLaunchActivity到handleResumeActivity的过程中,先后执行了

1.Activity创建

2.Activity的attch

  • 创建了PhoneWindow以及对应的WindowManager

3.Activity的onCreate

  • 执行setContentView,完成了DerView的创建 4.Activity的onResume

5.WindowMananger.addView

  • 创建ViewRootImpl,并将DecorView传入

  • 通过Choreography申请刷新信号 6.VSync刷新信号到来

  • ViewRootImpl执行performTraversals

  • ViewTree控件树,执行measure,layout,draw方法

其中draw方法会根据是否开启硬件加速有多种实现机制。

13.1.2 通过runOnUiThread快速操纵界面

分线程若想操纵界面控件,在线程内部调用runOnThread方法即可

调用代码如下:

//回到主线程(UI线程)操作界面

runOnUiThread(new Runnable(){

@Override

public void run (){

//操作界面的代码放在这里

}

});

Runnable属于函数式接口可简化为:

runOnUiThread(()->{

});

如果Runnable的运行代码只有一行,那么Lambda允许进一步简化,也就是省略外面的花括号

runOnUiThread(()->/*如果只有一行代码,那么连花括号也可省掉*/)

new Thread(new Runnable() {

@Override

public void run() {

while (isSend){

String word = newsArray[ new Random().nextInt(6)];

Log.d(TAG, "run: "+word);

news += word+"\n";

runOnUiThread(new Runnable() {

@Override

public void run() {

textView.setText(news);

}

});

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

throw new RuntimeException(e);

}

}

}

}).start();

13.1.3 工作管理器WorkManager

对于后台的异步服务,官方建议改为使用工作管理器WorkManager

继承Worker的工作者重写的doWork方法运行于分线程,因此该方法内部不能操作界面控件

在活动页面构建并启动工作任务,详细过程分为下列四个步骤:

1.构建约束条件

该步骤说明在哪些情况下才能执行后台任务,也就是运行后台任务的前提条件,此时用到了约束工具Constraints

2.构建输入数据

该步骤吧后台任务需要的参数封装到一个数据对象中,此时用到了数据工具Data

3.构建工作请求

该步骤把约束条件、输入数据等请求内容组装起来,此时用到了工作请求工具OneTimeWorkRequest

4.执行工作请求

该步骤生成工作管理器实例,并将步骤3的工作请求对象加入管理器的执行队列中,由于管理器调度并执行请求任务

工作管理器不止拥有enqueue方法,还有其他的调度方法,常用的几个方法:

enqueue:将文件请求加入执行队列

cancelWorkById:取消指定编号(步骤3getId方法返回的workId)的工作

cancelAllWorkByTag:取消指定标签(步骤3getId方法返回的workId)的工作

cancelAllWork:取消所有工作

getWorkInfoByIdLiveData:获取指定编号的工作信息

后台工作是异步执行的,若想知晓工作任务的处理结果,就得调用getWorkInfoByIdLiveData方法

获取工作信息并实时监听他的运行情况

// 周期性任务的观察器实际无法操纵界面,因为周期任务一直在“执行”与“等待”之间切换,不会结束处理

workManager.getWorkInfoByIdLiveData(workId).observe(this, workInfo -> {

Log.d(TAG, "workInfo:" + workInfo.toString());

if (workInfo.getState() == WorkInfo.State.SUCCEEDED) { // 该分支永远都进不去

Data outputData = workInfo.getOutputData(); // 获得工作信息的输出数据

int resultCode = outputData.getInt("resultCode", 0);

String resultDesc = outputData.getString("resultDesc");

String desc = String.format("%s resultCode=%d,resultDesc=%s",

DateUtil.getNowTime(), resultCode, resultDesc);

tv_result.setText(desc);

}

});

13.2 HTTP访问:

1.学习如何利用移动数据格式JSON封装结构信息

2.学习如何从JSON串解析获得结构对象

3.学习okhttp调用HTTP接口的三种方式(GET方式、表单格式的POST请求、JSON格式的POST请求)

4.学习使用okhttp下载网络文件

5.将本队文件上传到服务器

13.2.1 移动数据格式JSON

网络通信的交互数据格式有两大类:JSON和XML

JSON的基本格式:

1.整个JSON串由一对花括号包裹,并且内部的每个结构都以花括号包起来

2.参数格式类似键值对,其中键名与键值之间以冒号分隔

3.两个键值对之间以逗号分隔

4.键名需要用双引号引起来,键值为数字的话无需双引号,为字符串的话仍需双引号

5.JSON数组通过方括号表达,方括号内部依次罗列各个元素,具体格式形如“数组的键名:[元素1,元素2,元素3]”

针对JSPN字符串,Android提供了JSON解析工具,支持对JSONObject(JSON对象)和JSOnArray(JSON数组)的解析处理

1.JSONObjet

常用方法:

今日总结:

1.解决了上周遗留的post(thread)问题

2.学习了使用runOnUiThread快速操纵界面

3.学习了工作管理器WorkManager

4.学习在活动页面构建并启动工作任务的四个步骤

5.学习了移动数据格式JSON

6.学习了使用Gson库转换JSON数据

明日计划:

1.学习okhttp调用HTTP接口的三种方式

2.学习利用Glide实现图片的三级缓存

3.学习使用Glide加载特殊图像

4.学习通过SocketIO传输文本消息和图片消息

  • 20
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值