开发者

Android实现界面定时刷新功能

开发者 https://www.devze.com 2025-04-22 10:18 出处:网络 作者: Katie。
目录一、项目介绍二、相关技术与知识三、实现思路四、完整代码五、方法解读六、项目总结一、项目介绍
目录
  • 一、项目介绍
  • 二、相关技术与知识
  • 三、实现思路
  • 四、完整代码
  • 五、方法解读
  • 六、项目总结

一、项目介绍

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

  1. 时钟/秒表:每秒更新显示当前时间或计时;

  2. 实时数据监控:定期拉取服务器状态或传感器数据并更新 UI;

  3. 列表自动刷新:如新闻、社交Feeds 定时刷新最新内容;

  4. 倒计时:在促销、考试倒计时场景下每秒更新剩余时长;

  5. 游戏逻辑刷新:简单动画或状态轮询。

本教程将以一个“实时时钟”示例为主线,演示多种常用的定时刷新的实现方式:

  • 方案 A:Handler + postDelayed

  • 方案 B:Timer + Handler

  • 方案 C:ScheduledExecutorService

  • 方案 D:RxJava interval

  • 方案 E:Kotlin Coroutines + Flow

并对比它们的代码简洁度性能消耗生命周期管理取消机制,帮助您在项目中快速选型并上手。

二、相关技术与知识

  1. 主线程与 UI 更新javascript

    • android 要求所有 UI 操作必须在主线程(UI 线程)中执行。

    • 定时任务若在子线程中执行,需要切回主线程使用 runOnUiThread() 或 Handler

  2. Handler & Looper

    • Handler:将 Runnable 或 Message 发布到所绑定的 Looper(线程消息队列)。

    • postDelayed(Runnable r, long delayMillis):延迟执行任务。

  3. Timer & TimerTask

    • Timer 用于安排 TimerTask 在后台线程周期或延迟执行;

    • 结果需要通过 Handler 或 runOnUiThread() 回到主线程。

  4. ScheduledExecutorService

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

  5. RxJava

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

  6. Kotlin Coroutines & Flow

    • flow { while(true) { emit(Unit); delay(1000) } }:使用协程轻量定时;

    • 在 lifecycleScope.launchWhenStarted 中收集并更新 UI。

  7. 生命周期管理与取消

    • 定时任务应在 Activity.onPause()/onDestroy() 中取消,避免内存泄漏与后台无用计算;

    • 不同方案的取消方式也不同:Handler.removeCallbacks()timer.cancel()future.cancel()disposable.dispose()job.cancel() 等。

三、实现思路

  1. 示例界面设计

    • 一个 TextView 用于显示当前时间(格式:HH:mm:ss);

    • 一个“开始”与“停止”按钮,控制定时刷新;

    • 布局简单,整合到 MainActivity 注释中。

  2. 核心方法封装

    • updateTime():获取系统当前时间并格式化 tvClock.setText(...)

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

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

  3. 生命周期钩子

    • 在 onPause() 或 onDestroy() 中统一调用 stopX() 方法,确保任务取消。

  4. 对比与选型

    • 在项目初期可使用最简单的 Handler.postDelayed

    • 若需要高可控或并发任务,可选择 ScheduledExecutorService

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

四、完整代码

// ==============================================
// 文件:MainActivity.java
// 功能:演示五种方式实现界面定时刷新(实时时钟示例)
// 包含布局 XML、Gradle 依赖一处整合,详细注释
// ==============================================
 
package com.example.timerrefresh;
 
import android.os.*;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
 
// RxJava 依赖
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.*;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
 
// Kotlin Coroutines & Flow 依赖(需 Kotlin 支持)
// import kotlinx.coroutines.*
// import kotlinx.coroutines.flow.*
 
// Java 并发
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.*;
 
public class MainActivity extends AppCompatActivity {
    private TextView tvClock;
    private Button btnStart, btnStop;
 
    // --- 方案 A: Handler + postDelayed ---
    private Handler handler = new Handler(Looper.getMainLooper());
    private Runnable taskA = new Runnable() {
        @Override public void run() {
            updateTime();
            handler.postDelayed(this, 1000);
        }
    };
 
    // --- 方案 B: Timer + Handler ---
    private Timer timerB;
    private TimerTask timerTaskB;
 
    // --- 方案 C: ScheduledExecutorService ---
    private ScheduledExecutorService schedulerC;
    private ScheduledFuture<?> futureC;
 
    // --- 方案 D: RxJava interval ---
    private Disposable disposableD;
 
    // --- 方案 E: Kotlin Coroutines + Flow ---
    // private Job jobE;
 
    @Override
    protected void onCreate(Bundle savedInstjavascriptanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);  // 布局整合在注释下方
 
        tvClock   = findViewById(R.id.tvClock);
        btnStart  = findViewById(R.id.btnStart);
        btnStop   = findViewById(R.id.btnStop);
 
