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影响。
MMS源码中异步处理简析的更多相关文章
- SpringMVC源码情操陶冶-DispatcherServlet简析(二)
承接前文SpringMVC源码情操陶冶-DispatcherServlet类简析(一),主要讲述初始化的操作,本文将简单介绍springmvc如何处理请求 DispatcherServlet#doDi ...
- Vue源码之 virtual-dom 实现简析
发现两篇写得特别好的博文,仔细通读,发现豁然开朗. 浅析Vue 中的patch和diff Vue 2.0 的 virtual-dom 实现简析
- 从express源码中探析其路由机制
引言 在web开发中,一个简化的处理流程就是:客户端发起请求,然后服务端进行处理,最后返回相关数据.不管对于哪种语言哪种框架,除去细节的处理,简化后的模型都是一样的.客户端要发起请求,首先需要一个标识 ...
- Android 网络框架之Retrofit2使用详解及从源码中解析原理
就目前来说Retrofit2使用的已相当的广泛,那么我们先来了解下两个问题: 1 . 什么是Retrofit? Retrofit是针对于Android/Java的.基于okHttp的.一种轻量级且安全 ...
- rxjava源码中的线程知识
rxjava源码中的线程知识 rx的最精简的总结就是:异步 这里说一下以下的五个类 1.Future2.ConcurrentLinkedQueue3.volatile关键字4.AtomicRefere ...
- Android Mms专题之:Mms源码结构
从软件的功能角度来讲,Mms分为对话列表,消息列表,短信编辑,彩信编辑,短信显示,彩信显示和配置. 从实现的角度来看,它分为GUI展示层,发送/接收,彩信解析,彩信附件,信息数据等,这些分类对应着源码 ...
- fileinput 配置项大全,从源码中翻出了很多属性,没那么多时间一一验证,特发出来给大家参考参考
fileinput 配置项大全,从源码中翻出了很多属性,没那么多时间一一验证,特发出来给大家参考参考 fileinput 配置项大全 option 属性名 属性类型 描述说明 默认值 language ...
- Eclipse与Android源码中ProGuard工具的使用
由于工作需要,这两天和同事在研究android下面的ProGuard工具的使用,通过查看android官网对该工具的介绍以及网络上其它相关资料,再加上自己的亲手实践,算是有了一个基本了解.下面将自己的 ...
- String源码中的"avoid getfield opcode"
引言: 之前一篇文章梳理了String的不变性原则,还提到了一段源码中注释"avoid getfield opcode",当时通过查阅资料发现,这是为了防止 getfield(获取 ...
随机推荐
- python几个重要的模块备忘
一:模块使用方法 二:时间模块time 三:系统接口模块os和sys 四:数据保存的几个模块json,pickle,xml,configparse 五:数据复制移动模块shutil 六:日志模块log ...
- 解决低版本chrome浏览器不支持es6 Array.find()
if (!Array.prototype.find) { Array.prototype.find = function(predicate) { 'use strict'; if ( ...
- Windows转到linux中,文件乱码,文件编码转换 & 解决sqlplus连接oracle乱码
转载:http://www.cnblogs.com/wanyao/p/3399269.html 最近,学习又重新开始Linux学习,所以一直在Centos中,昨天一朋友把他在Windows下写的C程序 ...
- 大型网站一致性的基础理论---CAP/BASE
最近在看<大型网站系统与java中间件事件>这本书,收获颇多. 分布式事务希望在多机环境下可以像单机系统那样做到强一致,这需要付出比较大的代价.而在有些场景下,接受状态并不用时刻保持一致, ...
- ATL开发 ActiveX控件的 inf文件模板
ATL开发 ActiveX控件的 inf文件模板
- HttpClient接口测试之会话保持
HttpClient接口测试之会话保持 HttpClient4.X自带会话保持功能,使用同一个HttpClient未关闭的连接即可保持登陆会话,如果多个HttpClient想要使用一个登陆会话 ...
- Kafka深入理解-1:Kafka高效的文件存储设计
文章摘自:美团点评技术团队 Kafka文件存储机制那些事 Kafka是什么 Kafka是最初由Linkedin公司开发,是一个分布式.分区的.多副本的.多订阅者,基于zookeeper协调的分布式日 ...
- 转:python dict按照value 排序
我们知道Python的内置dictionary数据类型是无序的,通过key来获取对应的value.可是有时我们需要对dictionary中 的item进行排序输出,可能根据key,也可能根据value ...
- c# 实现 java 的 System.currentTimeMillis() 值
本文地址:http://www.cnblogs.com/jying/p/3875331.html 以下一句即可实现 java 中的 System.currentTimeMillis() 值 , , , ...
- EntityFramework Reverse POCO Generator工具
https://visualstudiogallery.msdn.microsoft.com/ee4fcff9-0c4c-4179-afd9-7a2fb90f5838