it编程 > App开发 > Android

Android实现界面定时刷新功能

11人参与 2025-04-24 Android

一、项目介绍

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

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

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

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

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

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

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

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

二、相关技术与知识

  1. 主线程与 ui 更新

    • 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 savedinstancestate) {
        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.reactivex.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 环境,注意协程生命周期管理;

六、项目总结

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

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

Android Drawable目录下的XML图形文件详解

04-24

Android实现Android APP自动更新功能

04-24

Android实现多进程并发控制的两种方案

04-24

Android实现TextView中的部分文字实现点击跳转功能

04-24

Android实现跳转第三方百度地图导航

04-24

Android ImageButton 使用方法示例详解

04-24

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论