zoukankan      html  css  js  c++  java
  • MMS源码中异步处理简析

    1,信息数据的查询,删除使用AsycnQueryHandler处理

    AsycnQueryHandler继承了Handler

    public abstract class AsyncQueryHandler extends Handler

     内部使用HandleThread来实现异步线程处理数据,成员变量也有一个Handler并拥有HandleThread的looper。

    private Handler mWorkerThreadHandler;
    
    public AsyncQueryHandler(ContentResolver cr) {
            super();
            mResolver = new WeakReference<ContentResolver>(cr);
            synchronized (AsyncQueryHandler.class) {
                if (sLooper == null) {
                    HandlerThread thread = new HandlerThread("AsyncQueryWorker");
                    thread.start();
    
                    sLooper = thread.getLooper();
                }
            }
            mWorkerThreadHandler = createHandler(sLooper);
        }

    主线程调用AsycnQueryHandler的startQuery方法,成员变量mWorkerThreadHandler传递Message给HandleThread处理,查询参数使用对象WorkerArgs封装。

    public void startQuery(int token, Object cookie, Uri uri,
                String[] projection, String selection, String[] selectionArgs,
                String orderBy) {
            // Use the token as what so cancelOperations works properly
            Message msg = mWorkerThreadHandler.obtainMessage(token);
            msg.arg1 = EVENT_ARG_QUERY;
    
            WorkerArgs args = new WorkerArgs();
            args.handler = this;
            args.uri = uri;
            args.projection = projection;
            args.selection = selection;
            args.selectionArgs = selectionArgs;
            args.orderBy = orderBy;
            args.cookie = cookie;
            msg.obj = args;
    
            mWorkerThreadHandler.sendMessage(msg);
        }
    protected class WorkerHandler extends Handler {
            public WorkerHandler(Looper looper) {
                super(looper);
            }
    
            @Override
            public void handleMessage(Message msg) {
                final ContentResolver resolver = mResolver.get();
                if (resolver == null) return;
    
                WorkerArgs args = (WorkerArgs) msg.obj;
    
                int token = msg.what;
                int event = msg.arg1;
    
                switch (event) {
                    case EVENT_ARG_QUERY:
                        Cursor cursor;
                        try {
                            cursor = resolver.query(args.uri, args.projection,
                                    args.selection, args.selectionArgs,
                                    args.orderBy);
                            // Calling getCount() causes the cursor window to be filled,
                            // which will make the first access on the main thread a lot faster.
                            if (cursor != null) {
                                cursor.getCount();
                            }
                        } catch (Exception e) {
                            Log.w(TAG, "Exception thrown during handling EVENT_ARG_QUERY", e);
                            cursor = null;
                        }
    
                        args.result = cursor;
                        break;

    HandleThread将处理结果result封装到WorkerArgs中,再通过Message传递给AsycnQueryHandler, AsycnQueryHandler调用handleMessage就是主线程中处理了。

    public void handleMessage(Message msg) {
            WorkerArgs args = (WorkerArgs) msg.obj;
    
            if (localLOGV) {
                Log.d(TAG, "AsyncQueryHandler.handleMessage: msg.what=" + msg.what
                        + ", msg.arg1=" + msg.arg1);
            }
    
            int token = msg.what;
            int event = msg.arg1;
    
            // pass token back to caller on each callback.
            switch (event) {
                case EVENT_ARG_QUERY:
                    onQueryComplete(token, args.cookie, (Cursor) args.result);
                    break;

    2,对于信息数据加载后在UI中展现处理。

      ConversationList中ConversationListItem布局时在XML中写好的,只需根据Conversation数据来显示或隐藏对应的view即可。

      ComposeMessageActivity中的MessageListItem需要处理彩信附件,彩信附件有多种格式,且UI布局是从数据库中读取解析,所以无法直接在XML中写好,需要在代码中动态加载。也就是说对于彩信,需要同时处理UI加载(MessageListItem)和数据加载(MessageItem)。

      MessageItem中使用了异步处理加载MMS数据。

    private ItemLoadedFuture mItemLoadedFuture;
    mItemLoadedFuture = MmsApp.getApplication().getPduLoaderManager()
                        .getPdu(mMessageUri, loadSlideshow,
                        new PduLoadedMessageItemCallback());

    PduLoadManager是MMS源码中定义的异步处理类,使用了ThreadPoolExecutor来实现异步处理。getPdu方法中将处理结果封装为PduLoaded类通过PduLoadedMessageItemCallback接口回调将结果在主线程处理。

     ItemLoadedFuture也是使用了接口回调的设计,回调方法setIsDone是在 PduLoadedMessageItemCallback中触发,但实现是在PduLoadManager中,所以主线程可以通过ItemLoadedFuture取消PduLoadManager中的Executor运行。 

    public class PduLoaderManager extends BackgroundLoaderManager
    
    BackgroundLoaderManager(Context context) {
            mPendingTaskUris = new HashSet<Uri>();
            mCallbacks = new HashMap<Uri, Set<ItemLoadedCallback>>();
            final LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
            final int poolSize = MAX_THREADS;
            mExecutor = new ThreadPoolExecutor(
                    poolSize, poolSize, 5, TimeUnit.SECONDS, queue,
                    new BackgroundLoaderThreadFactory(getTag()));
            mCallbackHandler = new Handler();
        }
    public ItemLoadedFuture getPdu(Uri uri, boolean requestSlideshow,
                final ItemLoadedCallback<PduLoaded> callback) {
            if (uri == null) {
                throw new NullPointerException();
            }
           //……此处省略掉一些源码
           //……为了显示不太长,便于查看
            if (pduExists && slideshowExists) {
                if (callbackRequired) {
                    PduLoaded pduLoaded = new PduLoaded(cacheEntry.getPdu(), slideshow);
                    callback.onItemLoaded(pduLoaded, null);
                }//这几从缓存中返回数据
                return new NullItemLoadedFuture();
            }
    
            if (callbackRequired) {
                addCallback(uri, callback);
            }
    
            if (newTaskRequired) {
                mPendingTaskUris.add(uri);
                Runnable task = new PduTask(uri, requestSlideshow);
                mExecutor.execute(task);//后台线程执行加载数据
            }
            return new ItemLoadedFuture() {//返回接口实现
                private boolean mIsDone;
    
                public void cancel(Uri uri) {
                    cancelCallback(callback);
                    removePdu(uri);     // the pdu and/or slideshow might be half loaded. Make sure
                                        // we load fresh the next time this uri is requested.
                }
    
                public void setIsDone(boolean done) {
                    cancelCallback(callback);
                    mIsDone = done;
                }
    
                public boolean isDone() {
                    return mIsDone;
                }
            };
        }

    ItemLoadedFuture接口在MessageItem中声明,但在处理后台线程的类PduLoadManager中实现,可以实现主线程管理后台线程(如取消后台任务)

    PduLoadedMessageItemCallback接口在MessageItem中实现,作为参数传递给PduLoadManager,将后台线程处理的结果result通过方法onItemLoaded(Object result, Throwable exception)返回到主线程处理。

    MessageListItem中加载彩信附件

    private void bindCommonMessage(final boolean sameItem) {
                   ……
                   ……
           
                    if (mMessageItem.mSlideshow == null) {//如果附件数据还未加载完成
                        final int mCurrentAttachmentType = mMessageItem.mAttachmentType;
                        mMessageItem.setOnPduLoaded(new MessageItem.PduLoadedCallback() {//这里又是接口回调实现
                            public void onPduLoaded(MessageItem messageItem) {
                                if (DEBUG) {
                                    Log.v(TAG, "PduLoadedCallback in MessageListItem for item: " + mPosition +
                                            " " + (mMessageItem == null ? "NULL" : mMessageItem.toString()) +
                                            " passed in item: " +
                                            (messageItem == null ? "NULL" : messageItem.toString()));
                                }
                                if (messageItem != null && mMessageItem != null &&
                                        messageItem.getMessageId() == mMessageItem.getMessageId()) {
                                    mMessageItem.setCachedFormattedMessage(null);
                                    bindCommonMessage(//继续调用此方法,直到mMessageItem.mSlideshow加载完成
                                            mCurrentAttachmentType == messageItem.mAttachmentType);
                                }
                            }
                        });
                    } else {
                        if (mPresenter == null) {
                            mPresenter = PresenterFactory.getPresenter(
                                    "MmsThumbnailPresenter", mContext,
                                    this, mMessageItem.mSlideshow);
                        } else {
                            mPresenter.setModel(mMessageItem.mSlideshow);
                            mPresenter.setView(this);
                        }
                        if (mImageLoadedCallback == null) {
                            mImageLoadedCallback = new ImageLoadedCallback(this);
                        } else {
                            mImageLoadedCallback.reset(this);
                        }
                        mPresenter.present(mImageLoadedCallback);
    
                        
                    }
                ……
                ……
            requestLayout();
        }
                            

      

    3, 幻灯片编辑列表界面(SlideshowEditActivity),幻灯片中视频缩略图加载处理。

    SlideListAdapter的getView方法加载幻灯片缩略图
    private View createViewFromResource(int position, View convertView, int resource) {
                SlideListItemView slideListItemView;
                slideListItemView = (SlideListItemView) mInflater.inflate(
                        resource, null);
    
                // Show slide number.
                TextView text;
                text = (TextView) slideListItemView.findViewById(R.id.slide_number_text);
                text.setText(mContext.getString(R.string.slide_number, position + 1));
    
                SlideModel slide = getItem(position);
                int dur = slide.getDuration() / 1000;
                text = (TextView) slideListItemView.findViewById(R.id.duration_text);
                text.setText(mContext.getResources().
                             getQuantityString(R.plurals.slide_duration, dur, dur));
    
                if (mPresenter == null) {
                    mPresenter = PresenterFactory.getPresenter(
                            "SlideshowPresenter", mContext, slideListItemView, mSlideshow);
                } else {
                    mPresenter.setModel(mSlideshow);
                    mPresenter.setView(slideListItemView);
                }
                ((SlideshowPresenter) mPresenter).setLocation(position);            
                mPresenter.present(null);
    
                return slideListItemView;
            }
    SlideshowPresenter中调用present(..)方法,针对视频类型使用了异步线程处理,避免耗时阻塞UI。也是用接口回调设计,
    mItemLoadedFuture = video.loadThumbnailBitmap(mItemLoadedCallback, mLocation, mAdapterHandler);

    mItemLoadedFuture的实现在ThumbnailManager中实现,ThumbnailManager也继承了BackgroundLoaderManager,还是使用Executor实现后台线程。

    mItemLoadedCallback在SlideshowPresenter中实现,并传递给ThumbnailManager,用来将后台线程处理的结果返回到主线程处理。mItemLoadedCallback的回调方法处理返回的缩略图时,需要根据幻灯片的postion确定显示位置。但源码中,直接在SlideListAdapter的getView方法中设置positon,这样等视频缩率图返回时,position的值已经被修改了(因为getView在主线程中处理position, 而视频缩略图在异步线程中处理,当异步线程比主线程慢时,postion已经给后续处理改变了。)对于这个问题,可以将positon直接传给异步线程处理,缩率图显示时直接读取传递下去的postion,就不会被主线程的position影响。

    
    
    
  • 相关阅读:
    年薪百万必备能力
    二叉搜索树
    字符串和字符串模式匹配
    2006最后寄语
    “豆瓣”式推荐
    什么是LOMO?
    大国崛起
    马季之死
    时间的价值(The Value Of Time)
    我读雅虎的“花生酱宣言”
  • 原文地址:https://www.cnblogs.com/antoon/p/5730106.html
Copyright © 2011-2022 走看看