一、抽取原因
每一个页面都用到同样的内容,每次都写同样的代码,浪费;
规定代码的编写规范;
多人开发维护变得简单。
二、设计模式
模板设计模式
单例模式
三、代码
1.相同的部分
⑴抽取V层(吐司)
public interface BaseView {
void showToast(String string);
}
⑵抽取M层(创建网络管理类,使用双检索单例设计模式获取对象)
//单列模式 懒汉式
public class BaseModel {
//Rxjava内置容器CompositeDisposable
private CompositeDisposable compositeDisposable = null;
//所有的Disposable对象,都需要保存在CompositeDisposable中
//Disposable
//1.解除订阅关系
//2.如果在进行网络请求,还可以取消网络请求
public void addDisposable(Disposable disposable) {
if (compositeDisposable == null) {
compositeDisposable = new CompositeDisposable();
}
}
//compositeDisposable.clear();
//1.调用容器中Disposable的所有对象dispose();
//2.会将容器清空
public void destory() {
compositeDisposable.clear();
}
}
⑶抽取P层
//P层,view和model之间的桥梁
public abstract class BasePresenter<T extends BaseView> {
public T mView;//每一个presenter要有一个view,view的类别必须是BaseView的后代,用泛型来表示
//创建model集合
public ArrayList<BaseModel> models = new ArrayList<>();
//要先给view赋值(也就是先有布局),再给model赋值(再请求数据),现在还没有绑定view,要先写抽象方法
public BasePresenter() {
initModel();
}
protected abstract void initModel();//子类复写,用来初始化M层对象的
//绑定view
public void bindView(T view) {
mView = view;
}
//添加model
public void addModel(BaseModel baseModel) {
models.add(baseModel);
}
//当页面销毁时走这个方法
public void destory() {
mView = null;//页面销毁的条件
for (int i = 0; i < models.size(); i++) {
BaseModel baseModel = models.get(i);//获取model的请求
baseModel.destory();//将页面销毁
}
}
public abstract void initData();
}
⑷抽取Activity层
public abstract class BaseActivity<T extends BasePresenter> extends AppCompatActivity implements BaseView {
public T mPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayout());
ButterKnife.bind(this);//加载布局
initPresenter();//创建presenter
if (mPresenter != null) {
mPresenter.bindView(this);
}
initView();//设置布局
initData();//网络请求
}
protected abstract void initPresenter();
protected abstract void initView();
protected abstract void initData();
protected abstract int getLayout();
}
⑸callback抽取
public interface BaseCallBack<T> {
void onSuccess(T t);
void onFail(String error);
}
⑹封装网络框架
1.使用起来更简洁,效率更高
2.日志打印,缓存数据,公共参数(请求头:token,os:Android,IOS)
3.三方框架:Rxjava+Retrofit+OkHttpClient
addDisposable(HttpUtil.getInstance()
.getApiService()
.getData()
.compose(RxUtils.<MainBean>rxSchedulerHelper())
.subscribeWith(new BaseSubscriber<MainBean>() {
@Override
public void onNext(MainBean mainBean) {
back.onSuccess((ArrayList<MainBean.DataBean.DatasBean>) mainBean.getData().getDatas());
}
}));
2.其他的部分
⑴V层
public interface MainView extends BaseView {
//MainView自己的方法,加载数据时调用
void setData(ArrayList<MainBean.DataBean.DatasBean> datasBeans);
}
⑵M层
public class MainModel extends BaseModel {//网络请求
public void initData(final MainCallBack<ArrayList<MainBean.DataBean.DatasBean>> arrayListMainCallBack) {
new Retrofit.Builder()
.baseUrl(ApiService.url)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
.create(ApiService.class)
.getData()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<MainBean>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(MainBean mainBean) {
if (mainBean != null) {
arrayListMainCallBack.onSuccess((ArrayList<MainBean.DataBean.DatasBean>) mainBean.getData().getDatas());
}
}
@Override
public void onError(Throwable e) {
arrayListMainCallBack.onFail(e.getMessage());
}
@Override
public void onComplete() {
}
});
}
}
⑶P层
public class MainPresenter extends BasePresenter <MainView>{
private MainModel mainModel;
@Override
protected void initModel() {//MainPresenter是子类,复写BasePresenter中的initModel方法,来添加model
mainModel = new MainModel();
models.add(mainModel);
}
//相当于实现callback,重写callback中的方法
@Override
public void initData() {
//在M层中创建initData这个方法
mainModel.initData(new MainCallBack<ArrayList<MainBean.DataBean.DatasBean>>() {
@Override
public void onSuccess(ArrayList<MainBean.DataBean.DatasBean> datasBeans) {
mView.setData(datasBeans);
}
@Override
public void onFail(String string) {
mView.showToast(string);
}
});
}
}
⑷Activity层
public class MainActivity extends BaseActivity<MainPresenter> implements MainView {
@BindView(R.id.rv)
RecyclerView rv;
private ArrayList<MainBean.DataBean.DatasBean> list;
private MainAdapter adapter;
//调用Presenter的对象
@Override
protected void initPresenter() {
mPresenter = new MainPresenter();
}
//设置布局
@Override
protected void initView() {
rv.setLayoutManager(new LinearLayoutManager(this));
rv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
list = new ArrayList<>();
adapter = new MainAdapter(this, list);
rv.setAdapter(adapter);
}
//网络请求数据
@Override
protected void initData() {
mPresenter.initData();
}
//找控件
@Override
protected int getLayout() {
return R.layout.activity_main;
}
//失败的方法,吐司
@Override
public void showToast(String string) {
Toast.makeText(this, string, Toast.LENGTH_SHORT).show();
}
//成功的方法,将数据添加进集合中并刷新适配器
@Override
public void setData(ArrayList<MainBean.DataBean.DatasBean> datasBeans) {
list.addAll(datasBeans);
adapter.notifyDataSetChanged();
}
}
3.工具类
public class HttpUtil {
//rxjava+retrofit+ok
//单例
//数据缓存,日志,请求头(开发一般是固定的,token...)
//token,身份令牌
private Retrofit.Builder mRetrofitBuilder;
private HttpUtil() {
//1.获取一个OkHttpClient
OkHttpClient mOkHttpClient = getOkHttpClient();
//2.获取到一个Retrofit.Builder
getRetrofit(mOkHttpClient);
}
//在网络管理器的构造中获取Retrofit的builder对象
private void getRetrofit(OkHttpClient okHttpClient) {
mRetrofitBuilder = new Retrofit.Builder()
.client(okHttpClient)//使用自定义的更强大的ok代替原来的弱鸡ok
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
}
//volatile
private static volatile HttpUtil instance;
//Double checked lock
//创建网络管理类,使用双检索单例设计模式获取对象
public static HttpUtil getInstance() {
if (instance == null) {
synchronized (HttpUtil.class) {
if (instance == null) {
instance = new HttpUtil();
}
}
}
return instance;
}
/**
* 固定模板
* 创建带缓存的OkhttpClient
* 1.添加了缓存
* 2.添加了日志拦截器
*/
//自定义OKHTTPClient,设置超时、请求头、拦截器等
private OkHttpClient getOkHttpClient() {
//设置本地缓存文件
File cacheFile = new File(Constants.PATH_CACHE);
//设置缓存文件大小
//1 M = 1024Kb = 1024 * 1024 byte
Cache cache = new Cache(cacheFile, 1024 * 1024 * 100);
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.cache(cache)//缓存
.addInterceptor(new MyCacheinterceptor())
.addNetworkInterceptor(new MyCacheinterceptor())
//添加了请求头拦截器之后,所有使用网络框架的网络请求都会添加拦截器中的请求头
//不需要请求头的也加了请求头,是不影响请求
//.addInterceptor(new HeadersInterceptor())
//设置写入时间
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
//设置错误重连
.retryOnConnectionFailure(true);
//如果是debug状态(码农调试应用),添加日志拦截器,
// 如果是正式上线了isDebug该false,就不打印日志
if (Constants.isDebug) {
builder.addInterceptor(new LoggingInterceptor());
}
return builder.build();
}
/**
* 请求的修改设置
*/
/* public static class HeadersInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
//sp:shareprefrences
String token = (String) SpUtil.getParam(Constants.TOKEN,"");
//LogUtils.print("token:"+token);
Request request = chain.request().newBuilder()
.addHeader("Accept-Encoding", "identity")
.build();
return chain.proceed(request);
}
}*/
/**
* 固定模板
*/
private class MyCacheinterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//这里就是说判读我们的网络条件,要是有网络的话我么就直接获取网络上
// 面的数据,要是没有网络的话我么就去缓存里面取数据
if (!SystemUtil.isNetworkConnected()) {
request = request
.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)//强制使用缓存
.build();
}
Response originalResponse = chain.proceed(request);
if (SystemUtil.isNetworkConnected()) {
int maxAge = 0;
// 有网络时, 不缓存, 最大保存时长为0
return originalResponse.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public ,max-age=" + maxAge)
.build();
} else {
//s秒
int maxStale = 60 * 60 * 24;
return originalResponse.newBuilder()
.removeHeader("Pragma")
//这里的设置的是我们的没有网络的缓存时间,
// 想设置多少就是多少。
.header("Cache-Control", "public, only-if-cached," +
" max-age=" + maxStale)
.build();
}
}
}
//日志拦截器
public class LoggingInterceptor implements Interceptor {
private static final String TAG = "LoggingInterceptor";
@Override
public Response intercept(Chain chain) throws IOException {
//通过系统时间的差打印接口请求的信息
long time = System.nanoTime();
Request request = chain.request();
StringBuilder sb = new StringBuilder();
//把get和post请求提交的参数打印出来
if ("GET".equals(request.method())) { // GET方法
HttpUrl httpUrl = request.url().newBuilder().build();
sb.append("GET,");
// 打印所有get参数
Set<String> paramKeys = httpUrl.queryParameterNames();
for (String key : paramKeys) {
String value = httpUrl.queryParameter(key);
sb.append(key + ":" + value + ",");
}
} else if ("POST".equals(request.method())) { // POST方法
sb.append("POST,");
// FormBody和url不太一样,若需添加公共参数,需要新建一个构造器
/*FormBody.Builder bodyBuilder = new FormBody.Builder();
// 把已有的post参数添加到新的构造器
if (request.body() instanceof FormBody) {
FormBody formBody = (FormBody) request.body();
for (int i = 0; i < formBody.size(); i++) {
bodyBuilder.addEncoded(formBody.encodedName(i), formBody.encodedValue(i));
}
}
// 这里可以添加一些公共post参数
bodyBuilder.addEncoded("key_xxx", "value_xxx");
FormBody newBody = bodyBuilder.build();
// 打印所有post参数
for (int i = 0; i < newBody.size(); i++) {
Log.d("TEST", newBody.name(i) + " " + newBody.value(i));
}*/
if (request.body() instanceof FormBody) {
FormBody formBody = (FormBody) request.body();
for (int i = 0; i < formBody.size(); i++) {
sb.append(formBody.name(i)+":"+formBody.value(i)+",");
}
}
}
LogUtil.logd("Request:", String.format("Sending request %s %n %s %n%s", request.url(), sb.toString(),request.headers()));
Response response = chain.proceed(request);
long now = System.nanoTime();
LogUtil.logd("Received:", String.format("Received response for %s in %.1fms%n%s", response.request().url(), (now - time) / 1e6d, response.headers()));
//response.body().string(); 只能使用一次,使用之后就关流了
LogUtil.logd("Data:", response.peekBody(4096).string());
return response;
}
}
volatile ApiService mApiService;
//创建Retrofit请求数据接口,以前这么写是因为baseurl不固定
public ApiService getApiService(){
if (mApiService == null){
synchronized (HttpUtil.class){
if (mApiService == null){
mApiService = mRetrofitBuilder.baseUrl(ApiService.url)
.build()
.create(ApiService.class);
}
}
}
return mApiService;
}
//简单的日志拦截器
class SimpleLogInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
Log.d("SimpleLogInterceptor", "url: "+request.url()+
",data:"+response.peekBody(4096).string());
return response;
}
}
}
public class RxUtils {
public static <T> FlowableTransformer<T,T> rxSchedulerHelper(){
//compose简化线程
return new FlowableTransformer<T, T>() {
@Override
public Flowable<T> apply(Flowable<T> upstream) {
return upstream.subscribeOn(Schedulers.io())//被观察者执行的线程
.observeOn(AndroidSchedulers.mainThread());//观察者执行的线程
}
};
}
public static <T> ObservableTransformer<T,T> rxObserableSchedulerHelper(){
//compose 简化线程
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
return upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
}
public class SystemUtil {
/**
* 检查WIFI是否连接
*/
public static boolean isWifiConnected() {
ConnectivityManager connectivityManager = (ConnectivityManager) BaseApp.sContext.
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo wifiInfo = connectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return wifiInfo != null;
}
/**
* 检查手机网络(5G/4G/3G/2G)是否连接
*/
public static boolean isMobileNetworkConnected() {
ConnectivityManager connectivityManager = (ConnectivityManager) BaseApp.sContext.
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mobileNetworkInfo = connectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
return mobileNetworkInfo != null;
}
/**
* 检查是否有可用网络
*/
public static boolean isNetworkConnected() {
ConnectivityManager connectivityManager = (ConnectivityManager) BaseApp.sContext.
getSystemService(Context.CONNECTIVITY_SERVICE);
return connectivityManager.getActiveNetworkInfo() != null;
}
/**
* 保存文字到剪贴板
* @param context
* @param text
*/
public static void copyToClipBoard(Context context, String text) {
ClipData clipData = ClipData.newPlainText("url", text);
ClipboardManager manager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
manager.setPrimaryClip(clipData);
Toast.makeText(context,"已复制到剪贴板", Toast.LENGTH_SHORT).show();
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dp2px(float dpValue) {
final float scale = BaseApp.sContext.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dp(float pxValue) {
final float scale = BaseApp.sContext.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
public static int sp2px(float spValue) {
float scaledDensity = BaseApp.sContext.getResources().getDisplayMetrics().scaledDensity;
return (int)(spValue * scaledDensity + 0.5F);
}
public static int px2sp(float pxValue) {
float scaledDensity = BaseApp.sContext.getResources().getDisplayMetrics().scaledDensity;
return (int)(pxValue / scaledDensity + 0.5F);
}
/**
* 获取进程号对应的进程名
*
* @param pid 进程号
* @return 进程名
*/
public static String getProcessName(int pid) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("/proc/" + pid + "/cmdline"));
String processName = reader.readLine();
if (!TextUtils.isEmpty(processName)) {
processName = processName.trim();
}
return processName;
} catch (Throwable throwable) {
throwable.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException exception) {
exception.printStackTrace();
}
}
return null;
}
/**
* 关闭软键盘
*
* @param activity
*/
public static void closeKeyBoard(Activity activity) {
InputMethodManager im = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
if (activity.getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
if (activity.getCurrentFocus() != null)
im.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
}
}
}
具体代码参照:MVP抽取
网友评论