首页 > 其他分享 >[Android] Handler 倒计时和界面更新

[Android] Handler 倒计时和界面更新

时间:2024-10-12 12:18:38浏览次数:3  
标签:task 倒计时 Handler UI 组件 线程 Android

问题

在 PlyRP 中需要在界面上实时显示目前媒体的时长/剩余时长,TimeTask 本身是一个子线程,但在 Android 的子线程去更新 UI 的内容,会导致不确定的异常。

在非 UI 线程中刷新界面的时候,UI 线程(或者其他非 UI 线程)也在刷新界面,这样就导致多个界面刷新的操作不能同步,导致线程不安全。

UI 线程及 Android 的单线程模型原则

当应用启动,系统会创建一个主线程(main thread)

这个主线程负责向 UI 组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和 Android 的 UI 组件(components from the Android UI toolkit (components from the android.widget and android.view packages))发生交互。

所以 main thread 也叫 UI thread 也即 UI 线程。

系统不会为每个组件单独创建线程,在同一个进程里的 UI 组件都会在 UI 线程里实例化,系统对每一个组件的调用都从 UI 线程分发出去。

结果就是,响应系统回调的方法(比如响应用户动作的 onKeyDown() 和各种生命周期回调)永远都是在 UI 线程里运行

Android 单线程模型的两条原则

当 App 做一些比较重(intensive)的工作的时候,除非你合理地实现,否则单线程模型的 performance 会很 poor。

特别的是,如果所有的工作都在 UI 线程,做一些比较耗时的工作比如访问网络或者数据库查询,都会阻塞 UI 线程,导致事件停止分发(包括绘制事件)。对于用户来说,应用看起来像是卡住了,更坏的情况是,如果 UI 线程 blocked 的时间太长(大约超过 5 秒),用户就会看到 ANR(application not responding)的对话框

另外,Andoid UI toolkit 并不是线程安全的,所以你不能从非 UI 线程来操纵 UI 组件。你必须把所有的 UI 操作放在 UI 线程里,所以 Android 的单线程模型有两条原则:

  1. 不要阻塞 UI 线程。
  2. 不要在 UI 线程之外访问 Android UI toolkit(主要是这两个包中的组件:android.view)。

方案

Android 提供了几种从其他线程访问主线程的方式:

  1. Activity.runOnUiThread(Runnable)还没写
  2. View.post(Runnable)还没写
  3. View.postDelayed(Runnable, long)还没写
  4. Handler

可以使用 Handler 机制主动进行信息的传递再更新,避免在主 UI 线程外更新界面导致的线程不安全。

Handler 是什么

handler 是 android 线程之间的消息机制,主要的作用是将一个任务切换到指定的线程中去执行(准确的说是切换到构成 handler 的 looper 所在的线程中去出处理),android 系统中的一个例子就是主线程中的所有操作都是通过主线程中的 handler 去处理的。

只有在 UI 线程中的对象才能操作 UI 线程中的对象,为了将非 UI 线程中的数据传送到 UI 线程,可以使用一个 Handler 运行在 UI 线程中。

Handler 是 Android framework 中管理线程的部分,一个 Handler 对象负责接收消息然后处理消息。

你可以为一个新的线程创建一个 Handler,也可以创建一个 Handler 然后将它和已有线程连接。

如果你将一个 Handler 和你的 UI 线程连接,处理消息的代码就将会在 UI 线程中执行。 具体可以看[3]

可以在你创建线程池的类的构造方法中实例化 Handler 的对象,然后用全局变量存储这个对象。

要和 UI 线程连接,实例化 Handler 的时候应该使用

当你用一个特定的 Handler 时,这个 Handler 就运行在这个在 Handler 中,要覆写会在 Handler 管理的相应线程收到新消息时调用这个方法。一个特定线程的所有 Handler 对象都会收到同样的方法。(这是一个“一对多”的关系)。

解决

问题以倒计时为例,构建的倒计时可以完成指定时间按指定时间间隔完成倒数。

必要定义

import java.util.Timer;
import java.util.TimerTask;

private int timecount = 0;
private TextView TimeText;

private Timer timer = null;
private TimerTask task = null;

必要初始化

TimeText = (TextView) findViewById(R.id.TimeText);

主体

若需要启动倒计时,调用 startTime(),同样,若需要停止计时,调用 stopTime()即可。

private Handler mHandler = new Handler(){
    public void handleMessage(Message msg) {
        TimeText.setText(msg.arg1+"");
        startTime();
    };
};

