您的位置:首页 > 职场人生

黑马程序员-多线程-在android开发中经常会遇到从子线程切换到主线程,但是频繁地切换会使代码变得很臃肿,也不好维护,想请教一下各位大牛都是怎么处理的?

2016-06-24 20:16 856 查看
------- <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线程显示文章。

目前只知道这种方式,不知道大家有没有更好的方法? 求教
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息