Android仿人人客户端(v5.7.1)——网络模块处理的架构
转载请标明出处:http://blog.csdn.net/android_ls/article/details/8732427
声明:仿人人项目,所用所有图片资源都来源于官方人人android客户端,编写本应用的目的在于学习交流,如涉及侵权请告知,我会及时换掉用到的相关图片。
上一篇聊到了通过WebView组件加载人人的访问授权页面,接下来就是当用户输入人人访问账号和密码,点击“登录”按钮,成功后人人的服务器端会返回AccessToken的值。初次使用,我们本地是没有存储session Key的,我们需要通过AccessToken去服务器端请求数据,获得session Key、sessionSecret和用户的userId。存储当前获得的sessionKey, sessionSecret以备后用。这里就需要用到网络这块的知识,这一篇就来说下仿人人的网络模块是如何架构的,先来看下网络处理模块的类图:

一、网络请求基类(AsyncBaseRequest),是一个实现Runnable接口的线程类。
初始化时的参数列表:
public AsyncBaseRequest(String url, Map<String, String> parameter, ParseCallback handler, ResultCallback requestCallback) {}参数列表解释:
第一个参数:网络请求URL;
第二个参数:网络请求的参数;
第三个参数:网络请求返回数据的解析器;
第四个参数:网络请求返回的结果回调接口;
网络请求具体实现抽象方法:
protected abstract InputStream getRequestResult() throws IOException;
线程核心run()方法里面的实现:
@Overridepublic void run() {try {mInStream = getRequestResult();if (mInStream != null) {String result = new String(readInputStream(mInStream));Object obj = parseHandler.parse(result);requestCallback.onSuccess(flag, obj);} else {System.out.println("get InputStream By HttpURLConnection return result is NULL.");}} catch (IOException e) {requestCallback.onFail(flag, Constant.NETWORK_REQUEST_IOEXCEPTION_CODE); // IO异常标识e.printStackTrace();}}二、通过HTTP协议发送GET请求的具体实现
package com.everyone.android.net;import java.io.IOException;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLEncoder;import java.util.Map;import org.apache.http.protocol.HTTP;import com.everyone.android.callback.ParseCallback;import com.everyone.android.callback.ResultCallback;/** * 功能描述:通过HTTP协议发送GET请求 * @author android_ls * */public class AsyncHttpGet extends AsyncBaseRequest {/** * */private static final long serialVersionUID = 2L;public AsyncHttpGet(String url, Map<String, String> parameter,ParseCallback handler, ResultCallback requestCallback) throws IOException {super(url, parameter, handler, requestCallback);}@Overrideprotected InputStream getRequestResult() throws IOException {StringBuilder sb = new StringBuilder(requestUrl);sb.append('?');for(Map.Entry<String, String> entry : parameter.entrySet()){sb.append(entry.getKey()).append('=').append(URLEncoder.encode(entry.getValue(), HTTP.UTF_8)).append('&');}sb.deleteCharAt(sb.length()-1);URL url = new URL(sb.toString()); mHttpURLConn = (HttpURLConnection)url.openConnection();mHttpURLConn.setConnectTimeout(connectTimeout);mHttpURLConn.setRequestMethod("GET");if(mHttpURLConn.getResponseCode()== HttpURLConnection.HTTP_OK){return mHttpURLConn.getInputStream();}return null;}}三、通过HTTP协议发送POST请求的具体实现
package com.everyone.android.net;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLEncoder;import java.util.Map;import org.apache.http.protocol.HTTP;import com.everyone.android.callback.ParseCallback;import com.everyone.android.callback.ResultCallback;/** * 功能描述:通过HTTP协议发送POST请求 * @author android_ls * */public class AsyncHttpPost extends AsyncBaseRequest {/** * */private static final long serialVersionUID = 3L;public AsyncHttpPost(String url, Map<String, String> parameter,ParseCallback handler, ResultCallback requestCallback) {super(url, parameter, handler, requestCallback);}@Overrideprotected InputStream getRequestResult() throws IOException {StringBuilder sb = new StringBuilder();if(parameter!=null && !parameter.isEmpty()){for(Map.Entry<String, String> entry : parameter.entrySet()){sb.append(entry.getKey()).append('=').append(URLEncoder.encode(entry.getValue(), HTTP.UTF_8)).append('&');}sb.deleteCharAt(sb.length()-1);}// 得到实体的二进制数据byte[] entitydata = sb.toString().getBytes();URL url = new URL(requestUrl); mHttpURLConn = (HttpURLConnection)url.openConnection();mHttpURLConn.setRequestMethod("POST");mHttpURLConn.setConnectTimeout(5 * 1000);// 如果通过post提交数据,必须设置允许对外输出数据mHttpURLConn.setDoOutput(true);mHttpURLConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");mHttpURLConn.setRequestProperty("Content-Length", String.valueOf(entitydata.length));OutputStream outStream = mHttpURLConn.getOutputStream();outStream.write(entitydata);outStream.flush();outStream.close();if(mHttpURLConn.getResponseCode()== HttpURLConnection.HTTP_OK){return mHttpURLConn.getInputStream();}return null;}}四、线程池类
package com.everyone.android.net;import java.util.concurrent.AbstractExecutorService;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;import android.util.Log;/** * 功能描述:网络请求线程池类 * @author android_ls */public class DefaultThreadPool { /** * 用于保存等待执行的任务的阻塞队列。(有序的先进先出阻塞队列) */ private static ArrayBlockingQueue<Runnable> mBlockingQueue = new ArrayBlockingQueue<Runnable>(15, true); /** * 线程池 */ private static AbstractExecutorService mThreadPoolExecutor = new ThreadPoolExecutor(5, 7, 10, TimeUnit.SECONDS, mBlockingQueue, new ThreadPoolExecutor.DiscardOldestPolicy()); private static DefaultThreadPool instance = null; public static DefaultThreadPool getInstance() { if (instance == null) { instance = new DefaultThreadPool(); } return instance; } /** * 执行任务 * @param r */ public void execute(Runnable r) { mThreadPoolExecutor.execute(r); } /** * 关闭,并等待任务执行完成,不接受新任务 */ public static void shutdown() { if (mThreadPoolExecutor != null) { mThreadPoolExecutor.shutdown(); Log.i(DefaultThreadPool.class.getName(), "DefaultThreadPool shutdown"); } } /** * 关闭,立即关闭,并挂起所有正在执行的线程,不接受新任务 */ public static void shutdownRightnow() { if (mThreadPoolExecutor != null) { mThreadPoolExecutor.shutdownNow(); try { // 设置超时极短,强制关闭所有任务 mThreadPoolExecutor.awaitTermination(1, TimeUnit.MICROSECONDS); } catch (InterruptedException e) { e.printStackTrace(); } Log.i(DefaultThreadPool.class.getName(), "DefaultThreadPool shutdownRightnow"); } }}五、网络请求返回的数据解析接口
package com.everyone.android.callback;/** * 功能描述:网络请求返回的数据解析接口 * @author android_ls * */public interface ParseCallback { /** * 对网络请求返回的数据进行解析 * @param str 要解析的字符串,JSON格式或XML * @return 解析的结果 */public Object parse(String str);}六、网络请求返回的结果回调接口
package com.everyone.android.callback;/** * 功能描述:网络请求返回的结果回调接口 * @author android_ls * */public interface ResultCallback {public void onSuccess(Object obj);public void onFail(int errorCode);}七、应用中界面(Activity)的基类
package com.everyone.android;import java.net.HttpURLConnection;import java.util.ArrayList;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.widget.Toast;import com.everyone.android.net.AsyncBaseRequest;import com.everyone.android.net.DefaultThreadPool;/** * 功能描述:应用中界面(Activity)的基类 * 对原有的Activity类进行扩展 * @author android_ls */public abstract class AppBaseActivity extends Activity { /** * 当前activity所持有的所有网络请求 */ protected List<AsyncBaseRequest> mAsyncRequests; protected Handler mHandler; protected DefaultThreadPool mDefaultThreadPool; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayoutId()); ((EveryoneApplication) this.getApplication()).addActivity(this); mHandler = new Handler(); mAsyncRequests = new ArrayList<AsyncBaseRequest>(); mDefaultThreadPool = DefaultThreadPool.getInstance(); // 初始化组件 setupView(); // 初始化数据 initializedData(); } /** * 布局文件ID * @return */ protected abstract int getLayoutId(); /** * 初始化组件 */ protected abstract void setupView(); /** * 初始化数据 */ protected abstract void initializedData(); @Override protected void onPause() { /** * 在activity销毁的时候同时设置停止请求,停止线程请求回调 */ cancelRequest(); super.onPause(); } private void cancelRequest() { if (mAsyncRequests != null && mAsyncRequests.size() > 0) { for (AsyncBaseRequest request : mAsyncRequests) { HttpURLConnection conn = request.getRequestConn(); if (conn != null) { try { conn.disconnect(); System.out.println("onDestroy disconnect URL: " + conn.getURL()); mAsyncRequests.remove(request); } catch (UnsupportedOperationException e) { //do nothing . } } } } } /** * 显示Toast形式的提示信息 * @param message */ protected void show(String message) { Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); } @Override protected void onDestroy() { /** * 在activity销毁的时候同时设置停止请求,停止线程请求回调 */ cancelRequest(); super.onDestroy(); }}八、测试(继承自AppBaseActivity的子类),方法的调用
String url = "http://www.baidu.com/"; Map<String, String> parameter = new HashMap<String, String>(); parameter.put("name", "android_ls"); parameter.put("age", "23"); AsyncBaseRequest asyncBaseRequest = new AsyncHttpPost(url, parameter, new ParseCallback(){ @Override public Object parse(String str) { // TODO Auto-generated method stub return null; } }, new ResultCallback(){ @Override public void onSuccess(int flag, Object obj) { // TODO Auto-generated method stub } @Override public void onFail(int flag, int errorCode) { // TODO Auto-generated method stub } }); mDefaultThreadPool.execute(asyncBaseRequest); mAsyncRequests.add(asyncBaseRequest);AsyncBaseRequest的完整代码
package com.everyone.android.net;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.Serializable;import java.net.HttpURLConnection;import java.util.Map;import com.everyone.android.callback.ParseCallback;import com.everyone.android.callback.ResultCallback;import com.everyone.android.utils.Constant;/** * 功能描述:通过HTTP协议发送网络请求线程类 * @author android_ls * */public abstract class AsyncBaseRequest implements Runnable, Serializable {/** * */private static final long serialVersionUID = 1L;/** * 网络连接超时,默认值为5秒 */protected int connectTimeout = 5 * 1000;/** * 网络数据读取超时,默认值为5秒 */protected int readTimeout = 5 * 1000;protected void setConnectTimeout(int connectTimeout) {this.connectTimeout = connectTimeout;}protected void setReadTimeout(int readTimeout) {this.readTimeout = readTimeout;}protected String requestUrl;protected Map<String, String> parameter;private ParseCallback parseHandler;private ResultCallback requestCallback;protected HttpURLConnection mHttpURLConn;protected InputStream mInStream; public AsyncBaseRequest(String url, Map<String, String> parameter, ParseCallback handler, ResultCallback requestCallback) {this.parseHandler = handler;this.requestUrl = url;this.parameter = parameter;this.requestCallback = requestCallback;}/** * 发送网络请求 * * @return 网络请求返回的InputStream数据流 * @throws IOException */protected abstract InputStream getRequestResult() throws IOException;@Overridepublic void run() {try {mInStream = getRequestResult();if (mInStream != null) {String result = new String(readInputStream(mInStream));Object obj = parseHandler.parse(result);requestCallback.onSuccess(obj);} else {System.out.println("get InputStream By HttpURLConnection return result is NULL.");}} catch (IOException e) {requestCallback.onFail(Constant.NETWORK_REQUEST_IOEXCEPTION_CODE); // IO异常标识e.printStackTrace();}}/** * 从输入流读取数据 * * @param inStream * @return * @throws IOException * @throws Exception */protected byte[] readInputStream(InputStream inStream) throws IOException {ByteArrayOutputStream outSteam = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while ((len = inStream.read(buffer)) != -1) {outSteam.write(buffer, 0, len);}outSteam.close();inStream.close();return outSteam.toByteArray();}public HttpURLConnection getRequestConn() {return mHttpURLConn;}}好了就到这里吧,后面的待续。。。
吐槽下:在CSDN上写文章,写完后你若想删除掉之前写的一部分内容,就得一行一行删,不能选中某个区域,之后一次性删除,真郁闷。我记得之前不是这样的,现在为什么会这样呢?我刚才删除写错的文字和代码就用了我五分钟左右,真的想说粗话了,但想了下,算了。我是一个文明的人,呵呵。
这一篇网络模块处理有些地方有待优化,优化处理部分请阅读下篇Android仿人人客户端(v5.7.1)——网络模块优化
- 13楼u0100984538小时前
- 高手呀!
- Re: android_ls3小时前
- 回复u010098453n谢谢夸奖!
- 12楼u0101084128小时前
- ...
- 11楼mfkauko13小时前
- 赞一个,一直在学习中,希望更新。
- Re: android_ls9小时前
- 回复mfkaukon谢谢支持!
- 10楼u010096450昨天 14:33
- 魂牵梦萦
- 9楼u010100919昨天 13:38
- 收益
- Re: android_ls昨天 14:22
- 回复u010100919n能对你有帮助,我也很高兴。互相借鉴,共同进步。
- 8楼u010100919前天 22:29
- 还得学习
- Re: android_ls昨天 00:34
- 回复u010100919n这一篇中的部分处理,是不太完美,我已意识到,在《Android仿人人客户端(v5.7.1)——网络模块优化 》中我已处理,你若觉得我哪里处理的不合适,欢迎提出你的意见,大家互相交流、借鉴,共同进步。
- 7楼hljstardust2012前天 22:24
- 谢谢分享,真的很好!,学习了
- Re: android_ls前天 22:27
- 回复hljstardust2012n谢谢你的支持!
- 6楼liu_jun_y前天 20:50
- LZn请问你画图使用的是那个工具呀。
- Re: android_ls前天 20:50
- 回复liu_jun_ynAstah UML 绘图工具,你可以到网上搜下,下载一个试试,很好用的,呵呵。
- 5楼sunjunlaing52前天 17:32
- 分析的很翔实,受益了,关注中,能给一份跑通code吗? 谢谢!1449364567@qq.com
- 4楼goldseawu前天 16:40
- 能给code?最近在研究手机方面的代码,谢谢,511413077@qq.com
- 3楼witmind前天 15:02
- 代码写的很工整,异常处理准确,线程使用节省。楼主应该是位用心写代码的偏完美主义者。
- Re: android_ls前天 15:42
- 回复witmindn看来你认真阅读我写的代码片段了,不过你说的那些我觉得是每个专业程序员都应该做到。我写的还不是很好,有些地方处理的还是不完美。谢谢你的评论和支持!
- 2楼fisherheng3天前 16:42
- 写的很好 学习了
- Re: android_ls前天 23:09
- 回复fisherhengn谢谢夸奖!
- 1楼b879362603天前 14:38
- 直接用AsyncTask可以不?