设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间20 现在时间20 缓存数据 和聪明人交流,和靠谱的人恋爱,和进取的人共事,和幽默的人随行。晚安!

和聪明人交流,和靠谱的人恋爱,和进取的人共事,和幽默的人随行。晚安!

查看: 959|回复: 1

Android实现界面定时刷新功能

[复制链接]

  离线 

TA的专栏

  • 打卡等级:即来则安
  • 打卡总天数:18
  • 打卡月天数:0
  • 打卡总奖励:349
  • 最近打卡:2025-01-21 00:12:29
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
34
主题
26
精华
0
金钱
454
积分
74
注册时间
2023-8-12
最后登录
2025-9-8

发表于 2025-9-8 12:59:21 | 显示全部楼层 |阅读模式
一、项目介绍

在移动应用中,界面定时刷新是非常常见的需求,典型场景包括:

  • 时钟/秒表:每秒更新显示当前时间或计时;
  • 实时数据监控:定期拉取服务器状态或传感器数据并更新 UI;
  • 列表自动刷新:如新闻、社交Feeds 定时刷新最新内容;
  • 倒计时:在促销、考试倒计时场景下每秒更新剩余时长;
  • 游戏逻辑刷新:简单动画或状态轮询。
本教程将以一个“实时时钟”示例为主线,演示多种常用的定时刷新的实现方式:

  • 方案 A:Handler + postDelayed
  • 方案 B:Timer + Handler
  • 方案 C:ScheduledExecutorService
  • 方案 D:RxJava interval
  • 方案 E:Kotlin Coroutines + Flow
并对比它们的代码简洁度性能消耗生命周期管理取消机制,帮助您在项目中快速选型并上手。

二、相关技术与知识


  • 主线程与 UI 更新

    • Android 要求所有 UI 操作必须在主线程(UI 线程)中执行。
    • 定时任务若在子线程中执行,需要切回主线程使用
      1. runOnUiThread()
      复制代码
      1. Handler
      复制代码


  • Handler & Looper

      1. Handler
      复制代码
      :将
      1. Runnable
      复制代码
      1. Message
      复制代码
      发布到所绑定的
      1. Looper
      复制代码
      (线程消息队列)。
      1. postDelayed(Runnable r, long delayMillis)
      复制代码
      :延迟执行任务。

  • Timer & TimerTask

      1. Timer
      复制代码
      用于安排
      1. TimerTask
      复制代码
      在后台线程周期或延迟执行;
    • 结果需要通过
      1. Handler
      复制代码
      1. runOnUiThread()
      复制代码
      回到主线程。

  • ScheduledExecutorService

    • Java 标准库:
      1. Executors.newSingleThreadScheduledExecutor()
      复制代码
      可定期执行任务,支持
      1. scheduleAtFixedRate()
      复制代码


  • RxJava

      1. Observable.interval()
      复制代码
      :基于 Scheduler 定时发射 Long 值,结合
      1. observeOn(AndroidSchedulers.mainThread())
      复制代码
      更新 UI。

  • Kotlin Coroutines & Flow

      1. flow { while(true) { emit(Unit); delay(1000) } }
      复制代码
      :使用协程轻量定时;
      1. lifecycleScope.launchWhenStarted
      复制代码
      中收集并更新 UI。

  • 生命周期管理与取消

    • 定时任务应在
      1. Activity.onPause()
      复制代码
      /
      1. onDestroy()
      复制代码
      中取消,避免内存泄漏与后台无用计算;
    • 不同方案的取消方式也不同:
      1. Handler.removeCallbacks()
      复制代码
      1. timer.cancel()
      复制代码
      1. future.cancel()
      复制代码
      ,
      1. disposable.dispose()
      复制代码
      1. job.cancel()
      复制代码
      等。


三、实现思路


  • 示例界面设计

    • 一个
      1. TextView
      复制代码
      用于显示当前时间(格式:HH:mm:ss);
    • 一个“开始”与“停止”按钮,控制定时刷新;
    • 布局简单,整合到 MainActivity 注释中。

  • 核心方法封装

      1. updateTime()
      复制代码
      :获取系统当前时间并格式化
      1. tvClock.setText(...)
      复制代码

    • 对于每种方案,在“开始”时启动定时任务,每次调用
      1. updateTime()
      复制代码

    • 在“停止”时取消任务并停止刷新。

  • 生命周期钩子

      1. onPause()
      复制代码
      1. onDestroy()
      复制代码
      中统一调用
      1. stopX()
      复制代码
      方法,确保任务取消。

  • 对比与选型

    • 在项目初期可使用最简单的
      1. Handler.postDelayed
      复制代码

    • 若需要高可控或并发任务,可选择
      1. ScheduledExecutorService
      复制代码

    • 如果已引入 RxJava 或使用 Kotlin,推荐相应方案。


