从0来搭建超灵活的MVP商用框架<一>-------从MVC至MVP的转变、通用网络切换框架

摘要:
事实上,我一直想记录MVC、MVP和MVVM体系结构演变的细节,因此我将借此机会准备详细回顾这一领域。就我的实际工作而言,我仍然习惯于MVC的传统代码习惯。我已经习惯了很多年,无法改变。然而,MVP的代码风格在当前项目中越来越流行,然而,MVC和MVP风格在项目中经常共存,因此迫切需要习惯MVP风格的代码风格。最后,我们将构建公司使用的MVP的非常简洁的企业级实现框架。让我们从底部开始。

其实早就想记录关于MVC、MVP、MVVM架构的演变细节了,所以接下来借此机会准备对于这块的东东详细进行一个梳理,就自己实际工作而言还是习惯用MVC传统的代码习惯,毕境习惯了它N多年了有点改不过来,而对于MVP的代码风格在目前的项目上基本上已经越来越普及了,而往往项目中MVC和MVP风格都并存在的,所以习惯MVP风格的代码风格也是当务之急的,最终会打造目前公司所用的MVP的非常精简的企业级实现框架,好下面从点滴开始。

从MVC风格开始:

在正式学习MVP之前,还是对于人人皆知的MVC风格代码进行一个复习,这里以一个加载本地图片列表功能为例,之后会用MVP进行改造的,先看下效果:

从0来搭建超灵活的MVP商用框架<一>-------从MVC至MVP的转变、通用网络切换框架第1张

由于比较简单,代码贴出来如下:

从0来搭建超灵活的MVP商用框架<一>-------从MVC至MVP的转变、通用网络切换框架第2张

packagecom.android.mvparcstudy;

importandroidx.appcompat.app.AppCompatActivity;

importandroid.os.Bundle;
importandroid.widget.ListView;

importcom.android.mvparcstudy.adapter.MyAdapter;
importcom.android.mvparcstudy.bean.Shoe;

importjava.util.ArrayList;
importjava.util.List;

public class MainActivity extendsAppCompatActivity {

    privateListView listView;

