1. Project introduction
In mobile applications,Interface refresh regularlyIt is a very common requirement, and typical scenarios include:
Clock/stopwatch: Updates to display the current time or time every second;
Real-time data monitoring: Regularly pull server status or sensor data and update UI;
List automatically refreshes: For example, news and social feeds to refresh the latest content regularly;
Countdown: Update the remaining time per second in the case of promotional and exam countdown scenarios;
Game logic refresh: Simple animation or status polling.
This tutorial will take a "real-time clock" example as the main line to demonstrate a variety of commonly used implementation methods for timing refreshes:
Plan A: Handler + postDelayed
Plan B: Timer + Handler
Solution C: ScheduledExecutorService
Solution D: RxJava interval
Solution E: Kotlin Coroutines + Flow
And compare theirCode simplicity、Performance consumption、Lifecycle ManagementandCancel mechanism, help you quickly select and get started in your project.
2. Related technologies and knowledge
-
Main thread and UI updates
Android requires that all UI operations must be executed in the main thread (UI thread).
If the timing task is executed in the child thread, it needs to be switched back to the main thread for use.
runOnUiThread()
orHandler
。
-
Handler & Looper
Handler
:WillRunnable
orMessage
Publish to the boundLooper
(Thread Message Queue).postDelayed(Runnable r, long delayMillis)
: Delayed execution of tasks.
-
Timer & TimerTask
Timer
Used to arrangeTimerTask
Execution in background thread cycle or delayed;The result needs to be passed
Handler
orrunOnUiThread()
Back to the main thread.
-
ScheduledExecutorService
Java Standard Library:
()
Can execute tasks regularly and supportscheduleAtFixedRate()
。
-
RxJava
()
: Based on Scheduler timing transmitting Long values, combined withobserveOn(())
Update the UI.
-
Kotlin Coroutines & Flow
flow { while(true) { emit(Unit); delay(1000) } }
: Use coroutine light-timed;exist
Collect and update the UI.
-
Lifecycle management and cancellation
The timing task should be
()
/onDestroy()
Cancel the memory leak and useless calculations in the background;Different solutions cancellation methods are also different:
()
,()
,()
,()
,()
wait.
Ideas for realization
-
Sample interface design
one
TextView
Used to display the current time (format: HH:mm:ss);A "Start" and "Stop" buttons that control timing refresh;
Simple layout and integrated into MainActivity comments.
-
Core method encapsulation
updateTime()
: Get the current time of the system and format it(...)
;For each scheme, the timing task is started at "start", each call
updateTime()
;Cancel the task when "stop" and stop refreshing.
-
Life cycle hook
exist
onPause()
oronDestroy()
Unified callstopX()
Method, ensure that the task is cancelled.
-
Comparison and selection
The easiest to use in the early stage of the project
;
If you need highly controllable or concurrent tasks, you can choose
ScheduledExecutorService
;If RxJava has been introduced or Kotlin is used, the corresponding solution is recommended.
4. Complete code
// ============================================== // document:// Function: Demonstrate five ways to implement interface timing refresh (real-time clock example)// Includes layout XML and Gradle dependencies, detailed annotations// ============================================== package ; import .*; import ; import ; import ; import ; // RxJava dependenciesimport .; import ..*; import .; import .; // Kotlin Coroutines & Flow dependencies (requires Kotlin support)// import .* // import .* // Java concurrencyimport ; import ; import ; import ; import ; import .*; public class MainActivity extends AppCompatActivity { private TextView tvClock; private Button btnStart, btnStop; // --- Solution A: Handler + postDelayed --- private Handler handler = new Handler(()); private Runnable taskA = new Runnable() { @Override public void run() { updateTime(); (this, 1000); } }; // --- Solution B: Timer + Handler --- private Timer timerB; private TimerTask timerTaskB; // --- Solution C: ScheduledExecutorService --- private ScheduledExecutorService schedulerC; private ScheduledFuture<?> futureC; // --- Solution D: RxJava interval --- private Disposable disposableD; // --- Solution E: Kotlin Coroutines + Flow --- // private Job jobE; @Override protected void onCreate(Bundle savedInstanceState) { (savedInstanceState); setContentView(.activity_main); // Layout integration below comment tvClock = findViewById(); btnStart = findViewById(); btnStop = findViewById(); (v -> { // Select the following one and comment the rest startA(); // startB(); // startC(); // startD(); // startE(); }); (v -> { stopA(); stopB(); stopC(); stopD(); stopE(); }); } /** Update clock display */ private void updateTime() { String now = new SimpleDateFormat( "HH:mm:ss", ()) .format(new Date()); (now); } // === Scheme A: Handler + postDelayed === private void startA() { (taskA); } private void stopA() { (taskA); } // === Scheme B: Timer + Handler === private void startB() { timerB = new Timer(); timerTaskB = new TimerTask() { @Override public void run() { (() -> updateTime()); } }; (timerTaskB, 0, 1000); } private void stopB() { if (timerB != null) { (); timerB = null; } } // === Scheme C: ScheduledExecutorService === private void startC() { schedulerC = (); futureC = (() -> { runOnUiThread(this::updateTime); }, 0, 1, ); } private void stopC() { if (futureC != null) (true); if (schedulerC != null) (); } // === Scheme D: RxJava interval === private void startD() { disposableD = (0, 1, ) .subscribeOn(()) .observeOn(()) .subscribe(x -> updateTime()); } private void stopD() { if (disposableD != null && !()) { (); } } // === Scheme E: Kotlin Coroutines + Flow === /* private void startE() { jobE = CoroutineScope().launch { flow { while (true) { emit(Unit) delay(1000) } }.collect { updateTime() } }; } private void stopE() { if (jobE != null && ()) { (); } } */ @Override protected void onDestroy() { (); // Make sure to stop all plans stopA(); stopB(); stopC(); stopD(); stopE(); } } /* ==================================== res/layout/activity_main.xml =================================== <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andro android:orientation="vertical" android:gravity="center" android:padding="24dp" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android: 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: android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Refresh"/> <Button android: android:layout_marginStart="16dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="stop refresh"/> </LinearLayout> </LinearLayout> ======================================================================== */ /* ====================================================================== dependencies { implementation ':appcompat:1.5.1' implementation '.rxjava3:rxjava:3.1.5' implementation '.rxjava3:rxandroid:3.0.0' // Kotlin Coroutines & Flow (if required example E) // implementation ':kotlinx-coroutines-core:1.6.4' // implementation ':kotlinx-coroutines-android:1.6.4' } ================================================================== */
5. Method interpretation
-
Handler + postDelayed
advantage: The code is the simplest and has no additional dependencies;
shortcoming: Single thread serial, not easy to parallel multiple timing tasks;
-
Timer + Handler
advantage: Clear logic, directly executed in the background thread cycle;
shortcoming:
Timer
The UI life cycle cannot be sensed and needs to be canceled manually; if the task throws an exception, the dispatch will be terminated.
-
ScheduledExecutorService
advantage: Powerful, customize thread pool size and policy;
shortcoming: A little bit lengthy, but more suitable for multiple concurrent timing tasks.
-
RxJava interval
advantage: Chained calls, easy to combine, seamlessly connected with other Rx streams;
shortcoming: The RxJava library needs to be introduced, and the learning threshold is relatively high;
-
Kotlin Coroutines + Flow
advantage: Language-level support, writing styles are synchronous, easy to read and write;
shortcoming: Need a Kotlin environment, pay attention to coroutine life cycle management;
6. Project Summary
-
Select a suggestion:
The easiest: Only a certain time is required to update in the UI thread →Plan A;
Reuse requirements: Multiple timings, the same thread can be reused →Plan B/C;
Already have RxJava:recommendSolution D;
Kotlin Project:PreferredSolution E;
Life cycle attention: All timing tasks need to be
onDestroy()
、onPause()
oronStop()
middleCancel, avoid memory leaks and useless background calculations.-
Fine scheduling:
If you are sensitive to "drift", you can use it
scheduleAtFixedRate()
;If the execution time of subsequent tasks is uncontrollable, it is recommended
scheduleWithFixedDelay()
。
Performance optimization: Avoid performing over-repeated operations or Block UI in timing tasks; for high-precision (<100ms) timing, more underlying solutions such as
Choreographer
。
This is the end of this article about the implementation of Android interface timing refresh function. For more related content on Android interface timing refresh, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!