You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将实现接口的Activity弱引用传递给单例类?

正确实现接收IAnalytics弱引用的单例类

首先,先确认你的基础接口定义没问题:

public interface IAnalytics { 
    String getAnalyticViewName(); 
}

接下来我会帮你完善AnalyticsWrapper单例类的实现,既要保证单例的唯一性,又能安全持有所有实现IAnalytics接口的Activity弱引用,同时避免内存泄漏:

public class AnalyticsWrapper {
    // 用volatile保证多线程下实例的可见性
    private static volatile AnalyticsWrapper instance;
    // 持有IAnalytics的弱引用,避免Activity泄漏
    private WeakReference<IAnalytics> analyticsWeakRef;

    // 私有构造,禁止外部直接实例化
    private AnalyticsWrapper() {}

    // 无参版getInstance,用于获取全局唯一实例
    public static AnalyticsWrapper getInstance() {
        // 双重检查锁实现线程安全的单例
        if (instance == null) {
            synchronized (AnalyticsWrapper.class) {
                if (instance == null) {
                    instance = new AnalyticsWrapper();
                }
            }
        }
        return instance;
    }

    // 带参版getInstance,用于更新当前的IAnalytics弱引用
    public static AnalyticsWrapper getInstance(WeakReference<IAnalytics> analyticsRef) {
        AnalyticsWrapper wrapper = getInstance();
        // 更新弱引用,确保单例始终持有最新的Activity引用
        wrapper.analyticsWeakRef = analyticsRef;
        return wrapper;
    }

    // 提供安全获取当前IAnalytics实例的方法(必须判空)
    public IAnalytics getCurrentAnalytics() {
        return analyticsWeakRef != null ? analyticsWeakRef.get() : null;
    }

    // 示例:封装统计逻辑,自动获取当前页面名称
    public void trackPageView() {
        IAnalytics analytics = getCurrentAnalytics();
        if (analytics != null) {
            String viewName = analytics.getAnalyticViewName();
            // 这里替换成你的实际统计代码,比如上报到统计平台
            // Log.d("Analytics", "上报页面:" + viewName);
        }
    }

    // 可选:提供手动清空引用的方法,更安全
    public void clearAnalyticsRef() {
        this.analyticsWeakRef = null;
    }
}

关键细节说明

  • 线程安全的单例:用双重检查锁+volatile修饰符,确保多线程环境下不会创建多个实例,同时避免指令重排导致的半初始化问题。
  • 弱引用的安全使用:每次获取IAnalytics实例时都要判空,因为弱引用会在Activity被GC回收时自动释放,防止空指针异常。
  • 灵活更新引用:分离无参和带参的getInstance方法,既保证单例全局唯一,又能在Activity生命周期合适的时机更新引用。

Activity中的调用方式

因为所有Activity都实现了IAnalytics,建议你创建一个基类Activity,统一处理引用的更新和清空:

public class BaseAnalyticsActivity extends AppCompatActivity implements IAnalytics {
    @Override
    protected void onResume() {
        super.onResume();
        // 当Activity回到前台时,更新单例的弱引用
        AnalyticsWrapper.getInstance(new WeakReference<>(this));
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 当Activity退到后台时,清空引用(可选,但更安全)
        AnalyticsWrapper.getInstance().clearAnalyticsRef();
    }

    // 子类需要实现这个方法,返回当前页面的统计名称
    @Override
    public String getAnalyticViewName() {
        return this.getClass().getSimpleName();
    }
}

这样所有继承BaseAnalyticsActivity的页面都会自动维护单例中的引用,你在任何地方调用AnalyticsWrapper.getInstance().trackPageView()就能自动获取当前页面的名称进行统计了。

内容的提问来源于stack exchange,提问作者dev90

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:41:18