編輯: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;
- }
- }
好了就到這裡吧,後面的待續。。。
這一篇網絡模塊處理有些地方有待優化,優化處理部分請閱讀下篇。
轉自:http://blog.csdn.net/android_ls/article/details/8732427
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我
登錄應用程序的屏幕,詢問憑據登錄到一些特定的應用。可能需要登錄到Facebook,微博等本章介紹了,如何創建一個登錄界面,以及如何管理安全問題和錯誤嘗試。首先,必須定義兩
Content Provider:一個組件,必須放在應用的主包或應用的子包之下; 組件的配置需要在清單文件中進行配置;content provider需要在app
登錄應用程序的屏幕,詢問憑據登錄到一些特定的應用。可能需要登錄到Facebook,微博等本章介紹了,如何創建一個登錄界面,以及如何管理安全問題和錯誤嘗試。首先,必須定義兩