本文适合有一定的基础开发人员,主要介绍了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" />