Android 7.0 Gallery图库源码分析3
来源:互联网 发布:淘宝物品拍摄技巧 编辑:程序博客网 时间:2024/06/10 12:25
转载请注明出处: http://blog.csdn.net/lb377463323/article/details/69569133
前面分析Gallery启动流程时,说了传给DataManager的data的key是AlbumSetPage.KEY_MEDIA_PATH,value值,是”/combo/{/local/all,/picasa/all}”,下面分析具体怎么加载数据的。
数据加载的准备阶段
数据初始化是在AlbumSetPage的initializeData方法中。
private void initializeData(Bundle data) { //mediaPath即为"/combo/{/local/all,/picasa/all}" String mediaPath = data.getString(AlbumSetPage.KEY_MEDIA_PATH); //获取MediaSet来管理一组媒体数据 mMediaSet = mActivity.getDataManager().getMediaSet(mediaPath); /mSelectionManager用于管理选择事件 mSelectionManager.setSourceMediaSet(mMediaSet); //mAlbumSetDataAdapter类似于桥梁来连接页面和数据源 mAlbumSetDataAdapter = new AlbumSetDataLoader( mActivity, mMediaSet, DATA_CACHE_SIZE); //设置数据加载的监听接口 mAlbumSetDataAdapter.setLoadingListener(new MyLoadingListener()); mAlbumSetView.setModel(mAlbumSetDataAdapter); }
mActivity.getDataManager()就是获取Application(GalleryAppImpl)的DataManager,我们接着看getMediaSet方法,
//根据路径获取MediaObject,s为"/combo/{/local/all,/picasa/all}"public MediaSet getMediaSet(String s) { return (MediaSet) getMediaObject(s); }public MediaObject getMediaObject(String s) { return getMediaObject(Path.fromString(s)); }//进到PATH类中private WeakReference<MediaObject> mObject;private IdentityCache<String, Path> mChildren;public static Path fromString(String s) { synchronized (Path.class) { String[] segments = split(s); //segments为["combo", "{/local/all,/picasa/all}"] Path current = sRoot; for (int i = 0; i < segments.length; i++) { current = current.getChild(segments[i]); } //经过for循环,current会持有两条路径,"combo"为父PATH,"{/local/all,/picasa/all}"为子PATH return current; } }//获取PATH对应得MediaObjectpublic MediaObject getMediaObject(Path path) { synchronized (LOCK) { //根据PATH获取MediaObject,不为空直接返回 MediaObject obj = path.getObject(); if (obj != null) return obj; //根据PATH的前缀获取mSourceMap对应的MediaSource,mSourceMap初始化在源码分析2中讲过,这里返回的就是ComboSource MediaSource source = mSourceMap.get(path.getPrefix()); ...... try { //走到这里说明MediaObject为空,所以需要创建MediaObject MediaObject object = source.createMediaObject(path); return object; ...... } }
我们接着看下ComboSource的createMediaObject方法
public MediaObject createMediaObject(Path path) { //segments为["combo", "{/local/all,/picasa/all}"] String[] segments = path.split(); ...... //match结果为COMBO_ALBUMSET switch (mMatcher.match(path)) { //创建一个ComboAlbumSet并返回,dataManager.getMediaSetsFromString(segments[1])这个方法就是根据"{/local/all,/picasa/all}"创建LocalSource实例和PicasaSource实例以及对应的LocalAlbumSet实例和EmptyAlbumSet实例,这个过程就是重复上述步骤 case COMBO_ALBUMSET: return new ComboAlbumSet(path, mApplication, dataManager.getMediaSetsFromString(segments[1])); ...... }
创建好后,最终返回给AlbumSetPage的initializeData方法中的mMediaSet
private void initializeData(Bundle data) { ...... //mMediaSet就是ComboAlbumSet,也就是数据源,它管理着LocalAlbumSet和EmptyAlbumSet mMediaSet = mActivity.getDataManager().getMediaSet(mediaPath); mSelectionManager.setSourceMediaSet(mMediaSet); //mAlbumSetDataAdapter类似于桥梁来连接页面和数据源 mAlbumSetDataAdapter = new AlbumSetDataLoader( mActivity, mMediaSet, DATA_CACHE_SIZE); mAlbumSetDataAdapter.setLoadingListener(new MyLoadingListener()); 将mAlbumSetDataAdapter传给界面显示的渲染器 mAlbumSetView.setModel(mAlbumSetDataAdapter); }
setModel这个方法挺重要的,它在AlbumSetSlotRenderer中,我们具体看一下
public void setModel(AlbumSetDataLoader model) { ...... if (model != null) { //根据model创建AlbumSetSlidingWindow,它是负责滑动显示图片的,比如解码专辑缩略图等 mDataWindow = new AlbumSetSlidingWindow( mActivity, model, mLabelSpec, CACHE_SIZE); //设置监听接口,处理尺寸改变或内容改变的事件 mDataWindow.setListener(new MyCacheListener()); mSlotView.setSlotCount(mDataWindow.size()); } }
到这里数据源和数据源适配器都创建好了,并且也传给了AlbumSetPage页面,这样数据加载的准备工作就做好了,也就是onCreate方法执行结束,下面分析onResume方法,这里完成数据的实际加载过程。
数据加载过程
首先查看GalleryActivity的OnResume方法,
protected void onResume() { //调用其父类的OnResume方法 super.onResume(); } }
我们接着查看AbstractGalleryActivity的的OnResume方法
protected void onResume() { ...... try { //数据加载的核心在这里 getStateManager().resume(); //这个方法只有LocalSource获取ContentProvider,别的都是什么操作都没有 getDataManager().resume(); } mGLRootView.onResume(); mOrientationManager.resume(); }
StateManager().resume的方法如下:
public void resume() { //我们是从桌面图标进的应用,所以getTopState获取的是AlbumSetPage if (!mStack.isEmpty()) getTopState().resume(); }
我们看一下AlbumSetPage的resume方法,AlbumSetPage没有重写resume方法,所以调用的是其父类ActivityState的resume方法,我们先看一下
void resume() { ...... //这里就是调用AlbumSetPage的onResume方法 onResume(); ...... } public void onResume() { ...... //数据加载就是这一步完成的 mAlbumSetDataAdapter.resume(); ......
前面讲了mAlbumSetDataAdapter是一个AlbumSetDataLoader类,所以我们去看AlbumSetDataLoader的resume方法
public void resume() { //这个接口是数据变化的监听接口,当完成数据加载时会回调mSourceListener的onContentDirty方法 mSource.addContentListener(mSourceListener); //ReloadTask就是完成数据加载任务的子线程 mReloadTask = new ReloadTask(); mReloadTask.start(); }
我们看一下ReloadTask的run方法
public void run() { ...... //这里执行数据加载 long version = mSource.reload(); ......}mSource是new AlbumSetDataLoader( mActivity, mMediaSet, DATA_CACHE_SIZE)传入的mMediaSet,前面讲了mMediaSet就是ComboAlbumSet,它包含一个LocalAlbumSet和EmptyAlbumSet
我们去ComboAlbumSet类中查看它的reload方法
public long reload() { //mSets即为ComboAlbumSet所包含的LocalAlbumSet和EmptyAlbumSet,这里也就是分别调用LocalAlbumSet和EmptyAlbumSet的reload方法 for (int i = 0, n = mSets.length; i < n; ++i) { long version = mSets[i].reload(); ......
因为EmptyAlbumSet的reload方法就是返回数据版本,所以暂且不管它。下面只分析LocalAlbumSet的reload方法。
public synchronized long reload() { ...... //通过ThreadPool线程池执行专辑数据的加载,AlbumsLoader方法看下面讲述 mLoadTask = mApplication.getThreadPool().submit(new AlbumsLoader(), this); //这里就是对每个专辑进行数据加载,这之后的就不讲了 for (MediaSet album : mAlbums) { album.reload(); }
submit方法就是把job和listener封装成一个Worker,然后传给ThreadPoolExecutor执行
public <T> Future<T> submit(Job<T> job, FutureListener<T> listener) { Worker<T> w = new Worker<T>(job, listener); mExecutor.execute(w); return w; }
ThreadPoolExecutor的execute方法最终也是执行Worker的run方法,现在看下Worker的run方法
public void run() { ...... //mJob就是submit传进来的new AlbumsLoader() result = mJob.run(this); ...... //mListener是FutureListener接口,这里也就是LocalAlbumSet自身 if (mListener != null) mListener.onFutureDone(this);}
接着看下AlbumsLoader的run方法,这里主要是获取专辑的信息
private class AlbumsLoader implements ThreadPool.Job<ArrayList<MediaSet>> { @Override @SuppressWarnings("unchecked") public ArrayList<MediaSet> run(JobContext jc) { ...... //通过BucketHelper获取所有的专辑信息 BucketEntry[] entries = BucketHelper.loadBucketEntries( jc, mApplication.getContentResolver(), mType); ...... for (BucketEntry entry : entries) { //获取LocalAlbum并保存到ArrayList(albums)中,albums对应于每个专辑 MediaSet album = getLocalAlbum(dataManager, mType, mPath, entry.bucketId, entry.bucketName); albums.add(album); }
当AlbumsLoader的run方法执行完后,接着执行mListener.onFutureDone回调接口,通过这个接口通知MediaSet内容有变化。最终会走到AlbumSetDataLoader的onContentDirty方法
public void onContentDirty() { //这个方法会唤醒所以wait的线程 mReloadTask.notifyDirty(); }
现在我们回到AlbumSetDataLoader的ReloadTask中,reload方法执行之后会通过updateLoading发送MSG_LOAD_FINISH消息
while (mActive) { ...... //这一块很重要,用来更新界面的 //获取需要更新的数据信息,包括专辑数量等,这里我不细讲了,自己看代码 UpdateInfo info = executeAndWait(new GetUpdateInfo(version)); ...... //根据数据信息更新界面,这个方法最终会执行UpdateContent的call方法 executeAndWait(new UpdateContent(info));}//这个方法发送 MSG_LOAD_FINISH消息通知数据加载完成,这里不细讲了updateLoading(false);
更新界面
private class UpdateContent implements Callable<Void> { public Void call() { //这里是更新Slot数目 if (mDataListener != null) mDataListener.onSizeChanged(mSize); ...... //更新内容 mDataListener.onContentChanged(info.index); }}
mDataListener是实例化AlbumSetSlidingWindow是设置的,也就是AlbumSetSlidingWindow自身
source.setModelListener(this);
接着看AlbumSetSlidingWindow的onSizeChanged和onContentChanged方法
public void onSizeChanged(int size) { if (mIsActive && mSize != size) { mSize = size; //mListener是AlbumSetSlotRenderer的,MyCacheListener,onSizeChanged就是执行mSlotView.setSlotCount(size) if (mListener != null) mListener.onSizeChanged(mSize); if (mContentEnd > mSize) mContentEnd = mSize; if (mActiveEnd > mSize) mActiveEnd = mSize; } } public void onContentChanged(int index) { //更新图像 AlbumSetEntry entry = mData[index % mData.length]; updateAlbumSetEntry(entry, index); updateAllImageRequests(); updateTextureUploadQueue(); //onContentChanged方法就是执行mSlotView.invalidate()刷新界面 if (mListener != null && isActiveSlot(index)) { mListener.onContentChanged(); } }
到这里就完成了SlotView的渲染准备工作,至于怎么渲染到屏幕上见Gallery图库源码分析6。
- Android 7.0 Gallery图库源码分析3
- Android 7.0 Gallery图库源码分析1
- Android 7.0 Gallery图库源码分析2
- Android 7.0 Gallery图库源码分析4
- Android 7.0 Gallery图库源码分析5
- Android 7.0 Gallery图库源码分析6
- Android 7.0 Gallery图库源码分析7
- Android 7.0 Gallery图库源码分析8
- Android 7.0 Gallery图库源码分析1
- Android 7.0 Gallery图库源码分析9
- 编译Android Gallery图库源码所遇bug
- android从图库(gallery)选择一张图片
- android从图库(gallery)选择一张图片
- Google Gallery for Android 4.4源码分析以及主UI修改——Gallery整体结构
- android gallery photoview分析
- Matplotlib gallery 图库
- Android Gallery实现3D相册(附效果图+Demo源码)
- Android Gallery实现3D相册(附效果图+Demo源码)
- servlet生命周期与工作原理
- 李白打酒
- 自己用ssh框架写了个小项目中的一些总结
- jni崩溃输出
- [LeetCode]Course Schedule II
- Android 7.0 Gallery图库源码分析3
- 昨天终于把《VISUAL C++ 2010入门经典_第5版(中文版)》看完一遍了
- css初步学习1——css格式,文字处理属性,颜色属性
- Action 跳转的方法和详解
- c语言中逗号运算符的作用
- Mybatis where in语句如何传参数
- 网络抓包工具Fiddler的使用
- 十条笑话:结账时要320元,于是我和老板讲价,说给300行不
- materiallDesign资料收集