`
xuela_net
  • 浏览: 494292 次
文章分类
社区版块
存档分类
最新评论

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()方法里面的实现:

	@Override
	public 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);
	}

	@Override
	protected 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);
	}

	@Override
	protected 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;

	@Override
	public 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)——网络模块优化

分享到:
评论

相关推荐

    易语言v5.7.1[极致精简版]

    易语言v5.7.1[极致精简版]易语言v5.7.1[极致精简版]易语言v5.7.1[极致精简版]

    MONyog v5.7.1-0 MySQL Monitor Ultimate for Windows

    MONyog MySQL Monitor Ultimate v5.7.1-0,带序列号,本人亲测可用。 此前由于Webyog频繁的调整注册机制,之前的大部分Key都被封杀后,很久一段时间都用不了5.3以后的官网新版。 现在终于有可以使用的新版了,下载...

    HP-Socket v5.7.1.rar

    HP-Socket v5.7.1版本,2019年12月22日最新的资料,支持C,C++,Delphi和E语言,具体C#语言另一个文件上传,这个文件太大了,传不上去了

    Macro Recorder v5.7.1注册版.rar

    软件介绍: 注:本软件需要安装.net4.0框架,否则无法继续安装。JitBit Macro Recorder是一款用于记录键盘鼠标动作的小工具,虽然它的体积很小但是功能却不容小看,它能够轻松记录下所有的键盘和鼠标动作,录制...

    Rosetta Stone-v5.7.1_build_50701017.apk

    Rosetta Stone-v5.7.1_build_50701017.apk

    TMS_Component_pack_fullsource V5.7.1安装版

    TMS_Component_pack_fullsource安装版 V5.7.1

    node-v5.7.1.tar.gz

    此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也...

    QT5.7.1安装包,网络上已经找不到了哦

    QT5.7.1安装包,网络上已经找不到了哦

    int2e-HPSocket.Net-master_v5.7.1.zip

    HPSocket_v5.7.1版本所支持C#文件,需要的可以进行下载,目前国内号称最好的库,超级稳定的一个网络开发库,谢谢

    MONyog v5.7.1-0 MySQL Monitor.zip

    MySQL监控工具 MONyog可以动态地监控企业数据库环境,并针对MySQL系统安全性、数据库优化以及减少停机时间等提供专家意见。

    pypy2-v5.7.1-src.zip

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、...

    pypy3-v5.7.1-src.zip

    通过其灵活的架构,它允许用户轻松地部署计算工作在各种平台(CPUs、GPUs、TPUs)上,无论是在桌面、服务器还是移动设备上。TensorFlow最初由Google Brain团队(属于Google的人工智能部门)开发,并在2015年被发布到...

    【WordPress插件】2022年最新版完整功能demo+插件v5.7.1.zip

    "【WordPress插件】2022年最新版完整功能demo+插件v5.7.1 Stylish Cost Calculator Premium 时尚成本计算器溢价" ---------- 泰森云每天更新发布最新WordPress主题、HTML主题、WordPress插件、shopify主题、...

    Access2MySQL Pro v5.7.1

    Access2MySQL 是能允许你转换.mdb((Microsoft Access 数据库)数据库为MySQL以及反之亦然的高效应用程序.不像其他只能进行单向转换的工具.除此之外,Acces2MySQL 支持数据库同步,可以避免重复数据。

    pypy2-v5.7.1-win32.zip

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、...

    【WordPress插件】2022年最新版完整功能demo+插件v5.7.1 Nulled.zip

    "【WordPress插件】2022年最新版完整功能demo+插件v5.7.1 Nulled ARForms: Wordpress Form Builder Plugin Arforms:WordPress Form Builder插件" ---------- 泰森云每天更新发布最新WordPress主题、HTML主题、...

    pypy2-v5.7.1-src.tar.bz2

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、...

    pypy3-v5.7.1-src.tar.bz2

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、...

    pypy2-v5.7.1-osx64.tar.bz2

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、...

    pypy2-v5.7.1-ppc64.tar.bz2

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、...

Global site tag (gtag.js) - Google Analytics