绑定解除View(可以避免内存泄漏)
使用MVP还遇到过一个问题,容易产生内存泄漏的问题,我的项目里面有成百上千个Activity类,每一个Presenter我都做解决内存泄漏这个操作,很容易有些地方疏忽了,那一天可能加班,有点累,就没有注意内存泄漏这方面,结果就给我的项目带来很大的麻烦,而且我这个项目后期别人接手他可能意识不到内存泄漏的问题,他在基于我的框架写MVP的时候有可能也不做内存泄漏,那这样子的话,内存泄漏的多了就会造成OOM我们的程序就会奔溃。所以我当时在抽基类的时候我就想到,要定义规范,抽基类就两点,把冗余的代码简化一下放在基类里面,不必要每个子类都写一样的业务逻辑。第二就是定义规范,比如所有的子类都要进行一个初始化控件的操作,那么我就写一个抽象方法,你只要继承我的基类,那么你必然要实现抽象方法,只要实现抽象方法,那你一看抽象方法这个方法你就知道,他是做什么逻辑的,你就把你的逻辑放到你实现的抽象方法里面,那这样的话代码阅读性更高,每个人不管怎么做,这个操作都必须要做,我抽了一个Presenter。我在做MVP的时候抽了一个BasePresenter,通过泛型我把内存泄漏就处理了,任何一个MVP的子类只要继承我的BasePresenter,就自动把内存泄漏给解决了。别人就不用考虑这个方面了,不论是我自己还是别人接手我的项目,都可以省很多功夫,那么我们APP的健壮性更好。
依赖:
dependencies {
compile 'com.android.support:appcompat-v7:26.0.0-alpha1'
compile 'com.android.support:support-v4:26.0.0-alpha1'
testCompile 'junit:junit:4.12'
/*5.0新控件的依赖*/
compile 'com.android.support:design:26.0.0-alpha1'
/*RxJava与RxAndroid的依赖*/
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
/*Retrofit与RxAndroid配置依赖*/
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
/*使Retrofit的转化器自定义完成数据的转化
* 就是我们可以接口中少写一些bean类
* */
compile 'com.squareup.retrofit2:converter-scalars:+'
/*gson解析*/
compile 'com.google.code.gson:gson:2.8.1'
/*Log工具:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/1115/3685.html*/
compile 'com.github.zhaokaiqiang.klog:library:1.6.0'
}
/**
* MVP的基本封装
* 1.搭建框架,首先创建基类(IActivity,BasePresenter,BaseMvpActivity)
* 2.在SplashActivity使用一下MVP(SplashView,SplashPresenter)
* 3.自己搭建Fragment的MVP的基类,并使用一下(IFragment,BaseMvpFragment)
*/
public class SplashActivity extends BaseMvpActivity<SplashView,SplashPresenter> {
@Override
public SplashPresenter initPresenter() {
return new SplashPresenter();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
presenter.getData();
}
}
activity_main
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".SplashActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"/>
</RelativeLayout>
/**
* 这是MVP的Activity,一个抽象类.在对应的生命周期里绑定资源,释放资源,避免MVP带来的内存泄漏
* @param <V> 这个泛型代表当前的View
* @param <T> 这个泛型代表当前的presenter
* 提示:因为每个Activity创建的presenter,View都不同,所有用泛型
抽取基类的原则:子类共有且实现方式相同的代码,我们直接抽到我们的基类,提供效率,增加代码的阅读性
* 子类共有且实现方式不相同的代码,我们以抽象方法的形象在我们基类中体现,这样没有一个继承该基类的子类,都要去做规定的业务
比如说初始化控件,每个子类都要做,但是具体fb的代码不可能相同,因此我们可以用抽象方法行,强行让子类记着要初始化控件,然后怎么实现就不做要求
为什么定义接口,定义泛型,就是为让你按照我定义规则去写代码.只有按我的规则写代码,代码才会便于维护,阅读.
* 3个Android工程师,我写规则,内存泄漏,释放资源等等,我再定义规则都写好,你就在我写的这个框架内,去实现就可以
* 从moudle里拿到网上数据,把数据解析,更新UI控件显示,就可以了.你们传数据,MD5,时间戳,签名去封装然后你才够请求
* 掉我写的工具类,你把参数传进去,拿到结果,你去请求网络,薪资在15一上.
*/
public abstract class BaseMvpActivity<V,T extends BasePresenter<V>> extends IActivity {
public T presenter ;
public abstract T initPresenter();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base_mvp);
presenter = initPresenter();
}
//绑定资源
@Override
protected void onResume() {
super.onResume();
presenter.attach((V) this);
}
//释放资源
@Override
protected void onDestroy() {
super.onDestroy();
presenter.detach();
}
}
activity_base_mvp
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_base_mvp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".base.BaseMvpActivity">
</RelativeLayout>
/**
* 使用MVP的架构,同时参数为泛型
* 解决:MVP最常见的,内存泄漏的问题
* @param <T>
*/
public abstract class BasePresenter<T> {
public T view;
public void attach(T view) {
this.view = view;
}
//防止内存泄漏,将对象置为null
public void detach() {
this.view = null;
}
}
/**
* 所有的 activity 都继承这个Activity,这是一个简单的Activity
* 我们的项目并不是所有的模块都是MVP,对应业务逻辑不复杂的Activity,没必要抽成MVP,比如启动页
*/
public class IActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_i);
}
}
activity_i
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_i"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".base.IActivity">
</RelativeLayout>
public interface SplashView {
}
/* function:Presenter与module想关联
* 提示:这里的View对象,我们在 BasePresenter
*/
public class SplashPresenter extends BasePresenter<SplashView> {
private SplashModelImpl splashModel;
public SplashPresenter() {
splashModel =new SplashModelImpl();
}
//A.presenter里和Module进行交互,暴露一个获取数据的方法
public void getData(){
splashModel.getData();
}
}
/**
* function:module层,使用封装的RetrofitFactory工厂,从网络获取数据.
*/
public class SplashModelImpl {
public void getData() {
// //我们可以用一个适配器设计模式避免写那么多无用的回调
// RetrofitFactory.apiService.get("http://www.baidu.com")
// .subscribeOn(Schedulers.io())//被观察者运行在子线程
// .observeOn(AndroidSchedulers.mainThread())//观察运行在主线程
// .subscribe(new Observer<String>() {
// @Override
// public void onSubscribe(@NonNull Disposable d) {}
// @Override
// public void onNext(@NonNull String s) {}
// @Override
// public void onError(@NonNull Throwable e) {}
// @Override
// public void onComplete() {}
// });
RetrofitFactory.get("https://api-quality.jiemian.com/goodsCat/getBrandList").subscribe(new BaseObserver() {
@Override
public void onSuccess(String result) {
System.out.println("result = " + result);
}
@Override
public void onFailed() {}
});
}
}
/**
* Retrofit底层用的就是okhttpclient(Retrofit就是okhttp的封装)
* 1.使项目就一个okhttpClient,和Retrofit对象,节省内存,并设置基础Url
* 2.使Retrofit与RxJava结合使用
* 3.我们使用通用接口,减少了接口的定义的数量
* 子线程不能更新UI,主线程里面不能做耗时操作
* 子线程咱们做耗时操作,主线程咱们UI更新.
*/
public class RetrofitFactory {
//使全局就一个OKHttpClient对象
public static OkHttpClient okHttpClient = new OkHttpClient.Builder()
// .cookieJar(new CookiesManager())
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.addInterceptor(new LoggingInterceptor())
.build();
//使全局就一个Retrofit对象,设置基础Url
public static ApiService apiService = new Retrofit.Builder()
.baseUrl("http://qbh.2dyt.com")
//使我们能高度自定义转化器
.addConverterFactory(ScalarsConverterFactory.create())
.client(okHttpClient)
//把 以前的 call 转化成 Observable,这是Retrofit与RxJava结合使用的关键
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build().create(ApiService.class);
public static Observable<String> get(String url) {
return apiService.get(url)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
public static Observable<String> get(String url, Map<String, String> map) {
return apiService.get(url, map).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
public static Observable<String> post(String url, Map<String, String> map) {
return apiService.post(url, map).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}
//网络请求日志拦截器,直接拷贝使用即可
class LoggingInterceptor implements Interceptor {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
KLog.i(String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
Response response = chain.proceed(request);
long t2 = System.nanoTime();
KLog.i(String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
return response;
}
}
public interface ApiService {
/**
* Get基本请求,这里从Call改为Observable被观察者
* @param url
* @return
*/
@GET
public Observable<String> get(@Url String url);
/**
* Get请求提交表单
* @param url
* @param map
* @return
*/
@GET
public Observable<String> get(@Url String url, @QueryMap Map<String,String> map);
/**
* Post请求提交表单
* @param url
* @param map
* @return
*/
@FormUrlEncoded
@POST
public Observable<String> post(@Url String url , @FieldMap Map<String,String> map);
}
public abstract class BaseObserver implements Observer<String> {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull String s) {
onSuccess(s);
}
//自己封装失败的回调
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
public abstract void onSuccess(String result);
public abstract void onFailed();
}
————————————————
转载于:https://blog.csdn.net/jun_tong/article/details/80943983