    @Override
    protected voidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listView =findViewById(R.id.listView);
        loadData();
    }

    private voidloadData() {
        List<Shoe> data = new ArrayList<>();
        data.add(new Shoe(R.drawable.shop1, 1000, 10000));
        data.add(new Shoe(R.drawable.shop2, 111, 90));
        data.add(new Shoe(R.drawable.shop3, 2222, 800));
        data.add(new Shoe(R.drawable.shop4, 333, 110));
        data.add(new Shoe(R.drawable.shop5, 4444, 220));
        data.add(new Shoe(R.drawable.shop6, 100, 330));
        data.add(new Shoe(R.drawable.shop7, 20, 0));
        data.add(new Shoe(R.drawable.shop8, 10000, 20));
        data.add(new Shoe(R.drawable.shop9, 500, 120));
        data.add(new Shoe(R.drawable.shop10, 30, 400));
        listView.setAdapter(new MyAdapter(this, data));
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent">

    <ListView
        android:id="@+id/listView"android:layout_width="fill_parent"android:layout_height="fill_parent" />
</LinearLayout>
packagecom.android.mvparcstudy.bean;

/*** 实体
 */
public classShoe {

    public inticon;
    public int sales;//销量
    public int inventory;//库存

    public Shoe(int icon, int sales, intinventory) {
        this.icon =icon;
        this.sales =sales;
        this.inventory =inventory;
    }

    publicShoe() {
    }

    public intgetIcon() {
        returnicon;
    }

    public void setIcon(inticon) {
        this.icon =icon;
    }

    public intgetSales() {
        returnsales;
    }

    public void setSales(intsales) {
        this.sales =sales;
    }

    public intgetInventory() {
        returninventory;
    }

    public void setInventory(intinventory) {
        this.inventory =inventory;
    }
}
packagecom.android.mvparcstudy.adapter;


importandroid.content.Context;
importandroid.view.LayoutInflater;
importandroid.view.View;
importandroid.view.ViewGroup;
importandroid.widget.BaseAdapter;
importandroid.widget.ImageView;
importandroid.widget.TextView;

importcom.android.mvparcstudy.R;
importcom.android.mvparcstudy.bean.Shoe;

importjava.util.List;


public class MyAdapter extendsBaseAdapter {

    privateLayoutInflater inflater;
    private List<Shoe>shoes;

    public MyAdapter(Context context, List<Shoe>girs) {
        inflater =LayoutInflater.from(context);
        this.shoes =girs;
    }

    @Override
    public intgetCount() {
        returnshoes.size();
    }

    @Override
    public Object getItem(intposition) {
        returnshoes.get(position);
    }

    @Override
    public long getItemId(intposition) {
        returnposition;
    }

    @Override
    public View getView(intposition, View convertView, ViewGroup parent) {

        View view = inflater.inflate(R.layout.item, null);
        Shoe g =shoes.get(position);
        ImageView iv_icon =(ImageView) view.findViewById(R.id.iv_icon);
        iv_icon.setImageResource(g.icon);

        TextView tv_like =(TextView) view.findViewById(R.id.tv_like);
        tv_like.setText("销量:" +g.sales);

        TextView tv_style =(TextView) view.findViewById(R.id.tv_style);
        tv_style.setText("库存:" +g.inventory);

        returnview;
    }

}

item.xml:

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent">

    <ImageView
        android:id="@+id/iv_icon"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true" />

    <LinearLayout
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="8dip"android:layout_marginTop="20dip"android:layout_toRightOf="@id/iv_icon"android:orientation="vertical">

        <TextView
            android:id="@+id/tv_style"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#666"android:textSize="18sp" />

        <TextView
            android:id="@+id/tv_like"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="10dip"android:textColor="#666"android:textSize="15sp" />

    </LinearLayout>

</RelativeLayout>

另外图片都是从网上下载的,这里就不贴了,这种代码是我们最最常见的。

MVC与MVP的区别:

这里贴一张对比图,其实基本上都知道它们之间的区别:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第3张

简单来说对于MVP架构来说,就是把UI逻辑抽象成View接口,而把业务逻辑抽象成Presenter接口,Model还是原来的数据。大致流程会是这样:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第4张

将MVC改造成MVP:

好,接下来咱们将咱们的这个MVC的DEMO一点点转换成MVP, 先来建三个MVP的文件夹,好对代码进行归类:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第5张

定义V:

再来定义View,这里面只定义纯跟UI相关的接口:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第6张

定义M:

先来再来定义Model的接口,加载数据及数据的回调主要是靠它:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第7张

好,接下来则定义一个该Model的实现类:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第8张

packagecom.android.mvparcstudy.model;

importcom.android.mvparcstudy.R;
importcom.android.mvparcstudy.bean.Shoe;

importjava.util.ArrayList;
importjava.util.List;

public class MainModel implementsIMainModel {
    @Override
    public voidloadData(OnLoadListener onLoadListener) {
        List<Shoe> data = new ArrayList<>();
        data.add(new Shoe(R.drawable.shop1, 1000, 10000));
        data.add(new Shoe(R.drawable.shop2, 111, 90));
        data.add(new Shoe(R.drawable.shop3, 2222, 800));
        data.add(new Shoe(R.drawable.shop4, 333, 110));
        data.add(new Shoe(R.drawable.shop5, 4444, 220));
        data.add(new Shoe(R.drawable.shop6, 100, 330));
        data.add(new Shoe(R.drawable.shop7, 20, 0));
        data.add(new Shoe(R.drawable.shop8, 10000, 20));
        data.add(new Shoe(R.drawable.shop9, 500, 120));
        data.add(new Shoe(R.drawable.shop10, 30, 400));
        onLoadListener.onComplete(data);
    }
}

定义P:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第9张

packagecom.android.mvparcstudy.presenter;

importcom.android.mvparcstudy.bean.Shoe;
importcom.android.mvparcstudy.model.IMainModel;
importcom.android.mvparcstudy.model.MainModel;
importcom.android.mvparcstudy.view.IMainView;

importjava.util.List;

public classMainPresenter {

    //持有左边(VIEW)
IMainView iMainView;
    //持有右边(MODEL)
    IMainModel iMainModel = newMainModel();

    publicMainPresenter(IMainView mainView) {
        this.iMainView =mainView;
    }

    //执行UI逻辑
    public voidfetch() {
        if (iMainModel != null && iMainView != null) {
            iMainModel.loadData(newIMainModel.OnLoadListener() {
                @Override
                public void onComplete(List<Shoe>shoes) {
                    //再交给view
iMainView.showListView(shoes);
                }
            });
        }
    }

}

应用于Activity上:

此时则在Activity将P进行初始化并处理回调,如下:

packagecom.android.mvparcstudy;

importandroid.os.Bundle;
importandroid.widget.ListView;

importandroidx.appcompat.app.AppCompatActivity;

importcom.android.mvparcstudy.adapter.MyAdapter;
importcom.android.mvparcstudy.bean.Shoe;
importcom.android.mvparcstudy.presenter.MainPresenter;
importcom.android.mvparcstudy.view.IMainView;

importjava.util.List;

public class MainActivity extends AppCompatActivity implementsIMainView {

    privateListView listView;
    privateMainPresenter mainPresenter;

    @Override
    protected voidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listView =findViewById(R.id.listView);
        mainPresenter = new MainPresenter(this);
        loadData();
    }

    private voidloadData() {
        mainPresenter.fetch();
    }

   @Override
    public void showListView(List<Shoe> shoes) {
        listView.setAdapter(new MyAdapter(this, shoes));
    }
}