四、完整代码
  1. // ==============================================
  2. // 文件:MainActivity.java
  3. // 功能:演示五种方式实现界面定时刷新(实时时钟示例)
  4. // 包含布局 XML、Gradle 依赖一处整合,详细注释
  5. // ==============================================

  6. package com.example.timerrefresh;

  7. import android.os.*;
  8. import android.view.View;
  9. import android.widget.Button;
  10. import android.widget.TextView;
  11. import androidx.appcompat.app.AppCompatActivity;

  12. // RxJava 依赖
  13. import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
  14. import io.reactivex.rxjava3.core.*;
  15. import io.reactivex.rxjava3.disposables.Disposable;
  16. import io.reactivex.rxjava3.schedulers.Schedulers;

  17. // Kotlin Coroutines & Flow 依赖(需 Kotlin 支持)
  18. // import kotlinx.coroutines.*
  19. // import kotlinx.coroutines.flow.*

  20. // Java 并发
  21. import java.text.SimpleDateFormat;
  22. import java.util.Date;
  23. import java.util.Locale;
  24. import java.util.Timer;
  25. import java.util.TimerTask;
  26. import java.util.concurrent.*;

  27. public class MainActivity extends AppCompatActivity {
  28.     private TextView tvClock;
  29.     private Button btnStart, btnStop;

  30.     // --- 方案 A: Handler + postDelayed ---
  31.     private Handler handler = new Handler(Looper.getMainLooper());
  32.     private Runnable taskA = new Runnable() {
  33.         @Override public void run() {
  34.             updateTime();
  35.             handler.postDelayed(this, 1000);
  36.         }
  37.     };

  38.     // --- 方案 B: Timer + Handler ---
  39.     private Timer timerB;
  40.     private TimerTask timerTaskB;

  41.     // --- 方案 C: ScheduledExecutorService ---
  42.     private ScheduledExecutorService schedulerC;
  43.     private ScheduledFuture<?> futureC;

  44.     // --- 方案 D: RxJava interval ---
  45.     private Disposable disposableD;

  46.     // --- 方案 E: Kotlin Coroutines + Flow ---
  47.     // private Job jobE;

  48.     @Override
  49.     protected void onCreate(Bundle savedInstanceState) {
  50.         super.onCreate(savedInstanceState);
  51.         setContentView(R.layout.activity_main);  // 布局整合在注释下方

  52.         tvClock   = findViewById(R.id.tvClock);
  53.         btnStart  = findViewById(R.id.btnStart);
  54.         btnStop   = findViewById(R.id.btnStop);

  55.         btnStart.setOnClickListener(v -> {
  56.             // 选择下面一种,注释其余
  57.             startA();
  58.             // startB();
  59.             // startC();
  60.             // startD();
  61.             // startE();
  62.         });
  63.         btnStop.setOnClickListener(v -> {
  64.             stopA();
  65.             stopB();
  66.             stopC();
  67.             stopD();
  68.             stopE();
  69.         });
  70.     }

  71.     /** 更新时钟显示 */
  72.     private void updateTime() {
  73.         String now = new SimpleDateFormat(
  74.             "HH:mm:ss", Locale.getDefault())
  75.             .format(new Date());
  76.         tvClock.setText(now);
  77.     }

  78.     // === 方案 A:Handler + postDelayed ===
  79.     private void startA() {
  80.         handler.post(taskA);
  81.     }
  82.     private void stopA() {
  83.         handler.removeCallbacks(taskA);
  84.     }

  85.     // === 方案 B:Timer + Handler ===
  86.     private void startB() {
  87.         timerB = new Timer();
  88.         timerTaskB = new TimerTask() {
  89.             @Override public void run() {
  90.                 handler.post(() -> updateTime());
  91.             }
  92.         };
  93.         timerB.scheduleAtFixedRate(timerTaskB, 0, 1000);
  94.     }
  95.     private void stopB() {
  96.         if (timerB != null) {
  97.             timerB.cancel();
  98.             timerB = null;
  99.         }
  100.     }

  101.     // === 方案 C:ScheduledExecutorService ===
  102.     private void startC() {
  103.         schedulerC = Executors.newSingleThreadScheduledExecutor();
  104.         futureC = schedulerC.scheduleAtFixedRate(() -> {
  105.             runOnUiThread(this::updateTime);
  106.         }, 0, 1, TimeUnit.SECONDS);
  107.     }
  108.     private void stopC() {
  109.         if (futureC != null) futureC.cancel(true);
  110.         if (schedulerC != null) schedulerC.shutdown();
  111.     }

  112.     // === 方案 D:RxJava interval ===
  113.     private void startD() {
  114.         disposableD = Observable.interval(0, 1, TimeUnit.SECONDS)
  115.             .subscribeOn(Schedulers.io())
  116.             .observeOn(AndroidSchedulers.mainThread())
  117.             .subscribe(x -> updateTime());
  118.     }
  119.     private void stopD() {
  120.         if (disposableD != null && !disposableD.isDisposed()) {
  121.             disposableD.dispose();
  122.         }
  123.     }

  124.     // === 方案 E:Kotlin Coroutines + Flow ===
  125.     /*
  126.     private void startE() {
  127.         jobE = CoroutineScope(Dispatchers.Main).launch {
  128.             flow {
  129.                 while (true) {
  130.                     emit(Unit)
  131.                     delay(1000)
  132.                 }
  133.             }.collect {
  134.                 updateTime()
  135.             }
  136.         };
  137.     }
  138.     private void stopE() {
  139.         if (jobE != null && jobE.isActive()) {
  140.             jobE.cancel();
  141.         }
  142.     }
  143.     */

  144.     @Override protected void onDestroy() {
  145.         super.onDestroy();
  146.         // 确保停止所有方案
  147.         stopA(); stopB(); stopC(); stopD(); stopE();
  148.     }
  149. }

  150. /*
  151. =========================== res/layout/activity_main.xml ===========================
  152. <?xml version="1.0" encoding="utf-8"?>
  153. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  154.     android:orientation="vertical" android:gravity="center"
  155.     android:padding="24dp"
  156.     android:layout_width="match_parent" android:layout_height="match_parent">
  157.     <TextView
  158.         android:id="@+id/tvClock"
  159.         android:layout_width="wrap_content"
  160.         android:layout_height="wrap_content"
  161.         android:text="--:--:--"
  162.         android:textSize="48sp"
  163.         android:textStyle="bold"/>
  164.     <LinearLayout
  165.         android:orientation="horizontal"
  166.         android:layout_marginTop="32dp"
  167.         android:layout_width="wrap_content"
  168.         android:layout_height="wrap_content">
  169.         <Button
  170.             android:id="@+id/btnStart"
  171.             android:layout_width="wrap_content"
  172.             android:layout_height="wrap_content"
  173.             android:text="开始刷新"/>
  174.         <Button
  175.             android:id="@+id/btnStop"
  176.             android:layout_marginStart="16dp"
  177.             android:layout_width="wrap_content"
  178.             android:layout_height="wrap_content"
  179.             android:text="停止刷新"/>
  180.     </LinearLayout>
  181. </LinearLayout>
  182. =========================== 布局结束 ===========================
  183. */

  184. /*
  185. =========================== app/build.gradle 关键依赖 ===========================
  186. dependencies {
  187.     implementation 'androidx.appcompat:appcompat:1.5.1'
  188.     implementation 'io.reactivex.rxjava3:rxjava:3.1.5'
  189.     implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
  190.     // Kotlin Coroutines & Flow(如需要示例 E)
  191.     // implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
  192.     // implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
  193. }
  194. =========================== Gradle 结束 ===========================
  195. */
