Android核心基础-6.Android 耗时操作

2023-05-16

1.什么是ANR

  • 在应用程序的主线程中执行一段耗时的代码, 就有可能出现ANR异常.
  • 耗时的代码未执行结束时, 界面会卡住, 用户对界面进行了操作, 10秒之后耗时代码如果还未结束, 就会出现ANR异常

我们的布局文件中有个TextView和一个按钮Button

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0"
        android:textSize="30sp" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="go"
        android:text="GO" />

当点击Button按钮时触发go()函数,我们看到函数中执行了一个耗时操作,此时将出现界面卡死现象。

public void go(View v) {
    for (int i = 1; ; i++) {
        System.out.println(i);
        SystemClock.sleep(1000);
    }
}

2.怎么避免ANR

  • 主线程中不要执行耗时的代码
  • 如果一定要做耗时的事情, 开启新线程, 在新线程中执行

我们将耗时操作放置在一个线程中,那么界面就不会被卡死。

public void go(View v) {
    new Thread() {
        public void run() {
            for (int i = 1; ; i++) {
                System.out.println(i);
                SystemClock.sleep(1000);
            }
        }
    }.start();
}

3.UI Thread

  • 安卓手机中主线程负责刷新界面, 以及处理用户的操作
  • 应用程序的界面都是由主线程创建的
  • 界面的修改也只能在主线程中执行

4.Handler

有的时候我们需要执行一些耗时的代码, 会开启新线程, 这时又需要更新界面, 必须在主线程中操作, 那么就需要使用Handler来进行线程之间的通信

Handler工作流程图

4.1 sendMessage():

  • 新线程向主线程发送一个包含数据的消息, 主线程获取消息中的数据
  • 在主线程中创建Handler子类对象, 重写handleMessage()方法
  • 新线程中可以使用Handler的引用调用sendMessage()方法, 发送一个Message对象
  • 只要执行了sendMessage()方法, 那么主线程会自动执行handleMessage()方法, 收到Message对象

4.2 post():

  • 新线程向主线程发送一段代码, 主线程直接执行
  • 在主线程中创建Handler对象
  • 新线程中可以使用Handler调用post()方法发送一个Runnable对象
  • 主线程会自动执行Runable的run()

通过Handler发送Message通知主线程更新界面

public class SendMessageActivity extends Activity {

    private TextView tv;
    private Handler handler = new Handler(){
        public void handleMessage(Message msg) {    // 该方法在sendMessage()方法之后执行, 形参就是发送过来的Message对象
            tv.setText(msg.obj + "");               // 主线程更新界面
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv);  
    }

    public void go(View v) {
        new Thread() {
            public void run() {
                for (int i = 1; ; i++) {
                    // Message msg = new Message();         // 创建消息对象
                    Message msg = handler.obtainMessage();  // 从消息池中获取一个Message(比直接new效率要高)
                    msg.obj = i;                            // 把数据放在消息对象中
                    handler.sendMessage(msg);               // 在新线程中发送消息对象, 主线程会自动执行handleMessage()方法
                    System.out.println(i);
                    SystemClock.sleep(1000);
                }
            }
        }.start();
    }
}

课外知识:Message.obtain()和Handler.obtain()原理都一样,都是去消息池获取一个新的message对象。
但是Message的池全局性更高,两个线程同时使用到同一个的概率高;而Handler的范围相对要小点,指定了某一个Handler的Message对象。

直接通过post发送一段可执行代码更新界面

public class PostActivity extends Activity {

    private TextView tv;
    private Handler handler = new Handler();
    private int i;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv);  
    }

    public void go(View v) {
        System.out.println("go: " + Thread.currentThread().getName());
        new Thread() {
            public void run() {
                System.out.println("run: " + Thread.currentThread().getName());
                for (i = 1; ; i += 2) {
                    handler.post(new Runnable(){    // 在新线程中使用Handler向主线程发送一段代码, 主线程自动执行run()方法
                        public void run() {
                            System.out.println("Runnable: " + Thread.currentThread().getName());
                            tv.setText(i + "");
                        }
                    });

                    System.out.println(i);
                    SystemClock.sleep(1000);
                }
            }
        }.start();
    }
}

通过打印出来的log:
我们看到go: main, run: Thread-143, Runnable: main
表明post中的代码在主线程中执行的。

示例源代码->百度网盘

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android核心基础-6.Android 耗时操作 的相关文章