public void startTime(){
    timer = new Timer();
    task = new TimerTask() {
        @Override
        public void run() {
            i--;
            Message  message = mHandler.obtainMessage();
            message.arg1 = i;
            mHandler.sendMessage(message);
        }
    };
    timer.schedule(task, 1);
/*
java.util.Timer定时器的常用方法如下:
schedule(TimerTask task, long delay) // 延迟delay毫秒后,执行一次task。
schedule(TimerTask task, long delay, long period) // 延迟delay毫秒后,执行第一次task,然后每隔period毫秒执行一次task。
*/
}

public void stopTime(){
    timer.cancel();
}

声明

LocalWu 编写的文章。
文章内容仅供参考,遵循 CC 4.0 BY-SA 版权协议。

标签:task,倒计时,Handler,UI,组件,线程,Android
From: https://blog.csdn.net/qq_17440007/article/details/142873315

相关文章

  • Idea android应用kotlin-stdlib-1.8.20 kotlin-stdlib-jdk81.6.21冲突
    Ideaandroid应用kotlin-stdlib-1.8.20kotlin-stdlib-jdk81.6.21冲突idea中开发android应用,安装android插件后,新建项目,然后各种包更新,最后运行时提示kotlin-stdlib-1.8.20kotlin-stdlib-jdk8:1.6.21冲突错误如下:FAILURE:Buildfailedwithanexception.Whatwentwrong:......
  • 使用taro和react语言实现:微信小程序,地图中展示气泡,并在气泡中实现倒计时功能
    使用Taro和React来实现微信小程序中的地图气泡倒计时功能,你需要首先确保已经安装了TaroCLI并创建了一个Taro项目。接下来,我们将逐步实现这个功能。1.初始化Taro项目如果你还没有安装TaroCLI,可以使用npm或yarn进行安装:npminstall-g@tarojs/cli#或......
  • Android & iOS 使用 ARMS 用户体验监控(RUM)的最佳实践
    作者:元泊引言背景信息随着移动互联网技术的持续演进与全民互联网时代的深入,用户在Android、iOS应用程序、小程序、H5游戏及网页等多元化平台上的交互时长显著增长。这一趋势加剧了用户体验(UX)场景的复杂性,并对跨设备及多样网络环境下的性能监控提出了更高要求。在此背景下,深......
  • Android Studio添加依赖 新版 和 旧版 的添加方式(Gradle添加依赖)(Java)
    旧版的(在线添加)1找文件在项目的build.gradle文件中添加依赖(在下面的节点中添加库格式’组:名字:版本号‘)dependencies{implementation'com.example:library:1.0.0'}implementation‘组:名字:版本号’添加完成之后上方会出现如下图提示(点击现在同步)(Sy......
  • Android 11.0 第三方app授予DeviceOwner权限调用系统reboot,显示隐藏app,锁屏,禁用app
    1.前言 在11.0的系统rom定制化开发中,在有些客户开发app的功能中,需要系统授予app的DeviceOwner权限,然后app就可以实现重启关机禁用下拉通知栏,显示隐藏app,等功能,首选需要在app和framework中配置相关功能,接下来具体分析相关功能的实现2.第三方app授予DeviceOwner权限调用系统......
  • Android主流厂商云真机测试体验
    在Android平台下应用开发,机型适配是绕不开的话题,今天跟大家分享大厂商提供的云真机测试服务的使用体验。在我们开发分身产品空壳过程中,需要耗费大量的精力确保各厂商的设备稳定性,而针对主流手机厂商适配则是重中之重。以往我们需要外租对应的设备测试,耗资高,效率低,管理麻烦......
  • Android SELinux——Sepolicy基础语法(四)
           通过前面的文章内容,我们对 SELinux目录和te文件有一个初步的了解,这里我们继续研究Sepolicy的语法规范。一、Sepolicy语言介绍       Linux中有两种东西,一种死的(Inactive),一种活的(Active)。活的东西就是进程,而死的东西就是文件(Linux哲学,万物皆文......
  • Android SELinux——allow语句参数(五)
           通过上一篇文章我们知道,TE(TypeEnforcement,类型强制)的allow语句中主要包括主体(source)、对象(target)、类别(class)和权限(permissions),这里我们就来看一下其中的参数信息。一、参数详解1、主体        在SELinux的上下文中,主体类型source是指发起访......
  • 交叉编译c++给android调用
    NDK及其作用NDK(NativeDevelopmentKit)是一个由Google提供的工具集,用于在Android平台上开发C++或其他本机代码。NDK的主要作用是允许开发人员使用C、C++和其他本机语言编写代码,并将其编译为能够在Android设备上运行的本机代码(通常是共享库.so文件)。NDK的主要作用:......
  • AndroidSDK下载(不通过AndroidStudio)
    下载命令行工具在androiddeveloper滚动到Commandlinetoolsonly下载对应操作系统的命令行工具。笔者下载了windows版本的,其目录结构如下:└─cmdline-tools├─bin│apkanalyzer.bat│avdmanager.bat│lint.bat│profgen......