android 开发架构设计之MVP模式+okhttp3 WebSocket网络请求(如有问题,欢迎留言)

本文适合有一定的基础开发人员,主要介绍了android MVP模式和okhttp3的WebSocket网络请求,代码已经全部贴出,按照项目样式进行封装的,仔细的看两遍,相信你会有所收获。如果对本文有所疑惑,欢迎发送问题到qq1164688204(做良心代码,坚决不给阅览者留坑)。

(1)Activity代码实现@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

package com.mobile.appmine.appmvpmode;

import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import com.mobile.appmine.appmvpmode.base.BaseActivity;
import com.mobile.appmine.appmvpmode.presenter.MvpPresenter;
import com.mobile.appmine.appmvpmode.service.MyService;
import com.mobile.appmine.appmvpmode.view.MvpView;

import butterknife.BindView;
import butterknife.ButterKnife;

public class MainActivity extends BaseActivity implements MvpView, View.OnClickListener {

    @BindView(R.id.tev_show_data)
    TextView tevShowData;
    @BindView(R.id.tev_get_data_success)
    TextView tevGetDataSuccess;
    @BindView(R.id.tev_get_data_failed)
    TextView tevGetDataFailed;
    @BindView(R.id.tev_get_data_error)
    TextView tevGetDataError;
    @BindView(R.id.tev_request_connect)
    TextView tevRequestConnect;

    //进度条
    private ProgressDialog progressDialog;
    private MvpPresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);


        initData();
        initView();
    }

    private void initData() {
        // 初始化进度条
        progressDialog = new ProgressDialog(this);
        progressDialog.setCancelable(false);
        progressDialog.setMessage("正在加载数据");
        //初始化Presenter
        presenter = new MvpPresenter();
        // 绑定View引用
        presenter.attachView(this);
    }

    private void initView() {
        tevRequestConnect.setOnClickListener(this);
        tevGetDataSuccess.setOnClickListener(this);
        tevGetDataFailed.setOnClickListener(this);
        tevGetDataError.setOnClickListener(this);
    }

    @Override
    public void showLoading() {
        if (!progressDialog.isShowing()) {
            progressDialog.show();
        }
    }

    @Override
    public void hideLoading() {
        if (progressDialog.isShowing()) {
            progressDialog.dismiss();
        }
    }

    @Override
    public void showConWebSocket(String conStr) {
        showToast("WebSocket连接成功");
        showToast(conStr);
    }

    @Override
    public void showData(String data) {
        showToast(data);
        tevShowData.setText(data);
    }

    @Override
    public void showFailureMessage(String msg) {
        showToast(msg);
        tevShowData.setText(msg);
    }

    @Override
    public void showErrorMessage() {
        showToast("网络请求数据出现异常");
        tevShowData.setText("网络请求数据出现异常");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 断开View引用
        presenter.detachView();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.tev_request_connect:
                //连接WebSocket
                presenter.requestConWebSocket("onOpen");
                break;
            case R.id.tev_get_data_success:
                //获取数据成功
                presenter.getData("Success");
                break;
            case R.id.tev_get_data_failed:
                //获取数据成功
                presenter.getData("Failed");
                break;
            case R.id.tev_get_data_error:
                //获取数据成功
                presenter.getData("Error");
                break;
            default:
                break;
        }
    }
}

(2)View代码@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

package com.mobile.appmine.appmvpmode.base;

import android.content.Context;

/**
 * Created by Administrator on 2018/6/26 0026.
 */

public interface BaseView {

    /**
     * 显示正在加载view
     */
    void showLoading();

    /**
     * 关闭正在加载view
     */
    void hideLoading();

    /**
     * 显示提示
     *
     * @param msg
     */
    void showToast(String msg);

    /**
     * 显示请求错误提示
     */
    void showErr();

    /**
     * 获取上下文
     *
     * @return 上下文
     */
    Context getContext();
}

(3)Presenter代码实现@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

package com.mobile.appmine.appmvpmode.presenter;

import android.util.Log;

