手机号码归属地查询App

手机号码归属地查询App结合MVP设计模式和解析Json数据,制作一款“手机号码归属地查询的App小程序(Android)”说明:实现的原理很简单,有多种设计方式和代码编写风格。本文主要是认识、理解MVP设计模式和Json数据的常见解析框架的使用。源码:请点击链接访问我的GitHub进行查看准备工作:AndroidStudio开发工具(谷爹的亲儿子)浏览器(进行测试淘宝开放平台返回给我们的Json数据并进行…

大家好,又见面了,我是你们的朋友全栈君。

结合MVP设计模式和解析Json数据,制作一款“手机号码归属地查询的App小程序(Android)”

说明:实现的原理很简单,有多种设计方式和代码编写风格。本文主要是认识、理解MVP设计模式和Json数据的常见解析框架的使用。

源码:请点击链接访问我的GitHub进行查看
准备工作:

  1. AndroidStudio 开发工具(谷爹的亲儿子)
  2. 浏览器(进行测试淘宝开放平台返回给我们的Json数据并进行解析)
  3. 一部真机或者模拟机(能上网的手机)

分析步骤:

1.实现界面
2.获取数据:
(1).本地数据(数据不是最新的)
(2).网络数据(数据是最新的)。【数据提供方:淘宝的开放接口。淘宝API的Web接口】
接口地址:https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=要查询的手机号码
3.解析数据
http框架:Okhttp框架
Json数据处理:Gson,FastJson,自带JsonObject
本例,笔者调用的是自己的手机号。通过解析淘宝开放平台提供的数据接口返回Json数据进行解析
https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13795950539
4.展现数据
MVP通知界面-》展示数据

Json解析框架介绍:

JSONObject:安卓自带的Json解析框架,采用对象和数组的2种方式解析.不能直接把JSon转化为java对象
Gson:Java对象和Json可以相互直接转换
FastJson:阿里提供的库,用法和Gson差不多,小巧,解析快

关于MVP和MVC的简要说明:

层次分明的代码:
低耦合:业务层-数据层-展示层。(要分离)
1.MVC模式
2.衍生MVP模式(业务和界面进行分离)
Activity充当了 MVP中的View 的“角色”,业务逻辑在Presenter进行实现
View与Presenter进行解耦:采用接口交互。(即笔者在此把View的主要操作抽象为接口,Presenter通过接口与View进行交互,所以Presenter就不必依赖于具体的View对象)

MVC:
MVC
MVP:
MVP
MVP的好处:
MVP的优势
MVP的使用:
MVP的使用
MVC和MVP的结构对比:
在这里插入图片描述
注:实战中代码的具体说明已经注释到相应代码段中,如有需要,请自行在GitHub中搜索我的库进行查看理解

编写程序:AndroidStudio 3.3

  1. 资源文件:

strings.xml:

<resources>
    <string name="app_name">手机号码归属地查询</string>
    <string name="query_phone">手机号码查询:</string>
    <string name="input_phone">请输入手机号码查询</string>
    <string name="query">查询</string>
    <string name="result_query">查询结果:</string>
    <string name="phone">手机号:未知</string>
    <string name="province">省份:未知</string>
    <string name="type">运营商:未知</string>
    <string name="belongtype">归属运营商:未知</string>
</resources>

colors.xml:
颜色不重要,自定义即可

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#008577</color>
    <color name="colorPrimaryDark">#00574B</color>
    <color name="colorAccent">#D81B60</color>

    <!--自定义颜色-->
    <!--标题颜色-->
    <color name="title_text_color">#F44336</color>
    <!--输入框提示文字颜色-->
    <color name="hint_color">#F44336</color>
    <!--按钮背景-->
    <color name="button_backgrond_color">#54673AB7</color>
    <!--查询结果标题文字颜色-->
    <color name="search_title_color">#3F51B5</color>
    <!--透明-->
    <color name="BarColor">#00FFFFFF</color>
</resources>


styles.xml:
主要是在默认的styles文件中,去掉了ActionBar,并且底部栏改成了白色

<resources xmlns:tools="http://schemas.android.com/tools">

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:navigationBarColor" tools:targetApi="lollipop">@color/BarColor</item>
    </style>

</resources>

  1. 界面布局:
    activity_main.xml:(文末有界面图片展示,有需要的话请自行复制)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:background="@drawable/background"
    tools:context=".MainActivity">
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="#673AB7"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
    </android.support.v7.widget.Toolbar>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="20dp"
        android:textColor="@color/title_text_color"
        android:text="@string/query_phone"
        android:textSize="20sp"/>
    <EditText
        android:id="@+id/input_phone"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_marginLeft="50dp"
        android:layout_marginRight="50dp"
        android:singleLine="true"
        android:maxLength="11"
        android:inputType="phone"
        android:textColor="#FF5722"
        android:textColorHint="@color/hint_color"
        android:hint="@string/input_phone"
        android:textSize="20sp"/>
    <Button
        android:id="@+id/btn_search"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:layout_marginTop="10dp"
        android:layout_gravity="center_horizontal"
        android:background="@color/button_backgrond_color"
        android:textColor="#ffff"
        android:text="@string/query"
        />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:layout_gravity="center_horizontal"
        android:textColor="@color/hint_color"
        android:text="@string/result_query"
        android:textSize="18sp"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="30dp"
        android:layout_marginTop="10dp"
        android:layout_marginRight="30dp"
        android:background="@color/button_backgrond_color"
        android:orientation="vertical">

        <TextView
            android:id="@+id/result_phone"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/button_backgrond_color"
            android:paddingLeft="40dp"
            android:paddingTop="15dp"
            android:paddingBottom="15dp"
            android:text="@string/phone"
            android:textColor="#FF5722"
            android:textSize="20sp" />

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#ffff" />

        <TextView
            android:id="@+id/result_province"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/button_backgrond_color"
            android:paddingLeft="40dp"
            android:paddingTop="15dp"
            android:paddingBottom="15dp"
            android:text="@string/province"
            android:textColor="#FF5722"
            android:textSize="20sp" />
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#ffff" />
        <TextView
            android:id="@+id/result_type"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/button_backgrond_color"
            android:paddingLeft="40dp"
            android:paddingTop="15dp"
            android:paddingBottom="15dp"
            android:text="@string/type"
            android:textColor="#FF5722"
            android:textSize="20sp" />
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#ffff" />
        <TextView
            android:id="@+id/result_carrier"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/button_backgrond_color"
            android:paddingLeft="40dp"
            android:paddingTop="15dp"
            android:paddingBottom="15dp"
            android:text="@string/belongtype"
            android:textColor="#FF5722"
            android:textSize="20sp" />
        <ProgressBar
            android:id="@+id/progress"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>
  1. MVP目录结构大致理解:
    MVP目录结构展示
    1.先看Model层次:
    在笔者自己的理解中,Model无非就是一个模型,我们可以理解为一个“模特(穿没穿衣服自己想象)”。然后就是这个Class的get()、set()方法,有了这样的条件,就组成了“人”的特点。所以说,Model也就是类的实体层,用于保存实例状态(保存“模特穿衣服的状态”)。
    2.再看View层次:
    其实说白了,View层就是我们的Activity.对于MVC设计模式,Activity充当着View和一部分Controller的角色。导致Activity的代码很臃肿,且不易维护,看起来蛋疼,没有真正做到一目了然的效果。所以,MVP就是把View和Controller分离开,便于项目的维护和升级。
    3.大哥大:Presenter(中文意思:委托者)也称为业务逻辑处理实现。【说白了,复杂的东西交给它来做】
    Presenter是Model和View之间的桥梁。
    看下图:
    MVP
    Model和View没有直接联系,那么他们是怎么进行交互的呢?
    答案当然是MVP的核心思想:把Activity中的UI逻辑抽象成View接口,把业务逻辑抽象成Presenter接口,Model类还是原来的Model
    这样,Activity的工作就简单了,只用来响应生命周期。
  2. MVP设计模式主要代码:
    (1).Model->Phone(实体):
package com.example.yinlei.phoneattributionquery.model;

/**
 * Model。可理解为没有数据的模型,存储我们的手机号码
 * 代表手机号这个实体。
 * 有哪些字段需要我们通过预先对数据源接口返回的Json数据进行观察
 * Example:淘宝返回给我的json数据为
 * _GetZoneResult_={
 *     mts:'1379595',
 *     province:'四川',
 *     catName:'中国移动',
 *     telString:'13795950539',
 *              areaVid:'30508',
 *              ispVid:'3236139'
 *              carrier:'四川移动'
 * }
 */
public class Phone {
    String telString;//手机号
    String province;//省份
    String catName;//运营商
    String carrier;//手机运营商


    public String getTelString() {
        return telString;
    }

    public void setTelString(String telString) {
        this.telString = telString;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCatName() {
        return catName;
    }

    public void setCatName(String catName) {
        this.catName = catName;
    }

    public String getCarrier() {
        return carrier;
    }

    public void setCarrier(String carrier) {
        this.carrier = carrier;
    }

}

上面的代码的原理笔者在上面已经阐述过了,就不再啰嗦了,请自行查看理解。

(2).View ->MainActivity:
因为MVP的Presenter和View进行交互是通过接口,所以这里实现了Presenter的impl包下的MvpMainView接口来传递数据【剩下就是接口回调的事了】
在这里简单实例化一下控件,点击监听OnClick()方法请先忽略,等下了解了Presenter后返回来处理。

package com.example.yinlei.phoneattributionquery;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.example.yinlei.phoneattributionquery.model.Phone;
import com.example.yinlei.phoneattributionquery.mvp.MvpMainView;
import com.example.yinlei.phoneattributionquery.mvp.impl.MainPresenter;


public class MainActivity extends AppCompatActivity implements View.OnClickListener, MvpMainView {
    EditText input_phone;
    Button btn_search;
    TextView result_phone;
    TextView result_province;
    TextView result_type;
    TextView result_carrier;
    MainPresenter mainPresenter;

    ProgressBar progressBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /**设置Toolbar*/
        Toolbar toolbar=findViewById(R.id.toolbar);//此处注意导入android.support.v7.widget.Toolbar。此包对应于android.support.v7.app.AppCompatActivity
        setSupportActionBar(toolbar);
        initView();//初始化控件
        btn_search.setOnClickListener(this);
        mainPresenter=new MainPresenter(this);
        mainPresenter.attach(this);
    }

    /**
     * 初始化控件
     */
    public void initView(){
        input_phone=findViewById(R.id.input_phone);
        btn_search=findViewById(R.id.btn_search);
        result_phone=findViewById(R.id.result_phone);
        result_province=findViewById(R.id.result_province);
        result_type=findViewById(R.id.result_type);
        result_carrier=findViewById(R.id.result_carrier);
        progressBar=findViewById(R.id.progress);
    }

    @Override
    public void onClick(View v) {
//        Toast.makeText(this, "点击了查询按钮", Toast.LENGTH_SHORT).show();
        mainPresenter.searchPhoneInfo(input_phone.getText().toString());//调用Presenter中的查询手机号码业务

    }

    /**以下是MvpMainView接口的方法*/
    @Override
    public void showToast(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
    }

    @Override
    public void updateView() {
       Phone phone= mainPresenter.getPhoneInfo();
       result_phone.setText("手机号码:"+phone.getTelString());
       result_province.setText("省份:"+phone.getProvince());
       result_type.setText("运营商:"+phone.getCatName());
       result_carrier.setText("归属运营商:"+phone.getCarrier());
    }

    @Override
    public void showLoading() {
        if (progressBar==null) {
            progressBar.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void hidenLoading() {
        if (progressBar!=null){
            progressBar.setVisibility(View.GONE);
        }
    }

    @Override
    protected void onDestroy() {
        mainPresenter.onDestroy();
        super.onDestroy();
    }
}

(3).Presenter:委托者
首先,把业务逻辑抽象成接口:
在这里插入图片描述
这里的MvpLoadingView接口是父类接口,把常用的方法提取到了父类。

MvpLoadingView:

package com.example.yinlei.phoneattributionquery.mvp;

/**
 * MvpMainView接口的父类
 * 主要是方便MvpMainView对父接口的复用
 */
public interface MvpLodingView {
    void showLoading();
    void hidenLoading();
}


MvpMainView:

package com.example.yinlei.phoneattributionquery.mvp;

/**
 * Presenter通过View的操作都是通过这个接口来进行处理业务
 */
public interface MvpMainView  extends MvpLodingView{
    void showToast(String msg);
    void updateView();
}

再创建Presenter:
在这里插入图片描述
其中,BasePresenter只是把常用的方法写了去,比如生命周期

package com.example.yinlei.phoneattributionquery.mvp.impl;

import android.content.Context;

/**
 * 把Activity中常用的方法写在基类里面
 */
public class BasePresenter {
    Context mContext;
    public void attach(Context context){
        mContext=context;
    }
    public void onPause(){}
    public void onResume(){}
    public void onDestroy(){
        mContext=null;//释放掉mContext.避免Activity在释放的时候,Presenter却还在使用Context而造成Activity释放不了引起内存泄漏
    }
}

注:这里的Context与MainActivity进行绑定,建立关联,避免了内存泄漏
然后来看看MainPresenter中主要做了什么事情:

package com.example.yinlei.phoneattributionquery.mvp.impl;

import android.widget.Toast;

import com.example.yinlei.phoneattributionquery.Until.HttpUntil;
import com.example.yinlei.phoneattributionquery.model.Phone;
import com.example.yinlei.phoneattributionquery.mvp.MvpMainView;
import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

/**
 * 处理MainActivity的逻辑
 * Presenter靠本类进行接口交互。
 */
public class MainPresenter extends BasePresenter{
//    示例Url:https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13795950539
    String mUrl="https://tcc.taobao.com/cc/json/mobile_tel_segment.htm";
    MvpMainView mvpMainView;//保存传递过来的MvpMainView接口数据
    Phone mPhone;//保存下方接口解析后的Phone实例
    public MainPresenter(MvpMainView mainView){
        mvpMainView=mainView;
    }
    public Phone getPhoneInfo(){//返回解析后并保存后的Phone实例
        return mPhone;
    }

    /**
     * 查询手机号
     * @param phone
     */
    public void searchPhoneInfo(String phone){
        if (phone.length()!=11){
            mvpMainView.showToast("请输入正确的手机号码!");
            return;
        }
        mvpMainView.showLoading();
        //Http请求的处理逻辑
        sendHttp(phone);
    }

    /**
     * Http请求的处理逻辑
     * @param phone
     */
    private void sendHttp(String phone){
        //构造Map,然后作为形参传入工具类中
        final Map<String,String>map=new HashMap<String, String>();
        map.put("tel",phone);

        //实例化网络请求工具类
        HttpUntil httpUntil=new HttpUntil(new HttpUntil.HttpResponse() {//构造方法需要我们传入接口(实例接口变量)
            @Override
            public void onSuccess(Object object) {//返回
                String json=object.toString();//返回给我们的数据:包含json数据
                int index=json.indexOf("{");
                json=json.substring(index);
                //上面的操作是提取数据中的json,去掉多余的数据
                //mPhone=parseJson(json);//自定义函数:采用安卓自带的JsonObject框架
               // mPhone=parseJsonWithGson(json);
                mPhone=parseJsonWithFastJson(json);

                mvpMainView.hidenLoading();
                mvpMainView.updateView();

            }

            @Override
            public void onFail(String error) {
                //通知View显示失败信息,关闭Loading界面
                mvpMainView.showToast(error);//接口回调:接口变量中的showToast方法有了数据。所以实现mvpMainView接口,就可以接口回调
                mvpMainView.hidenLoading();
            }
        });
        httpUntil.sendGetHttp(mUrl,map);//调用工具类中定义的通过Get方式请求的方法
    }

    /**
     * 解析淘宝API返回给我们的Json数据
     * 方法1:通过JSONobjectn框架解析
     * @param json
     * @return Phone
     */
    private Phone parseJson(String json){
        Phone phone=new Phone();
        try {
            JSONObject jsonObject=new JSONObject(json);
            String informationOfJson=jsonObject.getString("telString");
            phone.setTelString(informationOfJson);
             informationOfJson=jsonObject.getString("province");
            phone.setProvince(informationOfJson);
            informationOfJson=jsonObject.getString("catName");
            phone.setCatName(informationOfJson);
            informationOfJson=jsonObject.getString("carrier");
            phone.setCarrier(informationOfJson);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return phone;
    }

    /**
     * 方法2:解析Json通过GSON框架
     * @param json
     * @return Phone
     */
    private Phone parseJsonWithGson(String json){
        Gson gson=new Gson();
//        String myJson=gson.toJson(json);//处理空格
        Phone phone=gson.fromJson(json,Phone.class);//直接将Json转化为JAVA对象
        return phone;
    }

    /**
     * 方法3:解析Json通过FastJson框架(阿里)
     * @param json
     * @return Phone
     */
    private Phone parseJsonWithFastJson(String json){
        Phone phone= com.alibaba.fastjson.JSONObject.parseObject(json,Phone.class);
        return phone;
    }


}

本类主要是对于数据进行处理,比如网络请求,请求后再对返回的JSon数据进行解析。注意:这里的String phone是输入框获取到的用户输入,那么可想而知,我们应该对searchPhoneInfo()方法在MainActivity中的按钮监听事件中进行调用。
对于网络请求:为了便于维护,写在了工具包Until中,在本类直接 HttpUntil httpUntil=new HttpUntil(new HttpUntil.HttpResponse() {}就可以调用网络请求:
工具类下的HttpUntil类发送网络请求:(get/post方式都写上了,实际上本例只需要Post方式请求网络)

package com.example.yinlei.phoneattributionquery.Until;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * 工具类:进行Http请求
 */
public class HttpUntil {
    String mUrl;
    Map<String,String>mParam;
    HttpResponse mHttpResponse;//接口变量,保存接收到的接口数据

    private final OkHttpClient client=new OkHttpClient();

     Handler mHandler=new Handler(Looper.getMainLooper());//使用主线程(即Ui线程).用Handler处理线程之间的传递问题,即主线程与子线程之间的交互问题解决
    /**回调接口,拿到请求返回的结果*/
    public interface HttpResponse{
        void onSuccess(Object object);
        void onFail(String error);
    }

    public HttpUntil(HttpResponse response) {//构造函数:进行接口回调
        mHttpResponse=response;
    }

    /**Post请求方式提交表单*/
    public void sendPostHttp(String url, Map<String,String>param){
        sendHttp(url,param,true);
    }
    /**Get请求方式提交表单*/
    public void sendGetHttp(String url,Map<String,String>param){
        sendHttp(url,param,false);
    }

    /**通过上面的2个方法中任选一个方法,传入定义方法的参数值isPost*/
    private void sendHttp(String url,Map<String,String>param,boolean isPost){//Post请求方式
        mUrl=url;
        mParam=param;
        //编写Http请求逻辑
        request(isPost);//自定义请求方法
    }

    /**
     * 自定义请求方法:使用Okhttp网络请求框架
     *
     */
    private void request(boolean isPost){
        //request请求创建
        Request request=createRequest(isPost);//构建OkHttp中的Request实例
        //创建请求队列Call
        client.newCall(request).enqueue(new Callback() {//OkHttp中的匿名回调类(即接口回调)
            @Override
            public void onFailure(Call call, IOException e) {
                if (mHttpResponse!=null){//回调是否有赋值,有回调,就把回调结果返回给接口HttpResponse
                    //考虑一个问题:Call接口回调是运行在子线程中,如果直接调用回调方法,在UI线程中使用就不方便。所以在UI线程中去调用回调接口,需要全局的Handler进行处理
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            mHttpResponse.onFail("请求错误!");
                        }
                    });
                }
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                if (mHttpResponse==null)return;
                //HttpResponse的接口有被调用
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (!response.isSuccessful()){//请求失败
                            mHttpResponse.onFail("请求失败:"+response);
                        }else {//请求成功
                            try {
                                mHttpResponse.onSuccess(response.body().string());
                            } catch (IOException e) {
                                e.printStackTrace();
                                mHttpResponse.onFail("结果转换失败!");
                            }
                        }
                    }
                });
            }
        });
    }

    /**
     *自定义函数:封装了一下Okhttp中,构造一个Request对象实例
     * @param isPost
     * @return
     */
    private Request createRequest(boolean isPost){
        Request request;
        if (isPost){//是Post请求:需要提交请求参数
            //构建表单
            MultipartBody.Builder requestBodyBuilder=new MultipartBody.Builder();
            requestBodyBuilder.setType(MultipartBody.FORM);//设置类型
            //遍历Map请求参数:迭代器Iterator
            Iterator<Map.Entry<String,String>> iterator=mParam.entrySet().iterator();
            while (iterator.hasNext()){
                Map.Entry<String,String>entry=iterator.next();
                requestBodyBuilder.addFormDataPart(entry.getKey(),entry.getValue());
            }
            request=new Request.Builder().url(mUrl)
                    .post(requestBodyBuilder.build()).build();//构造Okhttp3的请求Request实例【Post方式】
        }else {//是Get请求:地址和参数进行拼接
            String urlStr=mUrl+"?"+MapParamToString(mParam);
            request=new Request.Builder().url(urlStr).build();//构造Okhttp3的请求Request实例【Get方式】
        }
        return request;//返回经过逻辑处理完成的Request对象
    }

    /**
     * 自定义方法:Map中的值按照url的格式进行拼接并返回它,然后再和mUrl进行完整的拼接
     * @param param
     * @return
     */
    private String MapParamToString(Map<String,String>param){
        StringBuilder stringBuilder=new StringBuilder();//字符串构造器
        /**遍历Map*/
        Iterator<Map.Entry<String,String>>iterator=param.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String,String>entry=iterator.next();
            //把Map参数按http的Get请求方式进行拼接
            stringBuilder.append(entry.getKey()+"="+entry.getValue()+"&");
        }
        //求掉最后一个"&"符号
        String str=stringBuilder.toString().substring(0,stringBuilder.length()-1);//subString()方法是提取一段String【java的String基础和数据结构中的串的知识点】
        return str;
    }



}