        btnStart.setOnClickListener(v -> {
            // 选择下面一种,注释其余
            startA();
            // startB();
            // startC();
            // startD();
            // startE();
        });
        btnStop.setOnClickListener(v -> {
            stopA();
            stopB();
            stopC();
            stopD();
            stopE();
        });
    }
 
    /** 更新时钟显示 */
    private void updateTime() {
        String now = new SimpleDateFormat(
            "HH:mm:ss", Locale.getDefault())
            .format(new Date());
        tvClock.setText(now);
    }
 
    // === 方案 A:Handler + postDelayed ===
    private void startA() {
        handler.post(taskA);
    }
    private void stopA() {
        handler.removeCallbacks(taskA);
    }
 
    // === 方案 B:Timer + Handler ===
    private void startB() {
        timerB = new Timer();
        timerTaskB = new TimerTask() {
            @Override public void run() {
                handler.post(() -> updateTime());
            }
        };
        timerB.scheduleAtFixedRate(timerTaskB, 0, 1000);
    }
    private void stopB() {
        if (timerB != null) {
            timerB.cancel();
            timerB = null;
        }
    }
 
    // === 方案 C:ScheduledExecutorService ===
    private void startC() {
        schedulerC = Executors.newSingleThreadScheduledExecutor();
        futureC = schedulerC.scheduleAtFixedRate(() -> {
            runOnUiThread(this::updateTime);
        }, 0, 1, TimeUnit.SECONDS);
    }
    private void stopC() {
        if (futureC != null) futureC.cancel(true);
        if (schedulerC != null) schedulerC.shutdown();
    }
 
    // === 方案 D:RxJava interval ===
    private void startD() {
        disposableD = Observable.interval(0, 1, TimeUnit.SECONDS)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(x -> updateTime());
    }
    private void stopD() {
        if (disposableD != null && !disposableD.isDisposed()) {
            disposableD.dispose();
        }
    }
 
    // === 方案 E:Kotlin Coroutines + Flow ===
    /*
    private void startE() {
        jobE = CoroutineScope(Dispatchers.Main).launch {
            flow {
                while (true) {
                    emit(Unit)
                    delay(1000)
                }
            }.collect {
                updateTime()
            }
        };
    }
    private void stopE() {
        if (jobE != null && jobE.isActive()) {
            jobE.cancel();
        }
    }
    */
 
    @Override protected void onDestroy() {
        super.onDestroy();
        // 确保停止所有方案
        stopA(); stopB(); stopC(); stopD(); stopE();
    }
}
 
/*
=========================== res/layout/activity_main.xml ===========================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:gravity="center"
    android:padding="24dp"
    android:layout_width="match_parent" android:layout_height="match_parent">
    <TextView
        android:id="@+id/tvClock"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="--:--:--"
        android:textSize="48sp"
        android:textStyle="bold"/>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_marginTop="32dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/btnStart"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="开始刷新"/>
        <Button
            android:id="@+id/btnStop"
            android:layout_marginStart="16dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="停止刷新"/>
    </LinearLayout>
</LinearLayout>
=========================== 布局结束 ===========================
*/
 
/*
=========================== app/build.gradle 关键依赖 ===========================
dependencies {
    implementation 'androidx.appcompat:appcompat:1.5.1'
    implementation 'io.reactivex.rxjava3:rxjava:3.1.5'
    implementation 'io.re编程客栈activex.rxjava3:rxandroid:3.0.0'
    // Kotlin Coroutines & Flow(如需要示例 E)
    // implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
    // implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
}
=========================== Gradle 结束 ===========================
*/

五、方法解读

  1. Handler + postDelayed

    • 优点:代码最简洁,无额外依赖;

    • 缺点:单线程串行,不易并行多个定时任务;

  2. Timer + Handler

    • 优点:逻辑清晰,直接在后台线程周期执行;

    • 缺点Timer 无法感知 UI 生命周期,需要手动取消;若任务抛异常会终止调度。

  3. ScheduledExecutorService

    • 优点:功能强大,可自定义线程池大小与策略;

    • 缺点:稍显冗长,但更适编程客栈合多个并发定时任务。

  4. RxJava interval

    • 优点:链式调用、易于组合,可与其他 Rx 流无缝衔接;

    • 缺点:需引入 RxJava 库,学习门槛较高;

  5. Kotlin Coroutines + Flow

    • 优点:语言级支持,写法像同步,易读易写;

    • 缺点:需 Kotlin 环境,注意协程生命周期管理;

六、项目总结

  • 选择建议

    • 最简单:仅需单一定时在 UI 线程更新 → 方案 A

    • 复用需求:多处定时、可复用同一线程 → 方案 B/C

    • 已有 RxJava:推荐 方案 D

    • Kotlin 项目:首选 方案 E

  • 生命周期注意:所有定时任务都需在 onDestroy()onPause() 或 onStop() 中取消,避免内存泄漏与后台无用计算。

  • 精细调度

    • 若对“漂移”敏感,可使用 scheduleAtFixedRate()

    • 若后续任务执行时间不可控,推荐 scheduleWithFixedDelay()

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

到此这篇关于Android实现界面定时刷新功能的编程文章就介绍到这了,更多相关Android界面定时刷新内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号