单Activity Android库架构设计:下载状态与FileDetailsActivity同步咨询
实现方案
我们采用观察者模式结合Android生命周期感知能力实现状态同步,既可以避免内存泄漏,也能保证状态更新只会传递给活跃的Activity页面。
1. 预定义下载状态与回调接口
首先统一管理下载全链路状态,定义状态枚举和状态变更回调接口:
// 下载状态枚举 public enum DownloadStatus { IDLE, DOWNLOADING, SUCCESS, FAILED } // 状态变更回调接口 public interface DownloadStatusListener { void onStatusChanged(DownloadStatus status, File downloadedFile, String errorMsg); }
2. 改造FileDownloadHelper,新增状态管理与监听能力
将FileDownloadHelper改为单例实现,支持绑定生命周期注册监听,页面销毁时自动解绑避免内存泄漏:
public class FileDownloadHelper extends Thread { private static FileDownloadHelper INSTANCE; private DownloadStatus currentStatus = DownloadStatus.IDLE; private File targetFile; private String errorMsg; // 存储绑定了生命周期的监听器 private final Map<Lifecycle, DownloadStatusListener> listeners = new HashMap<>(); private FileDownloadHelper() {} public static synchronized FileDownloadHelper getInstance() { if (INSTANCE == null) { INSTANCE = new FileDownloadHelper(); } return INSTANCE; } // 绑定生命周期注册监听,页面销毁自动移除 public void addStatusListener(Lifecycle lifecycle, DownloadStatusListener listener) { // 如果已经有下载结果,直接回调当前状态 if (currentStatus == DownloadStatus.SUCCESS || currentStatus == DownloadStatus.FAILED) { listener.onStatusChanged(currentStatus, targetFile, errorMsg); return; } listeners.put(lifecycle, listener); // 监听页面生命周期,销毁时自动清理监听 lifecycle.addObserver(new LifecycleEventObserver() { @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (event == Lifecycle.Event.ON_DESTROY) { listeners.remove(lifecycle); lifecycle.removeObserver(this); } } }); } @Override public void run() { currentStatus = DownloadStatus.DOWNLOADING; notifyStatusChanged(); try { // 原有下载逻辑,下载完成后赋值给targetFile targetFile = downloadFileToInternalStorage(); currentStatus = DownloadStatus.SUCCESS; } catch (Exception e) { errorMsg = e.getMessage(); currentStatus = DownloadStatus.FAILED; } finally { notifyStatusChanged(); listeners.clear(); // 下载完成后清空所有监听,释放无用引用 } } // 统一分发状态变更,切到主线程回调保证UI操作安全 private void notifyStatusChanged() { new Handler(Looper.getMainLooper()).post(() -> { for (DownloadStatusListener listener : listeners.values()) { listener.onStatusChanged(currentStatus, targetFile, errorMsg); } }); } // 原有下载到内部存储的逻辑,此处省略具体实现 private File downloadFileToInternalStorage() throws IOException { // ... 原有下载逻辑 } public DownloadStatus getCurrentStatus() { return currentStatus; } }
3. 调整MyLib入口类逻辑
public class MyLib { private static Context appContext; public static void init(Context context) { appContext = context.getApplicationContext(); // 初始化时启动下载任务 FileDownloadHelper.getInstance().start(); } public static void showDetails() { if (appContext == null) { throw new IllegalStateException("请先调用init()完成库初始化"); } Intent intent = new Intent(appContext, FileDetailsActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); appContext.startActivity(intent); } }
4. FileDetailsActivity中实现状态监听与UI渲染
public class FileDetailsActivity extends AppCompatActivity { private ProgressBar loadingView; private TextView contentView; private TextView errorView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_file_details); loadingView = findViewById(R.id.loading); contentView = findViewById(R.id.content); errorView = findViewById(R.id.error); // 绑定当前页面生命周期注册下载状态监听 FileDownloadHelper.getInstance().addStatusListener(getLifecycle(), (status, file, errorMsg) -> { switch (status) { case DOWNLOADING: showLoading(); break; case SUCCESS: showFileContent(file); break; case FAILED: showErrorTip(errorMsg); break; } }); } private void showLoading() { loadingView.setVisibility(View.VISIBLE); contentView.setVisibility(View.GONE); errorView.setVisibility(View.GONE); } private void showFileContent(File file) { loadingView.setVisibility(View.GONE); errorView.setVisibility(View.GONE); contentView.setVisibility(View.VISIBLE); // 读取文件内容渲染到页面,此处省略具体实现 } private void showErrorTip(String errorMsg) { loadingView.setVisibility(View.GONE); contentView.setVisibility(View.GONE); errorView.setVisibility(View.VISIBLE); errorView.setText(errorMsg); } }
方案核心优势
- 无内存泄漏风险:监听绑定Activity生命周期,页面销毁时自动移除,不会出现持有Activity引用导致的内存泄漏
- 状态同步即时:进入页面时如果下载已经完成/失败,会直接返回当前状态,无需等待事件触发
- 线程安全:所有UI相关回调都切换到主线程执行,不会出现子线程操作UI的崩溃问题
- 入侵性低:原有业务逻辑不需要大幅修改,仅需新增状态管理和监听逻辑即可
内容的提问来源于stack exchange,提问作者Ankur Jain
相关产品推荐
相关产品推荐