MVP框架进一步优化:

P层对于V层的强引用消除:

对于上面MVP的使用中其实还是有一些待优化的地方,首先是P层强引用了V,如下:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第10张

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第11张

这样会干扰V的回收动作,所以接下来用弱引用来解决这种强引用的关系:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第12张

这样的话就不存在内存泄漏的问题了。

加入绑定与解绑管理:

目前P层加入了虚引用了之后,其回收动作并不是特别及时,正常应该是在Activity进入时创建,而在Activity退出时则需要将P中的这个引用给去掉,这样性能也比较好,所以接下来加入绑定与解绑的处理来进一步改造P中的代码,如下:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第13张

所以此时的Activity中的调用变化为:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第14张

抽一个BasePresenter:

在上面一步我们对P中增加了绑定与解绑的操作,对于这个操作其实每个P层都需要,很显然需要将这个通用行为往上抽,而不是每个同样类似的代码都散步在各个具体的P层中,这也是平常写业务代码时好的一个习惯,于是乎抽一个Base就很有必要的:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第15张

packagecom.android.mvparcstudy.presenter;

importcom.android.mvparcstudy.view.IMainView;

importjava.lang.ref.WeakReference;

public class BasePresenter<T extends IMainView>{

    //持有左边(VIEW)
    WeakReference<T>iMainView;

    public voidattachView(T view) {
        this.iMainView = new WeakReference<>(view);
    }

    public voiddetachView() {
        if (iMainView != null) {
            iMainView.clear();
            iMainView = null;
        }
    }
}

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第16张

嗯,但是呢,这个Base还是有点问题:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第17张

所以,对于这个UI接口还得抽一个Base出来:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第18张

目前通用的UI接口一般就是显示与隐藏对话框,这个根据实际具体的业务需要可以再次进行扩展。

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第19张

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第20张

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第21张

抽取一个BaseActivity:

对于Activity中创建P层的代码其实也可以往上抽,这样更加的精简,如下:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第22张

packagecom.android.mvparcstudy.view;

importandroid.os.Bundle;

importandroidx.annotation.Nullable;
importandroidx.appcompat.app.AppCompatActivity;

importcom.android.mvparcstudy.presenter.BasePresenter;

public abstract class BaseActivity<T extends BasePresenter, V extends IBaseView> extendsAppCompatActivity {
    //持有表示层
    protectedT presenter;

    @Override
    protected voidonCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //由activity选择一个表示层
        presenter =createPresenter();
        if(presenter == null)
            throw new NullPointerException("presenter is null。");
        presenter.attachView((V) this);

    }

    @Override
    protected voidonDestroy() {
        super.onDestroy();
        presenter.detachView();
    }

    protected abstractT createPresenter();
}

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第23张

加入灵活网络切换框架:

背景:

