MVP
之OOM
上一篇《MVP之初体验》 介绍了MVP的基本用法,但那种用法会导致重大隐患——
OOM
隐患在哪里
上一篇做法是在
Activity
的onCreate(...)
方法中创建的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;
}
}
- 具体
Presenter
类UserPresenter
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
问题,也不需要在每个Activity
的onCreate(...)
方法中创建Presenter
对象了。