https://blog.csdn.net/lb377463323/article/details/69523891
根据不同的getIntent()意图进行初始化,我们这里主要是看桌面点击程序的初始化 initCustomerView()
package com.android.gallery3d.app;
public final class GalleryActivity extends AbstractGalleryActivity implements OnCancelListener {
private void initializeByIntent() {
Intent intent = getIntent();
String action = intent.getAction();
if (Intent.ACTION_GET_CONTENT.equalsIgnoreCase(action)) {
mDrawerLayoutSupported = false;
startGetContent(intent);
} else if (Intent.ACTION_PICK.equalsIgnoreCase(action)) {
mDrawerLayoutSupported = false;
// We do NOT really support the PICK intent. Handle it as
// the GET_CONTENT. However, we need to translate the type
// in the intent here.
Log.w(TAG, "action PICK is not supported");
String type = Utils.ensureNotNull(intent.getType());
if (type.startsWith("vnd.android.cursor.dir/")) {
if (type.endsWith("/image")) intent.setType("image/*");
if (type.endsWith("/video")) intent.setType("video/*");
}
startGetContent(intent);
} else if (Intent.ACTION_VIEW.equalsIgnoreCase(action)
|| ACTION_REVIEW.equalsIgnoreCase(action)) {
mDrawerLayoutSupported = false;
Uri uri = intent.getData();
if (uri != null) {
int flag = intent.getFlags();
int match = sURIMatcher.match(uri);
if ((match == ALL_DOWNLOADS || match == ALL_DOWNLOADS_ID) &&
(flag & Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
if (checkCallingOrSelfPermission(
PERMISSION_ACCESS_ALL) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "no permission to view: " + uri);
return;
}
}
} else {
Log.w(TAG, "uri get from intent is null");
}
startViewAction(intent);
}else if(ACTION_VIEW_DESIGNATED_LIST.equalsIgnoreCase(action)) {
/**
* description 增加预览指定列表分支
*/
startTimelinePage();
}else if(ACTION_VIEW_DESIGNATED_ITEM.equalsIgnoreCase(action)){
/**
* description 增加预览指定Item分支
*/
startSinglePhotoPage();
} else {
// 这里为默认逻辑,即接收到的action为 android.intent.action.MAIN
// 表示为用户主动点击启动,非第三方跳转调用本程序
// 屏蔽DrawerLayout
// mDrawerLayoutSupported = true;
mDrawerLayoutSupported = false;
// 屏蔽进入页面时加载时间轴
// tartTimelinePage();
// 增加方法入口
initCustomerView();
// 屏蔽Title
//mToolbar.setTitle(R.string.albums_title);
mToolbar.setTitle(null);
}
// 是否显示侧边菜单
toggleNavDrawer(mDrawerLayoutSupported);
}
这里跳转的对应关系可以在AndroidMefest.xml
<activity android:name="com.android.gallery3d.app.GalleryActivity"
android:theme="@style/AppTheme"
android:configChanges="keyboardHidden|orientation|screenSize|locale|fontScale|layoutDirection|screenLayout|smallestScreenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" /> // 桌面启动
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" /> // 入口程序属性
<category android:name="android.intent.category.APP_GALLERY" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" /> // 第三方内容跳转
<category android:name="android.intent.category.OPENABLE" />
<data android:mimeType="vnd.android.cursor.dir/image" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.OPENABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" /> // 图片
<data android:mimeType="video/*" /> // 视频
</intent-filter>
<!-- We do NOT support the PICK intent, we add these intent-filter for
backward compatibility. Handle it as GET_CONTENT. -->
<intent-filter>
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
<data android:mimeType="video/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/image" />
<data android:mimeType="vnd.android.cursor.dir/video" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/image" />
<data android:mimeType="vnd.android.cursor.dir/video" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="com.android.camera.action.REVIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="content" />
<data android:scheme="file" />
<data android:mimeType="image/*" />
<data android:mimeType="application/vnd.google.panorama360+jpg" />
</intent-filter>
<intent-filter>
<action android:name="com.android.camera.action.REVIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="content" />
<data android:scheme="file" />
<data android:mimeType="video/mpeg4" />
<data android:mimeType="video/mp4" />
<data android:mimeType="video/3gp" />
<data android:mimeType="video/3gpp" />
<data android:mimeType="video/3gpp2" />
<data android:mimeType="application/sdp" />
</intent-filter>
<!-- 新增IntentFilter给文件浏览器提供多图预览列表接口 -->
<!--<intent-filter>
<action android:name="android.intent.action.VIEW_DESIGNATED_LIST"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>-->
<!-- 新增IntentFilter给文件浏览器提供多图预览详情接口(需要携带预览列表 用于左右滑动) -->
<intent-filter>
<action android:name="android.intent.action.VIEW_DESIGNATED_ITEM"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
这里我们进行了自定义,将界面修改为fragment
private List<BaseFragment> fragmentList;
/**
* 初始化视图 Activity拆分为多个Fragment
* Drawer视图结构改为Tab视图结构
*/
private void initCustomerView() {
...
}
package com.android.gallery3d.app;
/**
* 相册分页显示Fragment(时间轴Fragment)
*/
public class TimeLinePageFragment extends BaseFragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.i(TAG, "onViewCreated");
// 设置surfaceview控件
setGLRoot(getView().findViewById(R.id.gl_root_view));
...
}
private void startTimelinePage() {
String newBPath = getDataManager().getTopSetPath(DataManager.INCLUDE_ALL);
String newPath = FilterUtils.switchClusterPath(newBPath, FilterUtils.CLUSTER_BY_TIME);
Bundle data = new Bundle();
data.putString(TimeLinePage.KEY_MEDIA_PATH, newPath);
if (getStateManager().getStateCount() == 0)
getStateManager().startState(TimeLinePage.class, data);
else {
ActivityState state = getStateManager().getTopState();
String oldClass = state.getClass().getSimpleName();
String newClass = TimeLinePage.class.getSimpleName();
// if (!oldClass.equals(newClass)) {
getStateManager().switchState(getStateManager().getTopState(),
TimeLinePage.class, data);
// }
}
}
}
上述中使用了切换切换使用了getStateManager.startState或switchState接口, 即ActivityState页面的切换都是由StateManager来管理
public void startDefaultPage() {
......
Bundle data = new Bundle();
data.putString(AlbumSetPage.KEY_MEDIA_PATH,
getDataManager().getTopSetPath(DataManager.INCLUDE_ALL));
// 显示所有相册缩略图的页面
getStateManager().startState(AlbumSetPage.class, data);
......
}
Ps:进入Gallery显示的是AlbumSetPage;
AlbumSetPage是由多个相册组成的;
然后点击某一相册显示的AlbumPage,AlbumPage由该相册的所有缩略图组成;
再点击其中某一张图片显示的就是PhotoPage。
基于上述,接下来界面切换我们主要进行 StateManager、DataManager、ActivityState 的关系研究
StateManager通过栈(stack)来管理要显示的界面,每个界面都是一个ActivityState类,切换界面做的就是stack的入栈和出栈操作
package com.android.gallery3d.app;
abstract public class ActivityState {
// 1 实例化,在StateManager.startState() 被调用
protected ActivityState() {
}
// 2.初始化参数,在StateManager.startState() 被调用
void initialize(AbstractGalleryActivity activity, Bundle data) {
mActivity = activity;
mData = data;
}
// 3.界面显示,在StateManager.startState() 被调用
protected void onCreate(Bundle data, Bundle storedState) {
mBackgroundColor = GalleryUtils.intColorToFloatARGBArray(
mActivity.getResources().getColor(getBackgroundColorId()));
}
// 4.界面显示,在StateManager.startState() 被调用
// a subclass of ActivityState should override the method to resume itself
protected void onResume() {
if(null != mFragment && mFragment.isAdded()){
RawTexture fade = mFragment.getTransitionStore().get(
PreparePageFadeoutTexture.KEY_FADE_TEXTURE);
mNextTransition = mFragment.getTransitionStore().get(
KEY_TRANSITION_IN, StateTransitionAnimation.Transition.None);
if (mNextTransition != StateTransitionAnimation.Transition.None) {
mIntroAnimation = new StateTransitionAnimation(mNextTransition, fade);
mNextTransition = StateTransitionAnimation.Transition.None;
}
} else {
RawTexture fade = mActivity.getTransitionStore().get(
PreparePageFadeoutTexture.KEY_FADE_TEXTURE);
mNextTransition = mActivity.getTransitionStore().get(
KEY_TRANSITION_IN, StateTransitionAnimation.Transition.None);
if (mNextTransition != StateTransitionAnimation.Transition.None) {
mIntroAnimation = new StateTransitionAnimation(mNextTransition, fade);
mNextTransition = StateTransitionAnimation.Transition.None;
}
}
}
}
上述中继承 ActivityState 需要重写onCreate() 和 onResume() 周期,例如 AlbumSetPage.java:显示所有相册缩略图的页面
package com.android.gallery3d.app;
public class AlbumSetPage extends ActivityState implements OnClickListener,
SelectionManager.SelectionListener, GalleryActionBar.ClusterRunner,
EyePosition.EyePositionListener, MediaSet.SyncListener, ButtonControlsHandler.Delegate {
@Override
public void onCreate(Bundle data, Bundle restoreState) {
super.onCreate(data, restoreState);
// 初始化界面
initializeViews();
// 初始化数据
initializeData(data);
...
}
private void initializeViews() {
// mActivity -> mFragment
if (null != mFragment && mFragment.isAdded()) {
mSelectionManager = new SelectionManager(mFragment, true);
mSelectionManager.setSelectionListener(this);
mConfig = Config.AlbumSetPage.get(mActivity);
mSlotView = new SlotView(mFragment, mConfig.slotViewSpec);
// mActivity -> mFragment
mAlbumSetView = new AlbumSetSlotRenderer(
mFragment, mSelectionManager, mSlotView,
mConfig.labelSpec,
mConfig.slotViewSpec,
mConfig.placeholderColor);
mSlotView.setSlotRenderer(mAlbumSetView);
mSlotView.setListener(new SlotView.SimpleListener() {
@Override
public void onDown(int index) {
AlbumSetPage.this.onDown(index);
}
@Override
public void onUp(boolean followedByLongPress) {
AlbumSetPage.this.onUp(followedByLongPress);
}
@Override
public void onSingleTapUp(int slotIndex) {
AlbumSetPage.this.onSingleTapUp(slotIndex);
}
@Override
public void onLongTap(int slotIndex) {
AlbumSetPage.this.onLongTap(slotIndex);
}
});
mActionModeHandler = new ActionModeHandler(mFragment, mSelectionManager);
mActionModeHandler.setActionModeListener(new ActionModeListener() {
@Override
public boolean onActionItemClicked(MenuItem item) {
return onItemSelected(item);
}
});
mRootPane.addComponent(mSlotView);
} else {
mSelectionManager = new SelectionManager(mActivity, true);
mSelectionManager.setSelectionListener(this);
//mConfig是用来设置SlotView的参数,而SlotView就是一个相册
mConfig = Config.AlbumSetPage.get(mActivity);
mSlotView = new SlotView(mActivity, mConfig.slotViewSpec);
//mAlbumSetView是mSlotView的渲染器,控制mSlotView的显示
mAlbumSetView = new AlbumSetSlotRenderer(
mActivity, mSelectionManager, mSlotView, mConfig.labelSpec,
mConfig.slotViewSpec,
mConfig.placeholderColor);
//将mAlbumSetView设置给mSlotView
mSlotView.setSlotRenderer(mAlbumSetView);
//监听SlotView事件,根据手势操作做出相应的响应,这个监听事件的原理后面再分析
mSlotView.setListener(new SlotView.SimpleListener() {
@Override
public void onDown(int index) {
AlbumSetPage.this.onDown(index);
}
@Override
public void onUp(boolean followedByLongPress) {
AlbumSetPage.this.onUp(followedByLongPress);
}
@Override
public void onSingleTapUp(int slotIndex) {
AlbumSetPage.this.onSingleTapUp(slotIndex);
}
@Override
public void onLongTap(int slotIndex) {
AlbumSetPage.this.onLongTap(slotIndex);
}
});
mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager);
mActionModeHandler.setActionModeListener(new ActionModeListener() {
@Override
public boolean onActionItemClicked(MenuItem item) {
return onItemSelected(item);
}
});
//把这个SlotView作为一个子控件传给GLView,mRootPane是GLView类
mRootPane.addComponent(mSlotView);
}
}
private void initializeData(Bundle data) {
//获取data传入的value
String mediaPath = data.getString(AlbumSetPage.KEY_MEDIA_PATH);
//获取MediaSet,前面讲了每个ActivityState页面都需要一个数据源MediaSource来获取显示数据,而MediaSource是由MediaObject组成,MediaObject相当于MediaSource的单位,MediaSet就是一个MediaObject的子类,管理一组媒体数据
mMediaSet = getDataManager().getMediaSet(mediaPath);
//mSelectionManager用于管理选择事件
mSelectionManager.setSourceMediaSet(mMediaSet);
//mAlbumSetDataAdapter类似于桥梁来连接页面和数据源
// mActivity -> mFragment
if (null != mFragment && mFragment.isAdded()) {
mAlbumSetDataAdapter = new AlbumSetDataLoader(
mFragment, mMediaSet, DATA_CACHE_SIZE);
} else {
mAlbumSetDataAdapter = new AlbumSetDataLoader(
mActivity, mMediaSet, DATA_CACHE_SIZE);
}
mSelectionManager.setAlbumSetDataLoader(mAlbumSetDataAdapter);
//设置数据加载的监听接口
mAlbumSetDataAdapter.setLoadingListener(new MyLoadingListener());
mAlbumSetView.setModel(mAlbumSetDataAdapter);
}
package com.android.gallery3d.app;
// DataManager manages all media sets and media items in the system.
//
// Each MediaSet and MediaItem has a unique 64 bits id. The most significant
// 32 bits represents its parent, and the least significant 32 bits represents
// the self id. For MediaSet the self id is is globally unique, but for
// MediaItem it's unique only relative to its parent.
//
// To make sure the id is the same when the MediaSet is re-created, a child key
// is provided to obtainSetId() to make sure the same self id will be used as
// when the parent and key are the same. A sequence of child keys is called a
// path. And it's used to identify a specific media set even if the process is
// killed and re-created, so child keys should be stable identifiers.
public class DataManager implements StitchingChangeListener {
public static DataManager from(Context context) {
GalleryApp app = (GalleryApp) context.getApplicationContext();
return app.getDataManager();
}
}
上述查看 GalleryApp 为一个接口
package com.android.gallery3d.app;
public interface GalleryApp {
public DataManager getDataManager();
...
}
查看接口实现位置,即为单例模式实例化位置
package com.android.gallery3d.app;
public class GalleryAppImpl extends Application implements GalleryApp {
@Override
public synchronized DataManager getDataManager() {
if (mDataManager == null) {
mDataManager = new DataManager(this);
mDataManager.initializeSourceMap();
}
return mDataManager;
}
}
package com.android.gallery3d.data;
public class DataManager implements StitchingChangeListener {
public DataManager(GalleryApp application) {
mApplication = application;
mDefaultMainHandler = new Handler(application.getMainLooper());
}
package com.android.gallery3d.data;
public class DataManager implements StitchingChangeListener {
public synchronized void initializeSourceMap() {
if (!mSourceMap.isEmpty()) return;
// the order matters, the UriSource must come last
// 所有数据源
addSource(new LocalSource(mApplication));
addSource(new PicasaSource(mApplication));
addSource(new ComboSource(mApplication));
addSource(new ClusterSource(mApplication));
addSource(new FilterSource(mApplication));
addSource(new SecureSource(mApplication));
addSource(new UriSource(mApplication));
addSource(new SnailSource(mApplication));
if (mActiveCount > 0) {
for (MediaSource source : mSourceMap.values()) {
source.resume();
}
}
}
例如起码的参数实例
private static final String TOP_IMAGE_SET_PATH = "/combo/{/local/image,/picasa/image}";
private static final String TOP_VIDEO_SET_PATH =
"/combo/{/local/video,/picasa/video}";
// This is the path for the media set seen by the user at top level.
private static final String TOP_SET_PATH = "/combo/{/local/all,/picasa/all}";
private static final String TOP_LOCAL_IMAGE_SET_PATH = "/local/image";
private static final String TOP_LOCAL_VIDEO_SET_PATH = "/local/video";
private static final String TOP_LOCAL_SET_PATH = "/local/all";
public String getTopSetPath(int typeBits) {
switch (typeBits) {
case INCLUDE_IMAGE:
return TOP_IMAGE_SET_PATH;
case INCLUDE_VIDEO:
return TOP_VIDEO_SET_PATH;
case INCLUDE_ALL:
return TOP_SET_PATH;
case INCLUDE_LOCAL_IMAGE_ONLY:
return TOP_LOCAL_IMAGE_SET_PATH;
case INCLUDE_LOCAL_VIDEO_ONLY:
return TOP_LOCAL_VIDEO_SET_PATH;
case INCLUDE_LOCAL_ALL_ONLY:
return TOP_LOCAL_SET_PATH;
default:
throw new IllegalArgumentException();
}
}
上述的 DataManager 数据作为 startState 参数传递
package com.android.gallery3d.app;
public class StateManager {
}
package com.android.gallery3d.app;
public class StateManager {
private static class StateEntry {
public Bundle data;
public ActivityState activityState;
public StateEntry(Bundle data, ActivityState state) {
this.data = data;
this.activityState = state;
}
}
}
// 参数:ActivityState 界面 与 DataManager 相关数据
public void startState(Class<? extends ActivityState> klass,
Bundle data) {
Log.v(TAG, "startState " + klass);
ActivityState state = null;
try {
// newInstance()和 new() 都是用来创建新的对象
// newInstance: 是弱类型,效率低,只能调用无参构造
// new() : 强类型,高效率,能调用任何public构造器
state = klass.newInstance();
} catch (Exception e) {
throw new AssertionError(e);
}
// 栈不为空
if (!mStack.isEmpty()) {
// 获取栈顶数据
ActivityState top = getTopState();
// 暂停栈顶
top.transitionOnNextPause(top.getClass(), klass,
StateTransitionAnimation.Transition.Incoming);
if (mIsResumed) {
// 暂停栈顶
top.onPause();
}
}
UsageStatistics.onContentViewChanged(
UsageStatistics.COMPONENT_GALLERY,
klass.getSimpleName());
// 替换参数 mActivity -> mFragment
// 根据 ActivityState 和 DataManager 完成初始化
if(null != mFragment && mFragment.isAdded()){
state.initialize(mFragment, data);
}else {
state.initialize(mActivity, data);
}
// push 方法,入栈
mStack.push(new StateEntry(data, state));
// 界面显示
state.onCreate(data, null);
if (mIsResumed) state.resume();
}