上面MVP框架已经搭建好了,接下来这里加入一个跟MVP木有关系的框架,对于实际项目架构来说还是很重要的,下面先来描述一下要写这个框架的一个背景原因:

对于App来说,我们在商用时都会用各种成熟的三方框架,而且这些三方框架可能随着时代的变迁流行度可能也会变,咱们挼一下目前觉见的一些框架:

网络访问:retrofit、 okhttp、volley、xutils. . .

数据库:greendao、 room、 realm. . .

图片加载:imageloader、glide、picasso. . .

地图API:百度百图、腾讯地图、高德地图. . .

.....

这里就拿网络访问三方框架来说,目前基本上可能都是用retrofit+okhttp来对我们的网络访问进行封装,而假如哪一天这俩框架不行了需要将项目中所有的网络框架都改成volley,如果没有一个灵活切换的机制是不是得手动将所有的网络框架手动替换一下volley的实现?此时这种方式切换起来成本是很高的,所以在APP架构时如果能提前就将这种灵活度给考虑进去的话,那可以很从容的应对这种切换框架的需求的,所以接下来则打造一个满足这种切换背景的灵活框架,有了这个思路之后在实际工作中如果架构app时就可以借鉴一下。

思路:

这个实现思路就是在APP及框架使用中间加了一个能为我们动态切换的一个隔离层既可,用个示例图简单展示一下:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第24张

具体实现:

先来建立一个隔离的module层:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第25张

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第26张

好先来定义好通用的网络接口,这里只定义一个就成了,重点是了解整个框架的构建过程,实际可以根据自己的业务去扩展就成了:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第27张

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第28张

这里以返回JSON的格式为例,具体其它格式可以基于它进行扩展的,接下来则来实现一下这个回调,这里以Json转对像为例:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第29张

packagecom.android.isolation_processor.httpprocessor;

importcom.google.gson.Gson;

importjava.lang.reflect.ParameterizedType;
importjava.lang.reflect.Type;

/*** 回调接口的json版本的实现类
 * 用于把网络返回的json字符串转让换成对象(Result就是用户接收数据的类型,不用T来表示泛型增加可读性)
 * //ResponceData就是Result
 */
public abstract class HttpCallback<Result> implementsICallback {
    @Override
    public void onSuccess(String result) {//result就是网络回来的数据
        //result把转换成用户需要的对象
        Gson gson = newGson();
        //需要得到用户输入的对象对应的字节码是什么样的
        //得到用户接收数据的对象对应的class
        Class<?> clz = analysisClassInfo(this);

        Result objResult =(Result) gson.fromJson(result, clz);

        //把已经转好的对象,交给用户
onSuccess(objResult);
    }

    public abstract voidonSuccess(Result result);

    private Class<?>analysisClassInfo(Object object) {
        //getGenericSuperclass可以得到包含原始类型,参数化类型,数组,类型变量,基本数据
        Type genType =object.getClass().getGenericSuperclass();
        //获取参数化类型
        Type[] params =((ParameterizedType) genType).getActualTypeArguments();
        return (Class<?>) params[0];
    }

    @Override
    public voidonFailure(String e) {

    }
}

上面的代码比较简单就不多解释了,也就是将JSON转换成我们要获取的那个对象,然后这里加几个依赖:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第30张

好,接下来则写一个工具类来使用一下这个网络框架,这里面都是用的抽象接口,以便在表示层可以进行具体网络框架的切换,代码也比较简单,直接贴出:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第31张

packagecom.android.isolation_processor.httpprocessor;

importjava.io.UnsupportedEncodingException;
importjava.net.URLEncoder;
importjava.util.Map;

public class HttpHelper implementsIHttpProcessor {

    private staticHttpHelper instance;

    public staticHttpHelper obtain() {
        synchronized (HttpHelper.class) {
            if (instance == null) {
                instance = newHttpHelper();
            }
        }
        returninstance;
    }

    privateHttpHelper() {
    }

    private staticIHttpProcessor mIHttpProcessor;

    //定义一个API,由应用层来决定用哪一个网络框架的实现
    public static voidinit(IHttpProcessor iHttpProcessor) {
        mIHttpProcessor =iHttpProcessor;
    }


