1,信息數據的查詢,刪除使用AsycnQueryHandler處理數據庫
AsycnQueryHandler繼承了Handler緩存
public abstract class AsyncQueryHandler extends Handler
內部使用HandleThread來實現異步線程處理數據,成員變量也有一個Handler並擁有HandleThread的looper。cookie
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就是主線程中處理了。ide
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中展示處理。oop
ConversationList中ConversationListItem佈局時在XML中寫好的,只需根據Conversation數據來顯示或隱藏對應的view便可。佈局
ComposeMessageActivity中的MessageListItem須要處理彩信附件,彩信附件有多種格式,且UI佈局是從數據庫中讀取解析,因此沒法直接在XML中寫好,須要在代碼中動態加載。也就是說對於彩信,須要同時處理UI加載(MessageListItem)和數據加載(MessageItem)。post
MessageItem中使用了異步處理加載MMS數據。ui
private ItemLoadedFuture mItemLoadedFuture;
mItemLoadedFuture = MmsApp.getApplication().getPduLoaderManager() .getPdu(mMessageUri, loadSlideshow, new PduLoadedMessageItemCallback());
PduLoadManager是MMS源碼中定義的異步處理類,使用了ThreadPoolExecutor來實現異步處理。getPdu方法中將處理結果封裝爲PduLoaded類經過PduLoadedMessageItemCallback接口回調將結果在主線程處理。this
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影響。