说明:本类方法还定义了一个接口,该类的内部定义的接口HttpResponse用于保存Okhttp回调时候返回的信息和 返回的Json数据。然后在MainPresenter中进行调用工具类的构造方法的时候就通过匿名实现接口HttpResponse中的方法。此时,实现的方法的参数是有数据的,且是工具类中接口已被赋有数据。即MainPresenter实现HttpResponse接口的方法,它的形参是已经被赋值后的。(理解接口回调)
在这里插入图片描述
逻辑就这样了,最后关于MainPresenter主要的业务是对Json数据进行解析,并转化成Phone(Model层)实例来保存解析后的带有数据的Model.(即现在是穿了衣服的模特啦!然后在View里面对界面进行展示数据通过Model的get和set方法)。

结果展示:
在这里插入图片描述
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/163184.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 图像处理——Canny算子

    图像处理——Canny算子首先感谢以下两位的渊博知识:(1)爱鱼     https://www.cnblogs.com/mightycode/p/6394810.html(2)mitutao  https://www.cnblogs.com/love6tao/p/5152020.html图像边缘信息主要集中在高频段,通常说图像锐化或检测边缘,实质就是高频滤波。我们知道微分运算是求信号的变化率,具有加

  • 轨迹规划——Bezier曲线与B样条曲线

    轨迹规划——Bezier曲线与B样条曲线一、Bezier曲线1、Bezier曲线的背景给定n+1个数据点,p0~pn,生成一条曲线,使得该曲线与这些点描述的形状相符。(如果要求曲线通过所有数据点,则属于插值问题;如果只要求曲线逼近这些数据点,则属于逼近问题。)2、Bezier曲线的定义p(t)=∑i=0naifi,n(t)p(t)=\sum_{i=0}^na_if_{i,n}(t)p(t)=i=0∑n​ai​fi,n…

  • 数据结构KMP_rsa算法例题

    数据结构KMP_rsa算法例题前言KMP算法是我们数据结构串中最难也是最重要的算法。难是因为KMP算法的代码很优美简洁干练,但里面包含着非常深的思维。真正理解代码的人可以说对KMP算法的了解已经相当深入了。而且这个算法的不少东西的确不容易讲懂,很多正规的书本把概念一摆出直接劝退无数人。这篇文章将尽量以最简单的方式介绍KMP算法以及他的改进,文章的开始我先对kmp算法的三位创始人Knuth,Morris,Pratt致敬,懂得这…

  • google Gmail_国外的新鲜玩意

    google Gmail_国外的新鲜玩意前不久,Google推出了Buzz,Buzz的说白了,就像QQ空间里面的好友关注,每天你登陆后,你都可以看到你所关注的好友做了哪些更新。让你和好友的关系更紧密。事实上,这个功能我甚至不会去使用它。为什么呢?因为我现在QQ上的好友更新已经太多了,我光是看QQ好友的更新已经觉得很累了。再去关注Buzz,想把我累死啊。。 所以其实现在中国的互联网市场上,成功还是腾讯和百度,Google是一个竞争…

    2022年10月15日
  • bat 延迟执行后面命令_bat命令延时10秒启动程序

    bat 延迟执行后面命令_bat命令延时10秒启动程序1、使用WScirpt的sleep功能,精度0.001秒创建vbs延迟文件,然后在批处理文件中调用,使用WScript的sleep函数,实现sleep的效果。实战:1)创建文件sleep.vbs:sleep.vbs内容如下:WScript.sleep5000。2)调用vbsstart/waitsleep.vbs1、使用choice命令choice/t10/cyn/n/dn/m(10秒后打开)CHOICE[/Cchoices][/.

  • 30套JSP网站源代码合集「建议收藏」

    30套JSP网站源代码合集「建议收藏」JSP技术是以Java语言作为脚本语言的,JSP网页为整个服务器端的Java库单元提供了一个接口来服务于HTTP的应用程序。我收集了一些JSP开发的网站源代码,从实践中学习,希望对大家有用。资料名称下载地址网上购物系统(jsp+mysql+tomcat) http://down.51cto.com/data/54179jsp网

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号