Android中的弱引用(WeakReference)

本文介绍了弱引用的概念及其应用场景,特别是在Handler中使用弱引用来防止因主线程结束导致的对象无法被垃圾回收而引发的内存泄漏问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

  • 弱引用,其实弱字说明了一切——容易被销毁(GC);举个例子在Handler里面如果直接引用了一个对象(强引用),handler在处理一个延时任务,期间主线程被用户finish掉,但这里的对象却不能被销毁,这样造成内存泄漏,也容易造成NullPointException异常。
  • 每次GC做回收都会销毁弱引用。
  • 常用与子线程或者handler里面。
  • private static class BannerHandler extends Handler {
        private WeakReference<BannerView3> weakReference = null;
    
        public BannerHandler(BannerView3 bannerView) {
            super(Looper.getMainLooper());
            this.weakReference = new WeakReference<BannerView3>(bannerView);
        }
    
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (this.weakReference == null) {
                return;
            }
            BannerView3 bannerView = this.weakReference.get();
            if (bannerView == null || bannerView.mViewPager == null || bannerView.mViewPager.getAdapter() == null || bannerView.mViewPager.getAdapter().getCount() <= 0) {
                sendEmptyMessageDelayed(MSG_LOOP, LOOP_INTERVAL);
                return;
            }
        }
    }
### 使用弱引用避免 Android MVP 架构中的内存泄漏 在 Android MVP 架构中,Presenter 对 View 的强引用可能导致内存泄漏。这是因为 Presenter 可能会在后台线程中长时间运行,在此期间即使 Activity 或 Fragment 已经销毁,但由于 Presenter 仍然持有对它们的强引用,垃圾回收机制无法释放这些对象[^3]。 为了防止这种情况的发生,可以通过 **WeakReference** 来实现 Presenter 和 View 之间的松耦合关系。具体来说: #### WeakReference 的作用 `WeakReference` 是 Java 提供的一种特殊类型的引用,允许 GC 在任何时刻回收该对象所指向的对象实例,而不受其他条件的影响。因此,通过 `WeakReference`,可以在 Presenter 中保存对 View 的弱引用,从而避免因 Presenter 存活而导致的 View 泄漏问题[^4]。 --- #### 实现方式 以下是基于 WeakReference 的 MVP 模式的典型实现方案: 1. **定义接口** 定义一个通用的 View 接口和 Presenter 接口,用于解耦具体的 UI 组件与业务逻辑。 ```java public interface IBaseView { void showLoading(); void hideLoading(); void onError(String message); } public interface IBasePresenter<V extends IBaseView> { void attachView(V view); void detachView(); } ``` 2. **创建 BasePresenter 类** 在 BasePresenter 中引入 WeakReference 并提供绑定和解除绑定的方法。 ```java import android.os.Handler; import android.os.Looper; import java.lang.ref.WeakReference; public abstract class BasePresenter<V extends IBaseView> implements IBasePresenter<V> { private WeakReference<V> mViewRef; // 使用 WeakReference 避免内存泄漏 @Override public void attachView(V view) { mViewRef = new WeakReference<>(view); // 初始化弱引用 } protected V getView() { // 获取当前绑定的 View return mViewRef != null ? mViewRef.get() : null; } protected boolean isViewAttached() { // 判断是否有有效的 View 被绑定 return mViewRef != null && mViewRef.get() != null; } @Override public void detachView() { if (mViewRef != null) { mViewRef.clear(); // 清除弱引用 mViewRef = null; } } protected void runOnUiThread(Runnable runnable) { new Handler(Looper.getMainLooper()).post(runnable); } } ``` 3. **实际使用场景** 下面是一个简单的登录功能示例,展示如何利用上述结构避免内存泄漏。 - **LoginView.java** ```java public interface LoginView extends IBaseView { String getUsername(); String getPassword(); void onLoginSuccess(String token); void onLoginFailure(String errorMessage); } ``` - **LoginPresenter.java** ```java public class LoginPresenter extends BasePresenter<LoginView> { public void login() { final String username = getView().getUsername(); final String password = getView().getPassword(); if (!isViewAttached()) { return; // 如果 View 不再有效,则停止操作 } // 模拟网络请求 new Thread(() -> { try { Thread.sleep(2000); // 模拟延迟 String token = "fake_token"; // 假设成功获取到令牌 runOnUiThread(() -> { if (isViewAttached()) { getView().onLoginSuccess(token); } }); } catch (Exception e) { runOnUiThread(() -> { if (isViewAttached()) { getView().onLoginFailure(e.getMessage()); } }); } }).start(); } } ``` - **LoginActivity.java** ```java public class LoginActivity extends AppCompatActivity implements LoginView { private LoginPresenter presenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); presenter = new LoginPresenter(); presenter.attachView(this); findViewById(R.id.btn_login).setOnClickListener(v -> presenter.login()); } @Override protected void onDestroy() { super.onDestroy(); presenter.detachView(); // 解绑以避免内存泄漏 } @Override public String getUsername() { return ((EditText)findViewById(R.id.et_username)).getText().toString(); } @Override public String getPassword() { return ((EditText)findViewById(R.id.et_password)).getText().toString(); } @Override public void onLoginSuccess(String token) { Toast.makeText(this, "Token: " + token, Toast.LENGTH_SHORT).show(); } @Override public void onLoginFailure(String errorMessage) { Toast.makeText(this, "Error: " + errorMessage, Toast.LENGTH_SHORT).show(); } @Override public void showLoading() {} @Override public void hideLoading() {} } ``` --- #### 总结 通过以上方法,可以有效地减少由 Presenter 强引用导致的内存泄漏风险。核心在于使用 `WeakReference` 替代传统的直接引用,并在生命周期结束时主动调用 `detachView()` 方法清理资源。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值