import com.mobile.appmine.appmvpmode.callback.MvpCallback;
import com.mobile.appmine.appmvpmode.base.BasePresenter;
import com.mobile.appmine.appmvpmode.model.UserDataModel;
import com.mobile.appmine.appmvpmode.view.MvpView;

/**
 * Created by Administrator on 2018/6/26 0026.
 */

public class MvpPresenter extends BasePresenter<MvpView> {

    private UserDataModel userDataModel;
    private static final String TAG = MvpPresenter.class.getSimpleName();

    /**
     * 构造方法中不再需要View参数
     */
    public MvpPresenter() {
    }

    /**
     * 绑定view,一般在初始化中调用该方法
     */
    @Override
    public void attachView(MvpView mvpView) {
        super.attachView(mvpView);
        this.mvpView = mvpView;
        userDataModel = new UserDataModel();
    }

    /**
     * 断开view,一般在onDestroy中调用
     */
    @Override
    public void detachView() {
        super.detachView();
        this.mvpView = null;
        userDataModel.detachView();
    }

    /**
     * 是否与View建立连接
     * 每次调用业务请求的时候都要出先调用方法检查是否与View建立连接
     */
    @Override
    public boolean isViewAttached() {
        super.isViewAttached();
        return mvpView != null;
    }

    /**
     * 获取网络数据
     *
     * @param params 参数
     */
    public void requestConWebSocket(String... params) {
        if (!isViewAttached()) {
            //如果没有View引用就不加载数据
            return;
        }
        //显示正在加载进度条
        getView().showLoading();

        userDataModel
                // 添加请求参数,没有则不添加
                .params(params[0])
                // 注册监听回调
                .requestConWebSocket(new MvpCallback<String>() {
                    @Override
                    public void onConWebSocket(String data) {
                        Log.i(TAG, "requestConWebSocket onConWebSocket");
                        //调用view接口显示数据
                        getView().showConWebSocket(data);
                    }

                    @Override
                    public void onSuccess(String data) {
                        //调用view接口显示数据
                        getView().showData(data);
                        Log.i(TAG, "requestConWebSocket onSuccess");
                    }

                    @Override
                    public void onFailure(String msg) {
                        //调用view接口提示失败信息
                        getView().showFailureMessage(msg);
                    }

                    @Override
                    public void onError() {
                        //调用view接口提示请求异常
                        getView().showErrorMessage();
                    }

                    @Override
                    public void onComplete() {
                        // 隐藏正在加载进度条
                        getView().hideLoading();
                    }
                });
    }

    /**
     * 获取网络数据
     *
     * @param params 参数
     */
    public void getData(String... params) {
        if (!isViewAttached()) {
            //如果没有View引用就不加载数据
            return;
        }
        //显示正在加载进度条
        getView().showLoading();

        userDataModel
                // 添加请求参数,没有则不添加
                .params(params[0])
                // 注册监听回调
                .execute(new MvpCallback<String>() {
                    @Override
                    public void onConWebSocket(String data) {
                        Log.i(TAG, "execute onConWebSocket");
                    }

                    @Override
                    public void onSuccess(String data) {
                        //调用view接口显示数据
                        getView().showData(data);
                        Log.i(TAG, "execute onSuccess");
                    }

                    @Override
                    public void onFailure(String msg) {
                        //调用view接口提示失败信息
                        getView().showFailureMessage(msg);
                        Log.i(TAG, "execute onFailure");
                    }

                    @Override
                    public void onError() {
                        //调用view接口提示请求异常
                        getView().showErrorMessage();
                    }

                    @Override
                    public void onComplete() {
                        // 隐藏正在加载进度条
                        getView().hideLoading();
                    }
                });
    }

}

(4)Model代码实现@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

package com.mobile.appmine.appmvpmode.model;

import android.os.Handler;
import android.util.Log;

import com.mobile.appmine.appmvpmode.callback.MvpCallback;
import com.mobile.appmine.appmvpmode.base.BaseModel;
import com.mobile.appmine.appmvpmode.bean.MessageEvent;
import com.mobile.appmine.appmvpmode.callback.WebSocketCallback;
import com.mobile.appmine.appmvpmode.socket.EchoWebSocketListener;

import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

