MVP之OOM

MVPOOM

上一篇《MVP之初体验》 介绍了MVP的基本用法,但那种用法会导致重大隐患——OOM

隐患在哪里

上一篇做法是在ActivityonCreate(...)方法中创建的Presenter对象,并把当前Activity 对象在Presenter 的构造方法中传入。那么问题来了,如果某个Activity 已经被finish() 了,那么对应Presenter中的Activity 对象的引用是不是还存在呢?这就很容易导致内存泄漏。那么如何解决呢?这时“弱引用”就该出场了。。(先回顾下上一篇代码)

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    mPresenter = new UserPresenter(this);
}
Java中的几种引用

Java中有四种对象引用方式,分别是:强引用、软引用、弱引用和虚引用。详情请参考Java基础之自四大引用方式

如何解决上述隐患

泛型 + 弱引用

Presenter
  • 首先,Presenter需要一个共同的父类BasePresenter,在这个父类中统一管理其对View的引用
public class BasePresenter<V> {

    //View的弱引用
    protected WeakReference<V> mViewRef;

    /**
     * 构造函数
     *
     * @param view 需要关联的View
     */
    public BasePresenter(V view) {
        //关联View
        attachView(view);
    }

    /**
     * 关联View
     *
     * @param view 需要关联的View
     */
    public void attachView(V view) {
        mViewRef = new WeakReference<>(view);
    }

    /**
     * 取消关联的View
     */
    public void detachView() {
        if (null != mViewRef) {
            mViewRef.clear();
        }
    }

    /**
     * 获取将当前关联的View
     *
     * @return 当前关联的View
     */
    public V getView() {
        if (null != mViewRef) {
            return mViewRef.get();
        }
        return null;
    }
}
  • 具体PresenterUserPresenter
public class UserPresenter extends BasePresenter<UserView> {
    private UserView mUserView;
    private UserModel mUserModel;

    public UserPresenter(UserView userView) {
        super(userView);
        mUserView = userView;
        mUserModel = new UserModelImpl();
    }

    public void addUser() {
        if (null != mUserModel) {
            mUserModel.addUser(mUserView.getUser());
        }
    }

    public void showUser() {
        if (null != mUserModel) {
            mUserModel.loadUsers(new UserModel.OnUserLoadedListener() {
                @Override
                public void onLoaded(List<User> userList) {
                    mUserView.showUser(userList);
                }
            });
        }
    }
}
  • 同时,也需要一个BaseActivity类,用来管理Presenter的“生命周期”
public abstract class BaseActivity<V, P extends BasePresenter<V>> extends AppCompatActivity {

    protected P mPresenter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //从子类中获取到具体的Presenter对象
        mPresenter = createPresenter();
        //关联当前View(子类Activity需要实现具体的View)
        //mPresenter.attachView((V) this);
        //改为在BasePresenter构造方法中关联
    }

    @Override
    protected void onDestroy() {
        //取消View的关联
        mPresenter.detachView();
        super.onDestroy();
    }

    protected abstract P createPresenter();
}
  • 具体Activity子类中的实现
public class MainActivity extends BaseActivity<UserView, UserPresenter> implements UserView {

    private EditText etUsername;
    private EditText etPassword;
    private Button btnAdd;
    private Button btnShow;
    private ListView lvUsers;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        etUsername = (EditText) findViewById(R.id.et_username);
        etPassword = (EditText) findViewById(R.id.et_password);
        btnAdd = (Button) findViewById(R.id.btn_add);
        btnShow = (Button) findViewById(R.id.btn_show);
        lvUsers = (ListView) findViewById(R.id.lv_users);

        btnAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPresenter.addUser();
            }
        });

        btnShow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPresenter.showUser();
            }
        });
    }

    @Override
    public User getUser() {
        String username = etUsername.getText().toString();
        String password = etPassword.getText().toString();
        if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {
            return null;
        }
        return new User(username, password);
    }

    @Override
    public void showUser(final List<User> userList) {
        lvUsers.setAdapter(new BaseAdapter() {
            @Override
            public int getCount() {
                return userList.size();
            }

            @Override
            public User getItem(int position) {
                return userList.get(position);
            }

            @Override
            public long getItemId(int position) {
                return position;
            }

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                TextView tv = new TextView(MainActivity.this);
                tv.setPadding(20, 32, 20, 32);
                tv.setText(getItem(position).username + " :: " + getItem(position).password);
                return tv;
            }
        });
    }

    @Override
    protected UserPresenter createPresenter() {
        //返回具体Presenter和需要关联的View
        return new UserPresenter(this);
    }
}
  • UserView代码
public interface UserView extends BaseView {

    User getUser();

    void showUser(List<User> userList);
}
  • UserModel接口代码
public interface UserModel {

    void addUser(User user);

    void loadUsers(OnUserLoadedListener listener);

    interface OnUserLoadedListener {
        void onLoaded(List<User> userList);
    }
}
  • UserModelImpl实现类代码
public class UserModelImpl implements UserModel {
    private static final List<User> USER_LIST = new ArrayList<>();

    @Override
    public void addUser(User user) {
        USER_LIST.add(user);
    }

    @Override
    public void loadUsers(OnUserLoadedListener listener) {
        //此处处理网络加载数据
        if (null != listener) {
            listener.onLoaded(USER_LIST);
        }
    }
}

这样不仅很有效地解决了OOM问题,也不需要在每个ActivityonCreate(...) 方法中创建Presenter 对象了。


运行效果

运行效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值