編輯:Android編程入門
本篇文章我們來一起寫一個最基本的Android異步網絡請求框架,借此來了解下Android中網絡請求的相關姿勢。由於個人水平有限,文中難免存在疏忽和謬誤,希望大家可以指出,謝謝大家:)
以HTTP的GET請求為例,我們來介紹一下Android中一個基本的同步請求框架的實現。直接貼代碼:
public class HttpUtils {
public static byte[] get(String urlString) {
HttpURLConnection urlConnection = null;
try {
URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
//設置請求方法
urlConnection.setRequestMethod("GET");
//設置超時時間
urlConnection.setConnectTimeout(5000);
urlConnection.setReadTimeout(3000);
//獲取響應的狀態碼
int responseCode = urlConnection.getResponseCode();
if (responseCode == 200) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
InputStream in = urlConnection.getInputStream();
byte[] buffer = new byte[4 * 1024];
int len = -1;
while((len = in.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
close(in);
byte[] result = bos.toByteArray();
close(bos);
return result;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return null;
}
private static void close(Closeable stream) {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
相信以上的代碼我們大家都不陌生,以上代碼就實現了基本的同步網絡請求功能,get 方法會返回一個byte[]數組,後續我們可以根據返回的相應類型(文本或圖片)對這個字節數組作進一步處理。
通常一個異步HTTP GET請求是這樣的:發出get方法的調用後,相關任務會在後台線程中自動執行,而我們在主線程中繼續處理其他工作,它成功獲取GET請求的響應時,就會回調onSuccess方法。最直接的寫法通常如下所示:
public class AsyncHttpUtils {public static byte[] get(String url, ResponseHandler handler) {
final Handler mHandler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
final byte[] result = HttpUtils.get(url);
handler.post(new Runnable() {
@Override
public void run() {
responseHandler.onSuccess(result);
}
});
}
});
}
}
其中,ResponseHandler接口的定義如下:
public interface ResponseHandler {
void onSucess(bytep[] result);
}
我們可以看到,以上實現異步GET請求的代碼很直截了當,然而存在著以下問題:每次請求時都會創建一個線程,這樣當請求比較頻繁的情況下會創建大量大線程,這樣的話創建、銷毀線程以及線程調度的開銷會很大。而且Thread對象是一個匿名內部類對象,會隱式持有外圍類引用,可能會引起Memory Leak。
針對以上問題,我們可以使用線程池來復用線程,以避免不必要的創建及銷毀線程的開銷,改進後AsyncHttpUtils類的代碼如下:
public class AsyncHttpUtils {
//獲取當前設備的CPU數
public static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//核心池大小設為CPU數加1
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
//設置線程池的最大大小
private static final int MAX_POOL_SIZE = 2 * CPU_COUNT + 1;
//存活時間
private static final long KEEP_ALIVE = 5L;
//創建線程池對象
public static final Executor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAX_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
public static void get(final String url, final ResponseHandler responseHandler) {
final Handler mHandler = new Handler(Looper.getMainLooper());
//創建一個新的請求任務
Runnable requestRunnable = new Runnable() {
@Override
public void run() {
final byte[] result = HttpUtils.get(url);
if (result != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
//result不為空表明請求成功,回調onSuccess方法
responseHandler.onSuccess(result);
}
});
}
}
};
threadPoolExecutor.execute(requestRunnable);
}
}
以上代碼主要就是使用了線程池來達到線程的復用的目的,關於線程池的更加深入詳細的介紹,大家可以看這裡:深入理解Java之線程池
Android docs
Android開發學習之路-Android Studio真神器!
放假之後電腦配置升級就開始用Android Studio(下面簡稱AS)了,那個酸爽真的不是一般的啊,這裡開一篇博客來記錄下AS裡面各種酷炫的功能,有更好玩的,大家不要吝
Android—自定義控件實現ListView下拉刷新
這篇博客為大家介紹一個android常見的功能——ListView下拉刷新(參考自他人博客,網址忘記了,閱讀他的代碼自己理解注釋的,希望能幫助到大
總結一下Android中主題(Theme)的正確玩法
在AndroidManifest.xml文件中有<application android:theme=@style/AppTheme>,其中的@style/A
Android應用的閃退(crash)分析
阿裡客戶端工程師試題簡析——Android應用的閃退(crash)分析1. 問題描述 閃退(Crash)是客戶端程序在運行時遭遇無法處理的異常或