/**
 * Created by Administrator on 2018/6/26 0026.
 */

public class UserDataModel extends BaseModel {

    private EchoWebSocketListener echoWebSocketListener;
    private static final String TAG = UserDataModel.class.getSimpleName();

    @Override
    public void requestConWebSocket(MvpCallback<String> callback) {
        this.mvpCallback = callback;
        echoWebSocketListener = EchoWebSocketListener.getInstance();
    }

    @Override
    public void execute(final MvpCallback<String> callback) {
        this.mvpCallback = callback;
        /*
         * 网络请求耗时操作
         */
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                echoWebSocketListener = EchoWebSocketListener.getGlobalWebSocket();
                if (echoWebSocketListener != null) {
                    // mParams 是从父类得到的请求参数
                    switch (mParams[0]) {
                        case "Success":
                            echoWebSocketListener.sendMessage(mParams[0]);
                            break;
                        case "Failed":
                            echoWebSocketListener.sendMessage(mParams[0]);
                            break;
                        case "Error":
                            echoWebSocketListener.sendMessage(mParams[0]);
                            break;
                    }
                }

            }
        }, 500);

    }

    /**
     * 订阅方法,当接收到事件的时候,会调用该方法
     *
     * @param messageEvent
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(MessageEvent messageEvent) {
        Log.i(TAG, "onEvent&&&&&&&" + messageEvent.toString());
        switch (messageEvent.getData()) {
            case "onOpen":
                mvpCallback.onConWebSocket(messageEvent.getData());
                break;
            case "Success":
                mvpCallback.onSuccess(messageEvent.getData());
                break;
            case "Failed":
                mvpCallback.onFailure(messageEvent.getData());
                break;
            case "Error":
                mvpCallback.onError();
                break;
            default:
                break;
        }
        mvpCallback.onComplete();
    }
}

(5)自定义回调代码@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

package com.mobile.appmine.appmvpmode.callback;

/**
 * Created by Administrator on 2018/6/26 0026.
 */

public interface MvpCallback<T> {

    /**
     * 数据请求成功
     * @param data 请求到的数据
     */
    void onConWebSocket(T data);

    /**
     * 数据请求成功
     * @param data 请求到的数据
     */
    void onSuccess(T data);

    /**
     *  使用网络API接口请求方式时,虽然已经请求成功但是由
     *  于{@code msg}的原因无法正常返回数据。
     */
    void onFailure(String msg);

    /**
     * 请求数据失败,指在请求网络API接口请求方式时,出现无法联网、
     * 缺少权限,内存泄露等原因导致无法连接到请求数据源。
     */
    void onError();

    /**
     * 当请求数据结束时,无论请求结果是成功,失败或是抛出异常都会执行此方法给用户做处理,通常做网络
     * 请求时可以在此处隐藏“正在加载”的等待控件
     */
    void onComplete();
}

(6)okhttp3 WebSocket代码实现

package com.mobile.appmine.appmvpmode.socket;

import android.util.Log;

import com.mobile.appmine.appmvpmode.bean.MessageEvent;
import com.mobile.appmine.appmvpmode.callback.WebSocketCallback;

import org.greenrobot.eventbus.EventBus;

import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;

/**
 * Created by Administrator on 2018/6/26 0026.
 */

public class EchoWebSocketListener extends WebSocketListener {

    private static EchoWebSocketListener webSocketListener = null;
    private WebSocket mySocket = null;
    private static final String TAG = EchoWebSocketListener.class.getSimpleName();


    private EchoWebSocketListener() {
    }

    private static void connectWebSocket(String url, long overTime) {
        Log.i(TAG, "connectWebSocket&&&&&");
        OkHttpClient client = new OkHttpClient.Builder()
                .readTimeout(overTime, TimeUnit.MILLISECONDS)//设置读取超时时间
                .writeTimeout(overTime, TimeUnit.MILLISECONDS)//设置写的超时时间
                .connectTimeout(overTime, TimeUnit.MILLISECONDS)//设置连接超时时间
                .build();

        Request request = new Request.Builder().url(url).build();
        webSocketListener = new EchoWebSocketListener();
        client.newWebSocket(request, webSocketListener);

        client.dispatcher().executorService().shutdown();
    }

