文章纯属个人学习的代码实现
网易云微专业公开课这节课主要讲了如何自己完成一个简易的网络请求框架,核心是线程处理和架构思想。
我们分析一下整个架构设计
![](https://img.haomeiwen.com/i12262980/ba7d7e4fd5152c17.png)
首选是 ThreadPoolManager
线程池里面有两个【永动机】,分别是coreThread
和delayThread
,他们都有一个 while (true)
代码段,不断地从队列里面获取请求
可以看看他们的代码
// 创建核心线程 将队列中的请求拿出来 ,交给线程池处理
public Runnable coreThread = new Runnable() {
Runnable runnable = null;
@Override
public void run() {
while (true) {
try {
runnable = mQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
mThreadPoolExecutor.execute(runnable);
}
}
};
public Runnable delayThread = new Runnable() {
HttpTask ht = null;
@Override
public void run() {
while (true) {
try {
ht = mDelay.take();
if (ht.getRetryCount() < 3) {
mThreadPoolExecutor.execute(ht);
ht.setRetryCount(ht.getRetryCount() + 1);
Log.e("===重试机智===", ht.getRetryCount() + " " + System.currentTimeMillis());
} else {
Log.e("===重试机智===", "放弃");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
这就能解释,我们App
随时都能发起网络请求的原因,因为他是一个死循环里面不断的去队列里面取,这样就能保证每个请求都能执行到。
ThreadPoolManager
的核心代码就是定义两个队列,一个线程池,然后执行这两个线程,具体看看代码
// 线程安全
private LinkedBlockingQueue<Runnable> mQueue = new LinkedBlockingQueue<>();
private DelayQueue<HttpTask> mDelay = new DelayQueue<>();
//线程池
private ThreadPoolExecutor mThreadPoolExecutor;
private ThreadPoolManager() {
mThreadPoolExecutor = new ThreadPoolExecutor(3, 6, 15,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
//线程没执行成功,返回到这里
addTask(r);
}
});
mThreadPoolExecutor.execute(coreThread);
mThreadPoolExecutor.execute(delayThread);
}
好,分析完整个驱动部分,我们要去看具体的请求怎么执行的
我们直接先看HttpTask
它是一个线程类,主要主要执行具体的请求,大概看看
public HttpTask(String url, T requestData, IHttpRequest request, CallbackListener listener) {
this.httpRequest = request;
request.setUrl(url);
request.setListener(listener);
String content = JSON.toJSONString(requestData);
try {
request.setData(content.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
httpRequest.execute();
} catch (Exception e) {
ThreadPoolManager.getInstance().addDelayTask(this);
}
}
这里面其实包含两个部分,一个是请求部分,请一个就是请求结果部分,
请求我们用了IHttpRequest
接口进行 封装,请求结果用 CallbackListener
接口进行封装,然后再run()
方法开启请求
这里为啥要用接口呢,第一比如请求,我们每个请求的url
,请求参数,请求返回的数据结果都不一样,所以我们定义了这些 不同参数的 入口,如下所示
public interface IHttpRequest {
void setUrl(String url);
void setData(byte[] data);
void setListener(CallbackListener listener);
void execute() throws MalformedURLException;
}
而请求结果回调接口CallbackListener
我们这么定义
public interface CallbackListener {
void onSuccess(InputStream inputStream);
void onFailure();
}
这样定义完了 我们看看我们怎么执行一个真正的请求
NeHttp.sendJsonRequest(url2, null, ResponseClass.class, new IJsonDataListener<ResponseClass>() {
@Override
public void onSuccess(ResponseClass clazz) {
Log.e("==========",clazz.toString());
}
});
这个NeHttp
又是什么,不急先看代码
public class NeHttp{
public static<T,M> void sendJsonRequest(String url,T requestData,Class<M> reponse,IJsonDataListener listener){
IHttpRequest request=new JsonHttpRequest();
CallbackListener callbackListener=new JsonCallBackListener<>(reponse,listener);
HttpTask ht=new HttpTask(url,requestData,request,callbackListener);
ThreadPoolManager.getInstance().addTask(ht);
}
}
其实就是封装一个真正的请求HttpTask
然后加到请求队列中ThreadPoolManager.getInstance().addTask(ht);
我们看一下这里是怎么生成一个真正的HttpTask
的
首先 请求部分
IHttpRequest request=new JsonHttpRequest();
其实就是新建了一个具体的IHttpRequest
实现类JsonHttpRequest
看一下代码
public class JsonHttpRequest implements IHttpRequest {
private String url;
private byte[] data;
private CallbackListener callbackListener;
private HttpURLConnection urlConn;
@Override
public void setUrl(String url) {
this.url = url;
}
@Override
public void setData(byte[] data) {
this.data = data;
}
@Override
public void setListener(CallbackListener listener) {
this.callbackListener = listener;
}
@Override
public void execute() throws MalformedURLException {
//访问网络
URL url = null;
try {
url = new URL(this.url); // 打开一个HttpURLConnection连接
urlConn = (HttpURLConnection) url.openConnection();
urlConn.setUseCaches(false);
urlConn.setInstanceFollowRedirects(true);
urlConn.setReadTimeout(3000);
urlConn.setDoInput(true);
urlConn.setDoOutput(true);
urlConn.setRequestMethod("POST");
urlConn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
urlConn.connect();
OutputStream out = urlConn.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(out);
bos.write(data);
bos.flush();
out.close();
bos.close();
if (urlConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
InputStream in = urlConn.getInputStream();
callbackListener.onSuccess(in);
} else {
throw new RuntimeException("请求失败");
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("请求失败");
} finally {
urlConn.disconnect();
}
}
}
代码 很长,但是核心在于execute()
里面的callbackListener.onSuccess(in);
完成请求后回调这个接口
当然这是Json
相关的请求,所以我们定一个了一个CallbackListener callbackListener=new JsonCallBackListener<>(reponse,listener);
处理Json
数据结果
具体代码如下
public class JsonCallBackListener<T> implements CallbackListener {
public Class<T> responsClass;
private IJsonDataListener iJsonDataListener;
private Handler mHandler = new Handler(Looper.getMainLooper());
public JsonCallBackListener(Class<T> responsClass, IJsonDataListener jsonDataListener) {
this.responsClass = responsClass;
this.iJsonDataListener = jsonDataListener;
}
@Override
public void onSuccess(InputStream inputStream) {
String response = getContent(inputStream);
final T clazz = JSON.parseObject(response, responsClass);
mHandler.post(new Runnable() {
@Override
public void run() {
iJsonDataListener.onSuccess(clazz);
}
});
}
private String getContent(InputStream inputStream) {
String content = null;
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
System.out.println("Error=" + e.toString());
} finally {
try {
inputStream.close();
} catch (IOException e) {
System.out.println("Error=" + e.toString());
}
}
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return content;
}
@Override
public void onFailure() {
}
}
核心代码是这段话
public void onSuccess(InputStream inputStream) {
String response = getContent(inputStream);
final T clazz = JSON.parseObject(response, responsClass);
mHandler.post(new Runnable() {
@Override
public void run() {
iJsonDataListener.onSuccess(clazz);
}
});
}
利用fastJson
完成了字符串转具体对象的操作
然后整个流程通过iJsonDataListener.onSuccess(clazz);
完成了串联,最后关于重试那个大家可以看看代码 ,思路基本一致,主要通过失败之后添加到 DelayQue
队列里面,然后每次都从这个队列重试。
大家想了解更多直接去我的github看代码实现
网友评论