自己整合的Android mvp+singlenet小框架
阿新 • • 發佈:2019-01-07
最近看到了一篇關於阿里何洪輝的singlenet框架,然後自己結合了mvp框架自己架構了一個簡單的程式框架,接下去我將以登入模組來說明一下我的這個小框架
首先是singlenet的框架,這個框架的知識是照搬書上的
//然後一個jsonRequest的實現,覆蓋父類的資料解析方法,返回jsonobject
//response和request完成後,書寫一個請求佇列進行處理請求
//請求佇列中的執行器,獲得請求佇列開啟執行緒進行處理
//接下去是網路請求的真正執行者,通過request獲取response
//response傳遞者,將response傳遞到UI執行緒中
//model請求網路完成後的回撥,網路中介完成請求後,通過responseReveive傳遞給model
首先是singlenet的框架,這個框架的知識是照搬書上的
//首先是request的抽象類,根據http協議的格式設定response內容
package net; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; /** * Created by Administrator on 2017/4/5. */ public abstract class Request<T> implements Comparable<Request<T>> { public static enum HttpMethod{ GET, POST, PUT, DELETE } public static enum Priority{ LOW, NORMAL, HIGHT, IMMEDIATE } //設定預設編碼 private static String DEFAULT_PARAMS_ENCODING ="UTF-8"; //請求序列號 protected int mSerialNum = 0; //請求優先順序 protected Priority priority =Priority.NORMAL; //是否取消請求 protected boolean isCancle = false; //是否需要快取 private boolean mShouldCache =true; //請求回撥 public RequestListener<T> mRequestListener; //請求url private String mUrl =""; //請求方法 HttpMethod mMethod =HttpMethod.GET; //請求的head private Map<String,String> mHeads = new HashMap<String,String>(); //請求引數 private Map<String,String> mBodyParams = new HashMap<String,String>(); public Request(HttpMethod mMethod,String mUrl,RequestListener<T> mRequestListener){ this.mMethod = mMethod; this.mUrl = mUrl; this.mRequestListener = mRequestListener; } public abstract T parseResponse(Response response); public final void deliveryResponse(Response response){ T result = parseResponse(response); //設定監聽 if( mRequestListener!=null){ int stCode =response!=null?200:-1; String msg = response!=null?"ok":"unknow error"; mRequestListener.onComplete(stCode,result,msg); } } protected String getParamsEncoding(){ return DEFAULT_PARAMS_ENCODING; } public String getBodyContendType(){ return "application/x-www-form-urlencoded;charset="+getParamsEncoding(); } public Map getParams(){ return mBodyParams; } public static String getDefaultParamsEncoding() { return DEFAULT_PARAMS_ENCODING; } public static void setDefaultParamsEncoding(String defaultParamsEncoding) { DEFAULT_PARAMS_ENCODING = defaultParamsEncoding; } public int getmSerialNum() { return mSerialNum; } public void setmSerialNum(int mSerialNum) { this.mSerialNum = mSerialNum; } public Priority getPriority() { return priority; } public void setPriority(Priority priority) { this.priority = priority; } public boolean isCancle() { return isCancle; } public void setCancle(boolean cancle) { isCancle = cancle; } public boolean ismShouldCache() { return mShouldCache; } public void setmShouldCache(boolean mShouldCache) { this.mShouldCache = mShouldCache; } public HttpMethod getmMethod() { return mMethod; } public void setmMethod(HttpMethod mMethod) { this.mMethod = mMethod; } public String getmUrl() { return mUrl; } public void setmUrl(String mUrl) { this.mUrl = mUrl; } public Map<String, String> getmHeads() { return mHeads; } public void setmHeads(Map<String, String> mHeads) { this.mHeads = mHeads; } public Map<String, String> getmBodyParams() { return mBodyParams; } public void setmBodyParams(Map<String, String> mBodyParams) { this.mBodyParams = mBodyParams; } public byte[] getBody(){ Map<String,String> params = getParams(); if(params!=null&¶ms.size()>0){ return encodedParams(params,getParamsEncoding()); } return null; } //body格式 private byte[] encodedParams(Map<String,String> params,String paramsEncoding){ StringBuilder encodedParamters = new StringBuilder(); int size =params.entrySet().size(); int index =1; try { for(Map.Entry<String,String> entry:params.entrySet()){ encodedParamters.append(URLEncoder.encode(entry.getKey(),paramsEncoding)); encodedParamters.append("="); encodedParamters.append(URLEncoder.encode(entry.getValue(),paramsEncoding)); if(index!=size){ encodedParamters.append("&"); } index++; } return encodedParamters.toString().getBytes(paramsEncoding); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return new byte[0]; } @Override public int compareTo(Request<T> another) { Priority myPriority = getPriority(); Priority anotherPriority = another.getPriority(); return myPriority.equals(anotherPriority)?this.getmSerialNum()-another.getmSerialNum():myPriority.ordinal()-anotherPriority.ordinal(); } //回撥介面 public static interface RequestListener<T>{ public void onComplete(int stCode,T response,String errMsg); } }
//然後一個jsonRequest的實現,覆蓋父類的資料解析方法,返回jsonobject
//response類,接收網路請求的響應內容package net; import org.json.JSONException; import org.json.JSONObject; /** * Created by Administrator on 2017/4/30. */ public class JsonRequest extends Request<JSONObject>{ public JsonRequest(HttpMethod mMethod, String mUrl, RequestListener<JSONObject> mRequestListener) { super(mMethod, mUrl, mRequestListener); } @Override public JSONObject parseResponse(Response response) { if(response!=null){ String jsonString = new String(response.getRowData()); try { return new JSONObject(jsonString); } catch (JSONException e) { e.printStackTrace(); } } return null; } }
package net; import org.apache.http.HttpEntity; import org.apache.http.ProtocolVersion; import org.apache.http.StatusLine; import org.apache.http.message.BasicHttpResponse; import org.apache.http.util.EntityUtils; import java.io.IOException; /** * Created by Administrator on 2017/4/5. */ public class Response extends BasicHttpResponse { byte[] rowData = new byte[0]; private int statusCode; public int getStatusCode() { return statusCode; } @Override public void setStatusCode(int statusCode) { this.statusCode = statusCode; } public Response(StatusLine statusline) { super(statusline); } public Response(ProtocolVersion ver, int code, String reason) { super(ver, code, reason); } @Override public void setEntity(HttpEntity entity) { super.setEntity(entity); rowData = entityToBytes(entity); } public byte[] getRowData(){ return rowData; } private byte[] entityToBytes(HttpEntity entity){ try { return EntityUtils.toByteArray(entity); } catch (IOException e) { e.printStackTrace(); } return new byte[0]; } }
//response和request完成後,書寫一個請求佇列進行處理請求
package net;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by Administrator on 2017/4/5.
*/
public class RequestQueue{
private BlockingQueue<Request<?>> mRequestQueue= new PriorityBlockingQueue<Request<?>>();
private AtomicInteger atomicInteger = new AtomicInteger(0);
public static int DEFAULT_CORE_NUMS = Runtime.getRuntime().availableProcessors()+1;
private int mDispatcherNums =DEFAULT_CORE_NUMS;
private NetWorkExecutor[] mDispatchers = null;
private HttpStack httpStack;
public RequestQueue(){
this(DEFAULT_CORE_NUMS,null);
}
protected RequestQueue(int coreNums,HttpStack httpStack){
this.mDispatcherNums = coreNums;
this.httpStack = httpStack!=null?httpStack:HttpStackFactory.createHttpStack();
}
private final void startNetworkExecutors(){
mDispatchers = new NetWorkExecutor[mDispatcherNums];
for(int i=0;i<mDispatcherNums;i++){
mDispatchers[i] = new NetWorkExecutor(mRequestQueue,httpStack);
mDispatchers[i].start();
}
}
public void start(){
stop();
startNetworkExecutors();
}
public void stop(){
if(mDispatchers!=null&&mDispatchers.length>0){
for(int i=0;i<mDispatchers.length;i++){
mDispatchers[i].quit();
}
}
}
public void addRequest(Request<?> request){
if(!mRequestQueue.contains(request)){
request.setmSerialNum(generateSerialNumber());
mRequestQueue.add(request);
}
}
private int generateSerialNumber(){
return atomicInteger.incrementAndGet();
}
}
//請求佇列中的執行器,獲得請求佇列開啟執行緒進行處理
package net;
import android.util.Log;
import android.util.LruCache;
import java.util.concurrent.BlockingQueue;
/**
* Created by Administrator on 2017/4/9.
*/
public class NetWorkExecutor extends Thread {
private BlockingQueue<Request<?>> mRequestQueue;
private HttpStack mHttpStack;
private static ResponseDelivery mResponseDelivery = new ResponseDelivery();
private static LruCache<String,Response> mreqCache = new LruCache<String,Response>(100);
private boolean isStop = false;
public NetWorkExecutor(BlockingQueue<Request<?>> mRequestQueue,HttpStack httpStack){
this.mRequestQueue=mRequestQueue;
this.mHttpStack = httpStack;
}
@Override
public void run() {
while(!isStop){
try {
final Request<?> request = mRequestQueue.take();
if(request.isCancle()){
Log.d("###","###取消執行");
continue;
}
Response response=null;
if(isUserCache(request)){
response=mreqCache.get(request.getmUrl());
}else{
response = mHttpStack.performRequest(request);
if(response==null){
System.out.println("返回response為空");
}
if(request.ismShouldCache()&&isSuccess(response)){
mreqCache.put(request.getmUrl(),response);
}
}
mResponseDelivery.deliveryResponse(request,response);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private boolean isSuccess(Response response){
return response!=null&&response.getStatusCode()==200;
}
private boolean isUserCache(Request<?> request){
return request.ismShouldCache()&& mreqCache.get(request.getmUrl())!=null;
}
public void quit(){
isStop=true;
interrupt();
}
}
//接下去是網路請求的真正執行者,通過request獲取response
package net;
import com.baidu.trace.T;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicStatusLine;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Created by Administrator on 2017/4/9.
*/
public class HttpUrlConnecStack implements HttpStack {
@Override
public Response performRequest(Request<?> request) {
HttpURLConnection urlConnection =null;
try {
urlConnection =createUrlConnection(request.getmUrl());
System.out.println("設定頭部");
setRequestHeaders(urlConnection,request);
System.out.println("設定引數");
setRequestParams(urlConnection,request);
urlConnection.connect();
return fetchResponse(urlConnection);
} catch (IOException e) {
e.printStackTrace();
System.out.println("異常是"+e.toString());
}finally {
if(urlConnection!=null){
urlConnection.disconnect();
}
}
return null;
}
private HttpURLConnection createUrlConnection(String url) throws IOException {
URL newURL = new URL(url);
URLConnection urlConnection = newURL.openConnection();
urlConnection.setDoInput(true);
urlConnection.setUseCaches(false);
return (HttpURLConnection) urlConnection;
}
private void setRequestHeaders(HttpURLConnection connection,Request<?> request){
Set<String> headersKeys = request.getmHeads().keySet();
for(String headerName:headersKeys){
connection.addRequestProperty(headerName,request.getmHeads().get(headerName));
}
}
protected void setRequestParams(HttpURLConnection connection,Request<?> request) throws IOException {
Request.HttpMethod method=request.getmMethod();
connection.setRequestMethod(method.toString());
//connection.setRequestMethod("POST");
byte[] body =request.getBody();
String params = new String(body);
System.out.println("引數是"+params);
if(body!=null){
connection.setDoInput(true);
connection.addRequestProperty("Content-Type",request.getBodyContendType());
DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream());
dataOutputStream.write(body);
dataOutputStream.close();
}
}
private Response fetchResponse(HttpURLConnection connection) throws IOException {
ProtocolVersion protocolVersion = new ProtocolVersion("HTTP",1,1);
int responseCode = connection.getResponseCode();
if(responseCode==-1){
System.out.println("丟擲異常!");
throw new IOException("Could not retrieve response code from HttpUrlConnection");
}
System.out.println("請求連結成功!");
StatusLine responseStatus = new BasicStatusLine(protocolVersion,connection.getResponseCode(),connection.getResponseMessage());
Response response = new Response(responseStatus);
response.setStatusCode(connection.getResponseCode());
response.setEntity(entityFromURLConnection(connection));
addHeadersToResponse(response,connection);
return response;
}
private HttpEntity entityFromURLConnection(HttpURLConnection connection){
BasicHttpEntity entity = new BasicHttpEntity();
InputStream inputStream =null;
try {
inputStream = connection.getInputStream();
} catch (IOException e) {
e.printStackTrace();
inputStream= connection.getErrorStream();
}
entity.setContent(inputStream);
entity.setContentLength(connection.getContentLength());
entity.setContentType(connection.getContentType());
return entity;
}
private void addHeadersToResponse(BasicHttpResponse response,HttpURLConnection connection){
for(Map.Entry<String,List<String>> header:connection.getHeaderFields().entrySet()){
if(header.getKey()!=null){
Header h = new BasicHeader(header.getKey(),header.getValue().get(0));
response.setHeader(h);
}
}
}
}
//response傳遞者,將response傳遞到UI執行緒中
package net;
import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.Executor;
/**
* Created by Administrator on 2017/4/9.
*/
public class ResponseDelivery implements Executor {
Handler mResponseHandler = new Handler(Looper.getMainLooper());
public void deliveryResponse(final Request<?>request,final Response response){
Runnable responseRunnable = new Runnable() {
@Override
public void run() {
request.deliveryResponse(response);
}
};
execute(responseRunnable);
}
@Override
public void execute(Runnable runnable) {
mResponseHandler.post(runnable);
}
}
以上整個網路框架就完成了,接下去就是結合mvp框架
//首先是view的介面
package viewinterface;
/**
* Created by Administrator on 2017/4/30.
*/
public interface LoginViewInterface {
void loginSuccess();
void loginFailed(String errorMessage);
void registFailed(String errorMessage);
void regustSuccess();
void doLogin();
void doRegist();
}
//view的實現LoginView,充當view檢視,只進行檢視的轉換
package com.example.administrator.exercise;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import FileUtils.ImageLoader;
import Manager.MyDialogFactory;
import chart.imp.ImgeSelectorActivity;
import present.LoginPresent;
import viewinterface.LoginViewInterface;
/**
* Created by Administrator on 2017/4/30.
*/
public class LoginActivtity extends Activity implements LoginViewInterface,View.OnClickListener{
private TextView phoneText ;
private TextView passwordText;
private Button loginButton;
private Button registButton;
private ImageView logoImage;
private LoginPresent present;
private ProgressDialog dialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
init();
}
@Override
protected void onResume() {
super.onResume();
}
private void init(){
phoneText = (TextView) findViewById(R.id.phone_text);
passwordText = (TextView) findViewById(R.id.password_text);
loginButton = (Button) findViewById(R.id.login_button);
registButton = (Button) findViewById(R.id.regist_button);
logoImage = (ImageView) findViewById(R.id.logo_image);
present = new LoginPresent(this);
dialog = MyDialogFactory.getInstance().createProgressDialog("請稍後。。。",this);
setListener();
}
private void setListener(){
loginButton.setOnClickListener(this);
registButton.setOnClickListener(this);
logoImage.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.login_button:
present.login(phoneText.getText().toString().trim(),
passwordText.getText().toString());
break;
case R.id.regist_button:
present.regist(phoneText.getText().toString().trim(),
passwordText.getText().toString().trim());
break;
}
}
@Override
public void loginSuccess() {
Toast.makeText(this,"成功",Toast.LENGTH_LONG).show();
Intent intent = new Intent();
intent.setClass( LoginActivtity.this,MainActivity.class);
startActivity(intent);
dialog.dismiss();
}
@Override
public void loginFailed(String errorMessage) {
Toast.makeText(this,"登入失敗:"+errorMessage,Toast.LENGTH_LONG).show();
dialog.dismiss();
}
@Override
public void registFailed(String errorMessage) {
Toast.makeText(this,"註冊失敗"+errorMessage,Toast.LENGTH_LONG).show();
dialog.dismiss();
}
@Override
public void regustSuccess() {
Toast.makeText(this,"註冊成功",Toast.LENGTH_LONG).show();
dialog.dismiss();
}
@Override
public void doLogin() {
dialog.show();
}
@Override
public void doRegist() {
dialog.show();
}
}
//present中介,實現onLoginListener介面,接收model中不同的情況進行不同的處理,同時擁有view 和model的物件,對view和model進行解耦資料獲取資料後直接在裡面進行設定檢視
package present;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import Listener.OnLoginListener;
import model.LoginModel;
import model.LoginModelInterface;
import proxy.MiddleNetProxy;
import proxy.ResponsReceiver;
import viewinterface.LoginViewInterface;
/**
* Created by Administrator on 2017/4/30.
*/
public class LoginPresent implements OnLoginListener {
LoginViewInterface loginViewInterface;
LoginModelInterface loginModelInterface;
public LoginPresent( LoginViewInterface loginViewInterface){
this.loginViewInterface = loginViewInterface;
loginModelInterface = new LoginModel();
loginModelInterface.setOnLoginListener(this);
}
public void login(String phone,String password){
loginModelInterface.doLogin(phone,password);
}
public void regist(String phone,String password){
if(!"".equals(phone)&&!"".equals(password)){
loginViewInterface.doRegist();
loginModelInterface.doRegist(phone,password);
}
}
@Override
public void loginSuccess() {
loginViewInterface.loginSuccess();
}
@Override
public void loginFailed(String errorMessage) {
loginViewInterface.loginFailed(errorMessage);
}
@Override
public void registFailed(String errorMessage) {
loginViewInterface.registFailed(errorMessage);
}
@Override
public void regustSuccess() {
loginViewInterface.regustSuccess();
}
}
//然後是model資料獲取,整合responseReveive,在hanler中處理網路中介返回來的response,並且通過onLoginListener傳遞給present,
package model;
import android.content.Context;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import FileUtils.TempURL;
import Listener.OnLoginListener;
import proxy.MiddleNetProxy;
import proxy.ResponsReceiver;
/**
* Created by Administrator on 2017/5/4.
*/
public class LoginModel implements LoginModelInterface , ResponsReceiver<JSONObject>{
private static String KEY_ACCOUNT = "userPhone";
private static String KEY_PASSWORD = "userPassword";
private static String TYPE_LOGIN = "LOGIN";
private static String TYPE_REGIST = "REGIST";
private Context context;
public LoginModel(){
}
public LoginModel(Context context){
this.context = context;
}
@Override
public void setOnLoginListener(OnLoginListener onLoginListener) {
this.onLoginListener = onLoginListener;
}
private OnLoginListener onLoginListener;
@Override
public int doLogin(String account, String passWord) {
HashMap<String,String> loginMap = new HashMap<String,String>();
loginMap.put(KEY_ACCOUNT,account);
loginMap.put(KEY_PASSWORD, passWord);
MiddleNetProxy.getInstance().postJsonRequest(TempURL.host+"/User/login",this,loginMap,null,false);
return 0;
}
@Override
public int doRegist(String account, String passWord) {
HashMap<String,String> registMap = new HashMap<String,String>();
System.out.println("賬號是"+account);
registMap.put(KEY_ACCOUNT,account);
registMap.put(KEY_PASSWORD,passWord);
MiddleNetProxy.getInstance().postJsonRequest(TempURL.host+"/User/addUser",this,registMap,null,false);
return 0;
}
@Override
public void handlerResponse(int stCode, JSONObject response, String errMsg) {
if(response==null)return;
System.out.println("result="+response.toString());
//根據返回的協議進行分發
try {
String type = response.getString(TYPE);
if(TYPE_LOGIN.equalsIgnoreCase(type)){
String msg = response.getString(MSG);
String info = response.getString(INFO);
if(MSG_OK.equalsIgnoreCase(msg)){
if(onLoginListener!=null){
onLoginListener.loginSuccess();
}
}else if(MSG_ERROR.equalsIgnoreCase(msg)){
if(onLoginListener!=null){
onLoginListener.loginFailed(info);
}
}
}else if(TYPE_REGIST.equalsIgnoreCase(type)){
String msg = response.getString(MSG);
String info = response.getString(INFO);
if(MSG_OK.equalsIgnoreCase(msg)){
if(onLoginListener!=null){
onLoginListener.regustSuccess();
}
}else if(MSG_ERROR.equalsIgnoreCase(msg)){
if(onLoginListener!=null){
onLoginListener.registFailed(info);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
//網路請求中介,用於傳遞請求,管理請求佇列
package proxy;
import net.JsonRequest;
import net.Request;
import net.RequestQueue;
import net.ResponseDelivery;
import org.json.JSONObject;
import java.util.Map;
/**
* Created by Administrator on 2017/4/30.
*/
public class MiddleNetProxy {
public static MiddleNetProxy instance;
private static RequestQueue mQueue = new RequestQueue();
MiddleNetProxy(){
mQueue.start();
}
public static synchronized MiddleNetProxy getInstance(){
if(instance==null){
instance = new MiddleNetProxy();
}
return instance;
}
public static void postJsonRequest(String url, final ResponsReceiver receiver,Map<String,String> body,Map<String,String> header,boolean isUseCase){
JsonRequest request = new JsonRequest(Request.HttpMethod.POST, url, new Request.RequestListener<JSONObject>() {
@Override
public void onComplete(int stCode, JSONObject response, String errMsg) {
if(receiver!=null){
receiver.handlerResponse(stCode,response,errMsg);
}
}
});
request.setmShouldCache(isUseCase);
if(header!=null)
request.setmHeads(header);
if(body!=null){
request.setmBodyParams(body);
}
mQueue.addRequest(request);
}
}
//model請求網路完成後的回撥,網路中介完成請求後,通過responseReveive傳遞給model
public interface ResponsReceiver<T> {
void handlerResponse(int stCode,T response, String errMsg);
}
//onLoginListener獲得present引用,因為present中實現了該介面,所以可以直接在model裡面使用onLoginListener來呼叫present的檢視設定的函式
public interface OnLoginListener {
void loginSuccess();
void loginFailed(String errorMessage);
void registFailed(String errorMessage);
void regustSuccess();
}
這是最近自己結合兩者設定的一個框架,後續有時間可能還會慢慢解耦,有意見請大家提出來~~~~