    /**
     * 新的单例模式
     *
     * @return
     */
    public static EchoWebSocketListener getInstance() {
        if (webSocketListener == null) {
            synchronized (EchoWebSocketListener.class) {
                if (webSocketListener == null) {
                    connectWebSocket("ws://echo.websocket.org", 15000);
                }
            }
        }
        return webSocketListener;
    }

    /**
     * 简单单例模式(只是为了获取全局变量)
     *
     * @return
     */
    public static EchoWebSocketListener getGlobalWebSocket() {
        return webSocketListener;
    }

    public void sendMessage(String data) {
        if (mySocket != null) {
            synchronized (EchoWebSocketListener.class) {
                if (mySocket != null) {
                    mySocket.send(data);
                }
            }
        }
    }

    public void closeWebSocket(int code) {
        Log.i(TAG, "closeWebSocket&&&&&&&");
        if (mySocket != null) {
            Log.i(TAG, "closeWebSocket&&&&&&&2");
            synchronized (EchoWebSocketListener.class) {
                if (mySocket != null) {
                    Log.i(TAG, "closeWebSocket&&&&&&&3");
                    mySocket.close(code, "主动关闭");
                    Log.i(TAG, "closeWebSocket&&&&&&&5");
                }
            }
        }
    }

//    public void closeWebSocket(int code) {
//        Log.i(TAG, "closeWebSocket&&&&&&&");
//        if (mySocket != null) {
//            mySocket.close(code, "主动关闭");
//        }
//    }

    @Override
    public void onOpen(WebSocket webSocket, Response response) {
        super.onOpen(webSocket, response);
        mySocket = webSocket;
        Log.i(TAG, "onOpen&&&&&");
        EventBus.getDefault().post(new MessageEvent("onOpen"));
    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        super.onMessage(webSocket, text);
        Log.i(TAG, "onMessage&&&&&");
        EventBus.getDefault().post(new MessageEvent(text));
        webSocketCallback.onMessage(new MessageEvent(text));
    }

    @Override
    public void onMessage(WebSocket webSocket, ByteString bytes) {
        super.onMessage(webSocket, bytes);
    }

    @Override
    public void onClosed(WebSocket webSocket, int code, String reason) {
        super.onClosed(webSocket, code, reason);
        Log.i(TAG, "onClosed&&&&&");
        mySocket = null;
        webSocketListener = null;
    }

    @Override
    public void onClosing(WebSocket webSocket, int code, String reason) {
        super.onClosing(webSocket, code, reason);
        Log.i(TAG, "onClosing&&&&&");
        mySocket.close(code, null);
    }

    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        super.onFailure(webSocket, t, response);
        mySocket = null;
        webSocketListener = null;
    }
}

(7)实体类代码

package com.mobile.appmine.appmvpmode.bean;

/**
 * Created by Administrator on 2018/6/26 0026.
 */

public class MessageEvent {

    private String data;

    public MessageEvent() {
    }

    public MessageEvent(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "MessageEvent{" +
                "data='" + data + '\'' +
                '}';
    }
}

(8)基础类代码@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

package com.mobile.appmine.appmvpmode.base;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

import com.mobile.appmine.appmvpmode.R;

/**
 * Created by Administrator on 2018/6/26 0026.
 */

public class BaseActivity extends AppCompatActivity implements BaseView {

    private ProgressDialog mProgressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mProgressDialog = new ProgressDialog(this);
        mProgressDialog.setCancelable(false);
    }

    @Override
    public void showLoading() {
        if (!mProgressDialog.isShowing()) {
            mProgressDialog.show();
        }
    }

    @Override
    public void hideLoading() {
        if (mProgressDialog.isShowing()) {
            mProgressDialog.dismiss();
        }
    }

    @Override
    public void showToast(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showErr() {
        showToast(getResources().getString(R.string.api_error_msg));
    }

    @Override
    public Context getContext() {
        return BaseActivity.this;
    }
}

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

package com.mobile.appmine.appmvpmode.base;