随机推荐

  • PCI中断处理

    首先在获得PCI配置空间资源的时候 xff0c 就要获得中断资源 xff0c 根据CM PARTIAL RESOURCE DESCRIPTOR 结构的 Type 域来区分需要获得什么样的中断资源的时候 xff0c 如果Type类型为 xff
  • VSCode常用快捷键

    快速复制一行 快捷键 xff1a shift 43 alt 43 下箭头 上箭头 或者 ctrl 43 c 然后 ctrl 43 v 选定多个相同的单词 快捷键 xff1a ctrl 43 d 先双击选定一个单词 xff0c 然后按下 ct
  • visca接口转RS-232C接口线序

  • Java迭代器详解,看这一篇就够了

    文章目录 x1f6a9 Java 迭代器详解 x1f4da 迭代器的定义 x1f4d2 认识Iterator 类结构图 Iterable接口 x1f58d Iterator接口 x1f4c3 Iterator接口的方法 x1f4d9 迭代器
  • 流式套接字实现简单的客户端/服务端通信过程

    一 实验内容 熟悉流式套接字socket函数的使用方法 xff0c 包括建立连接 数据发送 接收和关闭连接等 xff1b 客户端可向服务端发送任意字符串 xff0c 服务端在接收到该字 符串后 xff0c 回送给客户端 xff1b xff0
  • 实现基于 TCP/IP 协议简单的客户端、服务器通信程序实例

    本篇文章实现了一个基于TCP 的一个非常简单的客户 服务器通信程序实例 该程序中通讯协议使用的是面向连接的TCP协议SOCK STREAM 服务器的ip地址为本地地址即 xff1a 127 0 0 1 xff0c 端口号为自定义的5099
  • ARM:FreeRTOS系统栈和任务栈

    ARM xff1a FreeRTOS系统栈和任务栈 背景 xff1a ARM 有两个栈指针PSP和MSP xff0c 通过Control 寄存器来决定SP R13 使用哪个栈 我们下面谈论的系统栈和任务栈 xff0c 就和这两个栈指针有关
  • cmake编译时对‘xxxx‘未定义的引用问题

    众所周知 c c 43 43 编译过程中在链接阶段偶尔会出现 34 对 xxxx 未定义的引用 34 问题 在复杂的项目中更为常见 经查 大部分博主的关于这方面的博客千篇一律 都指出是头文件未包含的原因 我还是建议大家仔细阅读编译错误信息
  • 进制转换(C++):十六进制、二进制、十进制(附源代码)

    思路如下 xff1a 十进制转二进制 xff1a 除二求余 xff0c 得到低位到高位的二进制数字排列 十进制转八进制 xff1a 除八求余 xff0c 得到低位到高位的八进制数字排列 十进制转十六进制 xff1a 除十六取余 xff0c
  • [C/C++]C语言中math.h和cmath的pow()精度问题

    帮小朋友们DEBUG的时候 xff0c 他们有个题无论怎么提交OJ都不给过 我回来后想了想 xff0c 估计是因为math h库返回值转int时精度丢失的问题 gt 测试代码 include lt stdio h gt include lt
  • c语言自定义寄存器操作的一些方法

    1 寄存器地址的定义 xff1a define UART BASE ADRS 0x10000000 串口的基地址 define UART RHR volatile unsigned char UART BASE ADRS 43 0 数据接受
  • 数字签名-数字证书-ca认证

    数字签名是什么 xff1f 作者 xff1a 阮一峰 今天 xff0c 我读到一篇好文章 它用图片通俗易懂地解释了 xff0c 34 数字签名 34 xff08 digital signature xff09 和 34 数字证书 34 xf
  • Cocos2d-android游戏引擎-介绍

    一 游戏引擎概念 什么是游戏引擎 游戏引擎是指一些已编写好的可编辑游戏系统或者一些交互式实时图像应用程序的核心组件 这些系统为游戏设计者提供各种编写游戏所需的各种工具 xff0c 其目的在于让游戏设计者能容易和快速地做出游戏程式而不用由零开
  • JAVA语言的三种技术架构

    J2EE Java 2 Platform Enterprise Edition 企业版 是为开发企业环境下的应用程序提供的一套解决方案 该技术体系中包含的技术如Servlet Jsp等 xff0c 主要针对Web应用程序开发 J2SE Ja
  • java中数组排序Arrays.sort(arr)

    import java util 选择排序 class SwitchTest public static void main String args int arr 61 3 5 6 23 45 2 排序前 printArray arr 排
  • java中什么时候使用静态static,工具类的创建

    什么时候使用静态 xff1f 要从两方面下手 xff1a 因为静态修饰的内容有成员变量和函数 什么时候定义静态的变量 类变量 呢 xff1f 当对象中出现共享数据时 xff0c 该数据被静态所修饰 对象中的特有数据要定义成非静态存在于堆内存
  • java面向对象-包package-包与包之间访问-导入包import

    包 package 1 对类文件进行分类管理 2 给类提供多层命名空间 3 写在程序文件的第一行 4 类名的全称是 包名 类名 5 包也是一种封装形式 带包的java文件编译命令 编译 xff1a javac d PackageDemo j
  • String-练习3

    3 xff0c 获取一个字符串在另一个字符串中出现的次数 34 abkkcdkkefkkskk 34 思路 xff1a 1 xff0c 定义个计数器 2 xff0c 获取kk第一次出现的位置 3 xff0c 从第一次出现位置后剩余的字符串中
  • Java基础加强-java5的枚举

    枚举类 xff08 1 xff09 为什么需要枚举 xff1f 一些方法在运行时 xff0c 它需要的数据不能是任意的 xff0c 而必须是一定范围内的值 xff0c 此类问题在JDK5以前采用自定义带有枚举功能的类解决 xff0c Jav
  • Android核心基础-6.Android 耗时操作

    1 什么是ANR 在应用程序的主线程中执行一段耗时的代码 就有可能出现ANR异常 耗时的代码未执行结束时 界面会卡住 用户对界面进行了操作 10秒之后耗时代码如果还未结束 就会出现ANR异常 我们的布局文件中有个TextView和一个按钮B