复制代码
五、方法解读


  • Handler + postDelayed

    • 优点:代码最简洁,无额外依赖;
    • 缺点:单线程串行,不易并行多个定时任务;

  • Timer + Handler

    • 优点:逻辑清晰,直接在后台线程周期执行;
    • 缺点
      1. Timer
      复制代码
      无法感知 UI 生命周期,需要手动取消;若任务抛异常会终止调度。

  • ScheduledExecutorService

    • 优点:功能强大,可自定义线程池大小与策略;
    • 缺点:稍显冗长,但更适合多个并发定时任务。

  • RxJava interval

    • 优点:链式调用、易于组合,可与其他 Rx 流无缝衔接;
    • 缺点:需引入 RxJava 库,学习门槛较高;

  • Kotlin Coroutines + Flow

    • 优点:语言级支持,写法像同步,易读易写;
    • 缺点:需 Kotlin 环境,注意协程生命周期管理;


六、项目总结


  • 选择建议

    • 最简单:仅需单一定时在 UI 线程更新 → 方案 A
    • 复用需求:多处定时、可复用同一线程 → 方案 B/C
    • 已有 RxJava:推荐 方案 D
    • Kotlin 项目:首选 方案 E

  • 生命周期注意:所有定时任务都需在
    1. onDestroy()
    复制代码
    1. onPause()
    复制代码
    1. onStop()
    复制代码
    取消,避免内存泄漏与后台无用计算。
  • 精细调度

    • 若对“漂移”敏感,可使用
      1. scheduleAtFixedRate()
      复制代码

    • 若后续任务执行时间不可控,推荐
      1. scheduleWithFixedDelay()
      复制代码


  • 性能优化:避免在定时任务中执行过重运算或 Block UI;对于高精度(<100ms)定时可选更底层方案如
    1. Choreographer
    复制代码

到此这篇关于Android实现界面定时刷新功能的文章就介绍到这了,更多相关Android界面定时刷新内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
12
积分
4
注册时间
2023-12-9
最后登录
2023-12-9

发表于 2025-11-21 08:44:55 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表