import com.mobile.appmine.appmvpmode.callback.MvpCallback;

import org.greenrobot.eventbus.EventBus;

/**
 * Created by Administrator on 2018/6/26 0026.
 */

public abstract class BaseModel {

    //数据请求参数
    public String[] mParams;

    public MvpCallback<String> mvpCallback;

    public BaseModel() {
        attachView();

    }

    /**
     * 绑定view,一般在初始化中调用该方法
     */
    public void attachView() {
        EventBus.getDefault().register(this);
    }

    /**
     * 断开view,一般在onDestroy中调用
     */
    public void detachView() {
        EventBus.getDefault().unregister(this);
    }

    /**
     * 设置数据请求参数
     *
     * @param params 参数数组
     */
    public BaseModel params(String... params) {
        mParams = params;
        return this;
    }

    /**
     * 添加Callback并执行数据请求(具体的数据请求由子类实现)
     * @param callback
     */
    public abstract void requestConWebSocket(MvpCallback<String> callback);

    /**
     * 添加Callback并执行数据请求(具体的数据请求由子类实现)
     * @param callback
     */
    public abstract void execute(MvpCallback<String> callback);

}

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

package com.mobile.appmine.appmvpmode.base;

/**
 * Created by Administrator on 2018/6/26 0026.
 */

public class BasePresenter<V extends BaseView> {

    /**
     * 绑定的view
     */
    public V mvpView;

    /**
     * 绑定view,一般在初始化中调用该方法
     */
    public void attachView(V mvpView) {
        this.mvpView = mvpView;
    }

    /**
     * 断开view,一般在onDestroy中调用
     */
    public void detachView() {
        this.mvpView = null;
    }

    /**
     * 是否与View建立连接
     * 每次调用业务请求的时候都要出先调用方法检查是否与View建立连接
     */
    public boolean isViewAttached() {
        return mvpView != null;
    }

    /**
     * 获取连接的view
     */
    public V getView() {
        return mvpView;
    }
}

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

package com.mobile.appmine.appmvpmode.base;

import android.content.Context;

/**
 * Created by Administrator on 2018/6/26 0026.
 */

public interface BaseView {

    /**
     * 显示正在加载view
     */
    void showLoading();

    /**
     * 关闭正在加载view
     */
    void hideLoading();

    /**
     * 显示提示
     *
     * @param msg
     */
    void showToast(String msg);

    /**
     * 显示请求错误提示
     */
    void showErr();

    /**
     * 获取上下文
     *
     * @return 上下文
     */
    Context getContext();
}

(9)MainActivity布局文件@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:orientation="vertical"
    tools:context="com.mobile.appmine.appmvpmode.MainActivity">

    <TextView
        android:id="@+id/tev_show_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        android:layout_marginTop="20dp"
        android:padding="5dp"
        android:text="show data"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tev_request_connect"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/tev_bg_select"
        android:layout_marginTop="20dp"
        android:layout_marginStart="20dp"
        android:padding="5dp"
        android:text="Connect"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tev_get_data_success"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/tev_bg_select"
        android:layout_marginTop="20dp"
        android:layout_marginStart="20dp"
        android:padding="5dp"
        android:text="Success"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tev_get_data_failed"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/tev_bg_select"
        android:layout_marginTop="20dp"
        android:layout_marginStart="20dp"
        android:padding="5dp"
        android:text="Failed"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tev_get_data_error"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/tev_bg_select"
        android:layout_marginTop="20dp"
        android:layout_marginStart="20dp"
        android:padding="5dp"
        android:text="Error"
        android:textSize="20sp" />

</LinearLayout>

(10)项目引用的依赖@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

compile 'org.greenrobot:eventbus:3.0.0'
compile 'com.squareup.okhttp3:okhttp:3.8.0'
compile 'com.squareup.okhttp3:mockwebserver:3.8.0'

compile 'com.jakewharton:butterknife:8.5.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'

(11)一切就绪之后,记得添加联网权限@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

<uses-permission android:name="android.permission.INTERNET" />

猜你喜欢

转载自blog.csdn.net/NakajimaFN/article/details/81909683