Keywords: Android | Screen Orientation Change | Progress Dialog | Background Thread | Handler | Activity Lifecycle
Abstract: This article explores common issues when handling progress dialogs and background threads during screen orientation changes in Android, including window leaks, crashes, and deadlocks. By analyzing the Handler mechanism, Activity lifecycle, and thread safety, it proposes solutions based on volatile Handler and lifecycle management to ensure application stability and user experience during configuration changes.
Problem Background and Challenges
In Android development, when the screen orientation changes, the system by default destroys and recreates the current Activity. If a progress dialog is displayed and a background thread is running at this time, it can lead to issues such as window leaks, application crashes, or deadlocks. For example, in the provided sample code, the background thread attempts to operate on an old ProgressDialog instance via a Handler after Activity recreation, causing a WindowLeaked exception.
Core Issue Analysis
Screen orientation change is a configuration change that triggers the Activity's onDestroy() and subsequent onCreate(). The view hierarchy of the old Activity is destroyed, but the background thread may still be running and holding references to the old Activity or its views. When the thread sends messages to update the UI via a Handler, exceptions or undefined behavior can occur if the Handler's associated Looper is invalid or points to the old Activity.
Solution: Lifecycle Management with Volatile Handler
Referring to the best answer, the key is to ensure that the Handler instance is correctly updated after Activity recreation, preventing background threads from operating on invalid UI components. Here are the implementation steps:
- Declare a volatile Handler: Use the
volatilekeyword to modify the Handler, ensuring visibility in a multi-threaded environment. Update the Handler reference promptly when the Activity is recreated. - Initialize Handler in onCreate: Re-instantiate the Handler each time the Activity is created, binding it to the current main thread's Looper.
- Safe communication from background threads: Threads send messages via the volatile Handler, ensuring operations are performed on the latest Activity instance.
Example code implementation:
public class MyActivity extends Activity implements Runnable {
private volatile Handler mHandler;
private ProgressDialog mProgress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize Handler, binding to current main thread
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (mProgress != null && mProgress.isShowing()) {
mProgress.dismiss();
}
}
};
}
public void send() {
mProgress = ProgressDialog.show(this, "Please wait", "Processing...", true, true);
Thread thread = new Thread(this);
thread.start();
}
@Override
public void run() {
// Simulate network operation
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Send message via volatile Handler
if (mHandler != null) {
mHandler.sendMessage(new Message());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// Clean up resources to avoid leaks
if (mProgress != null && mProgress.isShowing()) {
mProgress.dismiss();
}
mProgress = null;
}
}Supplementary Solutions and Best Practices
Referencing other answers, robustness can be enhanced with the following methods:
- Avoid using
android:configChanges: As mentioned in Answer 1, Google does not recommend manually handling configuration changes, as it may ignore updates to other system resources. - IntentService and Sticky Broadcasts: As suggested in Answer 3, move long-running tasks to an IntentService and notify the UI via broadcasts, combined with
onSaveInstanceStateto save state, suitable for complex scenarios. - Weak Reference for Dialog Management: Use
WeakReferenceto store ProgressDialog, preventing Activity leaks, and restore dialog state upon recreation.
System Design Perspective
From a system design perspective, this issue involves resource management, thread synchronization, and lifecycle coordination. Referencing the auxiliary article, it emphasizes improving application adaptability in dynamic environments through modular design (e.g., separating UI logic from background tasks) and state persistence. Practicing similar problems can deepen understanding of Android architecture components.
Conclusion
Handling progress dialogs and background threads during screen orientation changes centers on ensuring safe communication between UI components and threads. By using a volatile Handler and lifecycle callbacks, window leaks and crashes can be effectively avoided, enhancing application stability. Developers should choose appropriate solutions based on specific needs and follow Android best practices.