    @Override
    public void post(String url, Map<String, Object>params, ICallback callback) {
        //url:http://www.aaa.bbb/index
        //params:user=jett&pwd=123
        //将其组拼到一块:http://www.aaa.bbb/index?&user=jett&pwd=123
        String finalUrl =appendParams(url, params);
        mIHttpProcessor.post(finalUrl, params, callback);
    }

    public static String appendParams(String url, Map<String, Object>params) {
        if (params == null ||params.isEmpty()) {
            returnurl;
        }
        StringBuilder urlBuilder = newStringBuilder(url);
        if (urlBuilder.indexOf("?") <= 0) {
            urlBuilder.append("?");
        } else{
            if (!urlBuilder.toString().endsWith("?")) {
                urlBuilder.append("&");
            }
        }
        for (Map.Entry<String, Object>entry : params.entrySet()) {
            urlBuilder.append("&" +entry.getKey())
                    .append("=")
                    .append(encode(entry.getValue().toString()));
        }
        returnurlBuilder.toString();
    }

    private staticString encode(String str) {
        try{
            return URLEncoder.encode(str, "utf-8");
        } catch(UnsupportedEncodingException e) {
            e.printStackTrace();
            throw newRuntimeException();
        }
}

}

好,接下来咱们来实现几个具体的网络请求,这里实现四个:Okhttp、Volley、XUtils,代码就不一一解释了,基本上都很熟了:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第32张

packagecom.android.isolation_processor.httpprocessor;

importandroid.os.Handler;

importjava.io.IOException;
importjava.util.Map;

importokhttp3.Call;
importokhttp3.Callback;
importokhttp3.FormBody;
importokhttp3.OkHttpClient;
importokhttp3.Request;
importokhttp3.RequestBody;
importokhttp3.Response;

public class OkHttpProcessor implementsIHttpProcessor {
    privateOkHttpClient mOkHttpClient;
    privateHandler myHandler;

    publicOkHttpProcessor() {
        mOkHttpClient = newOkHttpClient();
        myHandler = newHandler();
    }

    private RequestBody appendBody(Map<String, Object>params) {
        FormBody.Builder body = newFormBody.Builder();
        if (params == null ||params.isEmpty()) {
            returnbody.build();
        }
        for (Map.Entry<String, Object>entry : params.entrySet()) {
            body.add(entry.getKey(), entry.getValue().toString());
        }
        returnbody.build();
    }

    @Override
    public void post(String url, Map<String, Object> params, finalICallback callback) {
        RequestBody requestBody =appendBody(params);
        Request request = newRequest.Builder()
                .url(url)
                .post(requestBody)
                .build();
        mOkHttpClient.newCall(request).enqueue(newCallback() {
            @Override
            public voidonFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throwsIOException {
                final String result =response.body().string();
                if(response.isSuccessful()) {
                    myHandler.post(newRunnable() {
                        @Override
                        public voidrun() {
                            callback.onSuccess(result);
                        }
                    });
                }

            }
        });
    }
}
packagecom.android.isolation_processor.httpprocessor;

importandroid.content.Context;

importcom.android.volley.Request;
importcom.android.volley.RequestQueue;
importcom.android.volley.Response;
importcom.android.volley.VolleyError;
importcom.android.volley.toolbox.StringRequest;
importcom.android.volley.toolbox.Volley;

importjava.util.Map;

public class VolleyProcessor implementsIHttpProcessor {

    private static RequestQueue mQueue = null;

    publicVolleyProcessor(Context context) {
        mQueue =Volley.newRequestQueue(context);
    }

    @Override
    public void post(String url, Map<String, Object> params, finalICallback callback) {
        StringRequest stringRequest = newStringRequest(
                Request.Method.POST,
                url,
                new Response.Listener<String>() {
                    @Override
                    public voidonResponse(String response) {
                        callback.onSuccess(response);

                    }
                }, newResponse.ErrorListener() {
            @Override
            public voidonErrorResponse(VolleyError error) {

            }
        }
        );
        mQueue.add(stringRequest);
    }
}
packagecom.android.isolation_processor.httpprocessor;


importandroid.app.Application;

importorg.xutils.common.Callback;
importorg.xutils.http.RequestParams;
importorg.xutils.x;

importjava.util.Map;

