------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">java培訓</a>、期待與您交流! ----------
小弟新手一枚,我先來說說我自己在項目中的做法。因爲小弟只有JAVAWEB的基礎所以只能使用線程池來處理線程之間的切換
1.爲了使APP不出現卡頓和內存的低消耗。我是用了synchronized 和用一個Map 來限定每次只能運行一條子線程,Map 鍵:TAG 線程任務標記 、值:FutureTask線程任務,
2.當然線程之間的切換仍然還是使用handle,只是在等待分線程執行完,當然分線程也會由限定時間。
下面來看看代碼:
public class OCThreadExecutor extends ThreadPoolExecutor {
private Map<String,FutureTask> runnableMap;
public OCThreadExecutor(int maxRunningThread, String poolName) {
super(maxRunningThread, maxRunningThread, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new OCThreadFactory(poolName));
runnableMap = new HashMap<>();
}
以上是自定義線程池,帶參的構造方法;
static class OCThreadFactory implements ThreadFactory {
private final String name;
public OCThreadFactory(String name) {
this.name = name;
}
public String getPoolName() {
return name;
}
@Override
public Thread newThread(@NonNull Runnable r) {
return new OCThread(r, name);
}
}
static class OCThread extends Thread {
public OCThread(Runnable runnable, String name) {
super(runnable, name);
setName(name);
}
@Override
public void run() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
super.run();
}
}
實現線程工廠;
重點來了:
/**
* 執行任務
* @param task 任務對象
* @param tag 任務唯一TAG
*/
public void submit(FutureTask task , String tag){
synchronized (this){
//執行線程
if ( !runnableMap.containsKey(tag) ){
//如果池內沒有相同的任務則可以執行
Log.d("OCThreadExecutor", "Task submitting TAG: "+tag);
runnableMap.put(tag, task);
submit(task);
}else{
Log.d("OCThreadExecutor", "Pool: "+((OCThreadFactory)getThreadFactory()).getPoolName()+" Same task TAG. Skipped. "+tag);
}
}
}
以上提交方法的tag值是爲了唯一識別正在執行的線程,或者判斷該線程有沒有在執行。
如果沒有將執行該任務,且添加進Map
下面是得到URL訪問網絡:
protected NetworkHelper() {
handler = new Handler(Looper.getMainLooper());
httpClient = new OkHttpClient();
threadExecutor = new OCThreadExecutor(1,"networkTHS");
}
public static NetworkHelper getInstance() {
if (networkHelper == null){
networkHelper = new NetworkHelper();
}
return networkHelper;
}
/**
* UI 線程
* @param runnable 在UI線程運行的任務
*/
private void runOnUIThread(@NonNull Runnable runnable){
boolean done = handler.post(runnable);
while (!done){
handler = new Handler(Looper.getMainLooper());
runOnUIThread(runnable);
}
}
任務在UI線程中運行,知道任務完成,這是最讓我糾結的地方,但是在項目中有沒有出現過問題,可能是我現在的訪問量不大吧!!
下面是一個獲取項目文章的線程方法:
/**
* 讀取文章
* @param onArtcleLoadCallback 讀取進度回調
* @param needToCacheImage 是否進行緩存圖片網址以供主界面滾動顯示
* @param args 附帶的參數
*/
public void loadArtcles(@Nullable OnArtcleLoadCallback onArtcleLoadCallback ,@NonNull boolean needToCacheImage ,@NonNull String[] args){
threadExecutor.submit(new FutureTask<>(new GetArtclesThread(onArtcleLoadCallback, needToCacheImage, args)),GetArtclesThread.TAG+args[2]);
}
下載文章線程:
/**
* 獲取文章以及緩存首頁滾動圖片的任務
*/
class GetArtclesThread implements Callable<String>{
public static final String TAG = "GetArtclesThread";
private OnArtcleLoadCallback onArtcleLoadCallback;
private boolean needToCacheImage;
private ArrayList<ArtclesBean> artcles = null;
private String[] args;
public GetArtclesThread(OnArtcleLoadCallback onArtcleLoadCallback, boolean needToCacheImage ,String[] args) {
this.onArtcleLoadCallback = onArtcleLoadCallback;
this.needToCacheImage = needToCacheImage;
this.args = args;
}
@Override
public String call() throws Exception {
//先檢查OKHttp是否有效
if (httpClient == null){
httpClient = new OkHttpClient();
}
//如果參數數量大於等於4,則執行請求
if (args != null && args.length >= 4){
try {
artcles = requestData();
} catch (IOException e) {
Log.d(TAG, "Exception:"+e);
failed(null,e);
return null;
}
}else {
failed("無效的請求參數",null);
return null;
}
completed();
return null;
}
這是一個獲取文章的任務,這個任務會在線程池中執行,在回調方法中會先執行請求文章,當獲取文章完成之後纔會去UI線程顯示文章。
目前只知道這種方式,不知道大家有沒有更好的方法? 求教