android多线程以及线程池使用

之前有关线程、多线程、线程池等概念经常接触,但是实际工作中用的却不是很多,刚好公司app对商品详情页有一个优化的任务,在参考了一些主流app的处理方式以后,发现他们的思路都是一样的:拆分接口,模块化加载。

在确定了思路以后,对安卓客户端的程序设计我是这么考虑的:
- 接口请求与activity视图加载并发进行
- 尽可能早地进行接口请求
- 接口请求完成以后进入一个等待的状态,等待视图加载完成再进行数据绑定
- 由于接口请求完成的先后顺序不可控,需要一个统一的请求队列进行管理,并且利用synchronized关键字处理好同步问题
- 使用HandlerThread作为分发消息的单独线程
- 使用WeakReference来防止内存泄漏

首先介绍一些使用到的工具

  • CountDownLatch
    CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。
  • HandlerThread
    HandlerThread是一个子线程,它拥有自己的消息队列,利用它可以实现子线程与主线程之间的通信。
  • ExecutorService
    ExecutorService线程池,系统提供了多种线程池实例,这里我用到的是newFixedThreadPool,这是一种定长线程数的线程池,这里我配置的线程数是手机CPU核心数+1。

部分代码流程

1.进入DetailActivity之前就开始请求接口(我们将详情页接口拆分成了6个接口)

//title和image分别为商品的标题和图片,我们可以在进入activity后先显示这2项,一般都可以在入口处获取到这2项数据,这样能给人一种快速打开页面的感觉,主流的app都是这么处理的
public static void start(Activity activity, PageExtras pageExtras) {
        if (pageExtras != null) {
            ItemDataQueue.get().loadAll(pageExtras.getItemUid(), new int[]{MSG_WHAT_BASIC,
                    MSG_WHAT_COMMENT,
                    MSG_WHAT_COUPON,
                    MSG_WHAT_MARKET,
                    MSG_WHAT_SKU,
                    MSG_WHAT_SUGGEST});
            Intent intent = new Intent(activity, DetailActivity.class);
            intent.putExtra("item_uid", pageExtras.getItemUid());
            intent.putExtra("title", pageExtras.getTitle());
            intent.putExtra("image", pageExtras.getImage());
            activity.startActivity(intent);
        }
    }
//请求队列
public class ItemDataQueue {
    private static ItemDataQueue itemDataQueue;

    public synchronized static ItemDataQueue get(){
        if (itemDataQueue == null){
            itemDataQueue = new ItemDataQueue();
        }
        return itemDataQueue;
    }
    private ItemDataQueueLatch<MKItemBasic> countDownLatchBasic;
    //省略其余5个
    /**
     * 并行加载所有请求
     * @param item_uid
     */
    public void loadAll(final String item_uid , int...targets){
        cancelAll();
        if (targets != null){
            for (int t : targets){
                switch (t){
                    case DetailActivity.MSG_WHAT_BASIC:
                        countDownLatchBasic = new ItemDataQueueLatch<>(item_uid);
                        httpBasic(item_uid);
                        break;
                    ...
                }
            }

        }
    }
    private void httpBasic(final String item_uid) {
        countDownLatchBasic = new ItemDataQueueLatch<>(item_uid);
        MKItemCenter.getItemBasic( item_uid, new BusinessListener(null) {
            @Override
            public void onSuccess(MKBaseObject baseObject) {
                if (countDownLatchBasic != null && TextUtils.equals(countDownLatchBasic.getItem_uid(),item_uid)){
                    countDownLatchBasic.setData(((MKItemBasicResponse)baseObject).getData());
                    countDownLatchBasic.countDown();
                }
            }

            @Override
            public void onFail(MKBaseObject baseObject) {
                if (countDownLatchBasic != null && TextUtils.equals(countDownLatchBasic.getItem_uid(),item_uid)){
                    countDownLatchBasic.countDown();
                }
            }

            @Override
            public void onError() {
                if (countDownLatchBasic != null && TextUtils.equals(countDownLatchBasic.getItem_uid(),item_uid)){
                    countDownLatchBasic.countDown();
                }
            }
        });
    }
    public MKItemBasic getBasic(String item_uid){
        if (countDownLatchBasic == null){
            return null;
        }
        try {
            countDownLatchBasic.await(TIME_OUT_SEC, TimeUnit.SECONDS);
            if (countDownLatchBasic != null && TextUtils.equals(countDownLatchBasic.getItem_uid(),item_uid)){
                return countDownLatchBasic.getData();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }
    public void cancelAll(){
        if (countDownLatchBasic != null){
            countDownLatchBasic.countDown();
            countDownLatchBasic = null;
        }
        ...
    }
}

2.视图初始化完以后开始接收数据

//创建线程池
public class ItemDataThreadPool {

    private static ExecutorService executorService;

    //分发消息的队列的单独线程
    private static HandlerThread handlerThread;

    public static ExecutorService get(){
        if (executorService == null){
            executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
        }
        return executorService;
    }

    public static HandlerThread getHandlerThread(){
        if (handlerThread == null || !handlerThread.isAlive()){
            handlerThread = new HandlerThread("DetailActivity");
            handlerThread.start();
        }
        return handlerThread;
    }

}
//DetailActivity
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);
        ...
        fetchData(mItemUid,targets);
    }
    public void fetchData(String item_uid, int... targets) {
        for (int t : targets) {
            switch (t) {
                case DetailActivity.MSG_WHAT_BASIC:
                    mData.clearBasic();
                    ItemDataThreadPool.get().execute(new Runnable() {
                        @Override
                        public void run() {
                            Message msg = new Message();
                            msg.what = MSG_WHAT_BASIC;
                            msg.obj = ItemDataQueue.get().getBasic(mItemUid);
                            mHandler.sendMessage(msg);
                        }
                    });
                    break;
                ...
            }
        }
    }
//向主线程发送接收到的数据
public class ItemHandler extends Handler {

    private final WeakReference<DetailActivity> mActivity;

    public ItemHandler(Looper looper , DetailActivity activity){
        super(looper);
        mActivity = new WeakReference<>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        if (mActivity.get() != null && !mActivity.get().isFinishing()){
            switch (msg.what){
                case MSG_WHAT_BASIC:
                    if (msg.obj != null){
                        mActivity.get().setBasicData((MKItemBasic) msg.obj);
                    } else {
                        mActivity.get().setBasicData(null);
                    }
                    break;
                ...
            }
        }
    }
}
//最后在DetailActivity的setBasicData等方法中绑定数据
public void setBasicData(final MKItemBasic basicData) {
...
}

总结:
大致的流程就是这样,具体的代码逻辑就不贴了。在视图上,我采用模块化加载的方式将页面分成了多个模块,最理想的是每个接口对应相应的模块,但是实际上模块与接口之间都是穿插的较多,这时候就要用到synchronized实现同步了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值