public class XUtilsProcessor implementsIHttpProcessor {
    publicXUtilsProcessor(Application app) {
        x.Ext.init(app);
    }

    @Override
    public void post(String url, Map<String, Object> params, finalICallback callback) {
        RequestParams requestParams = newRequestParams(url);
        x.http().post(requestParams, new Callback.CommonCallback<String>() {
            @Override
            public voidonSuccess(String result) {
                callback.onSuccess(result);
            }

            @Override
            public void onError(Throwable ex, booleanisOnCallback) {

            }

            @Override
            public voidonCancelled(CancelledException cex) {

            }

            @Override
            public voidonFinished() {

            }
        });
    }
}

接下来咱们就可以来调用这个隔离层了:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第33张

然后咱们在Model层中来写一个测试代码验证一下:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第34张

其中得要JSON转换的一个对象:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第35张

packagecom.android.mvparcstudy.bean;

public classResponceData {

    /*** result : null
     * reason : 当前可请求的次数不足
     * error_code : 10012
     * resultcode : 112
     */
    privateString result;
    privateString reason;
    private interror_code;
    privateString resultcode;

    public voidsetResult(String result) {
        this.result =result;
    }

    public voidsetReason(String reason) {
        this.reason =reason;
    }

    public void setError_code(interror_code) {
        this.error_code =error_code;
    }

    public voidsetResultcode(String resultcode) {
        this.resultcode =resultcode;
    }

    publicString getResult() {
        returnresult;
    }

    publicString getReason() {
        returnreason;
    }

    public intgetError_code() {
        returnerror_code;
    }

    publicString getResultcode() {
        returnresultcode;
    }
}

添加一下网络权限:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第36张

好运行,看能不正常请求下来:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第37张

妥妥的, 此时咱们再来切换一下网络框架,超简单:

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第38张

从0来搭建超灵活的MVP商用框架&lt;一&gt;-------从MVC至MVP的转变、通用网络切换框架第39张

之后如果有类似要动态切的需求就可以用这套框架来搭建,还是挺灵活的。

免责声明:文章转载自《从0来搭建超灵活的MVP商用框架&amp;lt;一&amp;gt;-------从MVC至MVP的转变、通用网络切换框架》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇树莓派 HC-SRO4超声波测距模块的使用基于ServiceStack.OrmLite框架 代码性能、开发效率皆第一 没有之一下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

开源netcore前后端分离,前端服务端渲染方案

SPA单页面应用容器开源地址:https://github.com/yuzd/Spa 功能介绍 前端应用开发完后打包后自助上传部署发布 配合服务端脚本(javascript)实现服务端业务逻辑编写渲染SSR功能 可以快速回滚到上一个版本 可以设置环境变量供SSR功能使用 服务端脚本提供执行日志 redis db三大组件打造强大的基于js的ssr服务端...

Java 9 揭秘(19. 平台和JVM日志)

Tips做一个终身学习的人。 在这章中,主要介绍以下内容: 新的平台日志(logging)API JVM日志的命令行选项 JDK 9已经对平台类(JDK类)和JVM组件的日志系统进行了大整。 有一个新的API可以指定所选择的日志框架作为从平台类记录消息的日志后端。 还有一个新的命令行选项,可以从所有JVM组件访问消息。 在本章中,详细介绍两个记录工具...

SqlAlchemy

SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。 Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如: 1 MySQL-Python 2...

C#字符串和ASCII码的转换

C# 字符转ASCII码,ASCII码转字符 //字符转ASCII码:public static int Asc(string character) {if (character.Length == 1) { System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEnco...

XmlDocument的应用创建Xml模板

 protected void btnCreate_Click(object sender, EventArgs e)        {            //定义XMLDocument            XmlDocument xmlDocument = new XmlDocument();            //定义XML文档头文件   ...

实践Kong for Kubernetes(K8S),kong最新2.1版本和kong-ingress-controller:0.9.1版本

先决条件 Kubernetes集群:您可以使用Minikube或GKE集群。Kong与Kubernetes的所有发行版兼容。 kubectl访问权限:您应该已经kubectl安装并配置为与Kubernetes集群通信。 为Kubernetes安装Kong 使用以下安装方法之一安装Kong for Kubernetes: YAML清单 helm K...