手机号码归属地查询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)


相关推荐

  • Pycharm控制台乱码问题[通俗易懂]

    Pycharm控制台乱码问题[通俗易懂]Pycharm控制台出现乱码的解决方法

  • 大数据时代的大数据管理发展,经历了哪几个阶段?

    大数据时代的大数据管理发展,经历了哪几个阶段?近几年,在大数据管理不断发展的过程中,也取得了一定的成绩。但是,大数据管理也经历了一个漫长的过程,主要经历的人工、文件、数据库等管理阶段。同时,随着大数据时代的大数据不断增加,所管理的范围和环境也在不断的变化。并且,在大数据管理不断发展的过程中,一些管理问题逐渐的暴露出来,为大数据管理的发展带来了新的挑战和机遇,下面就大数据管理的发展历程,管理中存在的不足进行简要的分析和阐述。1.大数据时代的…

  • 特立独行的理解_幸福在一起第14集

    特立独行的理解_幸福在一起第14集原题链接对一个十进制数的各位数字做一次平方和,称作一次迭代。如果一个十进制数能通过若干次迭代得到 1,就称该数为幸福数。1 是一个幸福数。此外,例如 19 经过 1 次迭代得到 82,2 次迭代后得到 68,3 次迭代后得到 100,最后得到 1。则 19 就是幸福数。显然,在一个幸福数迭代到 1 的过程中经过的数字都是幸福数,它们的幸福是依附于初始数字的。例如 82、68、100 的幸福是依附于 19 的。而一个特立独行的幸福数,是在一个有限的区间内不依附于任何其它数字的;其独立性就是依附于它的的幸福数

  • LNK2001: 无法解析的外部符号的几种情况

    LNK2001: 无法解析的外部符号的几种情况errorLNK2001:无法解析的外部符号无法解析几种情况:1&amp;amp;gt;MSVCRT.lib(MSVCR90.dll):errorLNK2005:_printf已经在libcurl.lib(pqueue.obj)中定义1&amp;amp;gt;MSVCRT.lib(MSVCR90.dll):errorLNK2005:_fprintf已经在libcurl.lib(pem_lib.o…

  • 卷积神经网络及其在图像处理中的应用

    卷积神经网络及其在图像处理中的应用一,前言卷积神经网络(ConstitutionalNeuralNetworks,CNN)是在多层神经网络的基础上发展起来的针对图像分类和识别而特别设计的一种深度学习方法。先回顾一下多层神经网络:多层神经网络包括一个输入层和一个输出层,中间有多个隐藏层。每一层有若干个神经元,相邻的两层之间的后一层的每一个神经元都分别与前一层的每一个神经元连接。在一般的识别问题中,输入层代表特征向量,输入

  • JAVA小白 编程练习500题 超详细!!!带答案!!!持续更新中~

    JAVA小白 编程练习500题 超详细!!!带答案!!!持续更新中~JAVA小白编程题练习可能有很多刚入门的小白不知道自己如何能快速提升编程技巧与熟练度其实大佬进阶之路只有一个~那就是疯狂码代码!!!实践出真知!!!所以为了大家能够想练习的时候有素材,泡泡给大家整理了一些练习题由于平时比较忙,所以我在不定时努力更新中,欢迎监督~500是立的Flag啊哈哈哈哈,我们共同努力吧,先出个100道,希望能给大家带来帮助~????????????练习题1:接收用户输入的3个整数,并将它们的最大值作为结果输出packagecn.cxy.exec;importj

发表回复

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

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