以前装应用的时候有些应用会在桌面上生成两个图标,这两个图标有些是同一个Activity的入口,有些是另外一个Activity的入口,这样的效果是怎么实现的呢?在看Android原生DeskClock程序的时候看到了这个功能的实现.使用的是activity-alias:
1).语法格式
<activity-alias android:enabled=["true" | "false"] android:exported=["true" | "false"] android:icon="drawable resource" android:label="string resource" android:name="string" android:permission="string" android:targetActivity="string" > . . . </activity-alias>
从下面的配置可以看出这是同一个activity(DeskClock)的两个入口,并且这两个入口的名字图标都一样,这样做有什么意义呢?可以看到activity-alias中标记了一个名为android.intent.category.DESK_DOCK的category,这个是在android设备插上桌面Dock底 座的时候才会触发alias入口.
<activity android:name="DeskClock" android:label="@string/app_label" android:theme="@style/DeskClock" android:icon="@mipmap/ic_launcher_alarmclock" android:launchMode="singleTask" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity-alias android:name="DockClock" android:targetActivity="DeskClock" android:label="@string/app_label" android:theme="@style/DeskClock" android:icon="@mipmap/ic_launcher_alarmclock" android:launchMode="singleTask" android:enabled="@bool/config_dockAppEnabled" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DESK_DOCK" /> </intent-filter> </activity-alias>
activity-alias通过指定targetActivity来决定入口相连接的activity,给该程序更改一个不同的label(ClockAlias)和icon(菊花)并且替换掉Dock底座的category,如下部代码配置所示.
<activity-alias android:name="DockClock" android:targetActivity="DeskClock" android:label="@string/app_second_label" android:theme="@style/DeskClock" android:icon="@mipmap/entrance" android:launchMode="singleTask" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity-alias>
这样修改完成配置之后就可以实现在android设备上双入口图标了,点击两个图标都可以进入到DeskClock的程序里面,具体 效果如下图所示
if (mTabsAdapter == null) { mViewPager = new ViewPager(this); mViewPager.setId(R.id.desk_clock_pager); // Keep all four tabs to minimize jank. mViewPager.setOffscreenPageLimit(3); mTabsAdapter = new TabsAdapter(this, mViewPager); createTabs(mSelectedTab); } setContentView(mViewPager); mActionBar.setSelectedNavigationItem(mSelectedTab);主页中主要的页面切换等大部分逻辑都在自定义的FragmentPagerAdapter中,这里主要分析下适配器。TabsAdapter在构造的时候可以获取到DeskClock的context,actionbar,viewpager并绑定该适配器,绑定页面变化的监听.
public TabsAdapter(Activity activity, ViewPager pager) { super(activity.getFragmentManager()); mContext = activity; mMainActionBar = activity.getActionBar(); mPager = pager; mPager.setAdapter(this); mPager.setOnPageChangeListener(this); }
final class TabInfo { private final Class<?> clss; private final Bundle args; TabInfo(Class<?> _class, int position) { clss = _class; args = new Bundle(); args.putInt(KEY_TAB_POSITION, position); } public int getPosition() { return args.getInt(KEY_TAB_POSITION, 0); } }
public void addTab(ActionBar.Tab tab, Class<?> clss, int position) { TabInfo info = new TabInfo(clss, position); tab.setTag(info); tab.setTabListener(this); mTabs.add(info); mMainActionBar.addTab(tab); notifyDataSetChanged(); }
public void onTabSelected(Tab tab, FragmentTransaction ft) { TabInfo info = (TabInfo)tab.getTag(); int position = info.getPosition(); mPager.setCurrentItem(getRtlPosition(position)); }
public void onPageSelected(int position) { // Set the page before doing the menu so that onCreateOptionsMenu knows what page it is. mMainActionBar.setSelectedNavigationItem(getRtlPosition(position)); notifyPageChanged(position); // Only show the overflow menu for alarm and world clock. if (mMenu != null) { // Make sure the menu's been initialized. if (position == ALARM_TAB_INDEX || position == CLOCK_TAB_INDEX) { mMenu.setGroupVisible(R.id.menu_items, true); onCreateOptionsMenu(mMenu); } else { mMenu.setGroupVisible(R.id.menu_items, false); } } }
private boolean isRtl() { return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL; } private int getRtlPosition(int position) { if (isRtl()) { switch (position) { case TIMER_TAB_INDEX: return RTL_TIMER_TAB_INDEX; case CLOCK_TAB_INDEX: return RTL_CLOCK_TAB_INDEX; case STOPWATCH_TAB_INDEX: return RTL_STOPWATCH_TAB_INDEX; case ALARM_TAB_INDEX: return RTL_ALARM_TAB_INDEX; default: break; } } return position; }TabsAdapter在加载不同的fragment的时候也是同理的,通过positon取得TagInfo的数据,再根据Fragment的instantiate方法以ClassLoader的方式实例跟positon相对应的Fragment.
public Fragment getItem(int position) { TabInfo info = mTabs.get(getRtlPosition(position)); DeskClockFragment f = (DeskClockFragment) Fragment.instantiate( mContext, info.clss.getName(), info.args); return f; }
public void registerPageChangedListener(DeskClockFragment frag) { String tag = frag.getTag(); if (mFragmentTags.contains(tag)) { Log.wtf(LOG_TAG, "Trying to add an existing fragment " + tag); } else { mFragmentTags.add(frag.getTag()); } // Since registering a listener by the fragment is done sometimes after the page // was already changed, make sure the fragment gets the current page frag.onPageChanged(mMainActionBar.getSelectedNavigationIndex()); } public void unregisterPageChangedListener(DeskClockFragment frag) { mFragmentTags.remove(frag.getTag()); }
private void notifyPageChanged(int newPage) { for (String tag : mFragmentTags) { final FragmentManager fm = getFragmentManager(); DeskClockFragment f = (DeskClockFragment) fm.findFragmentByTag(tag); if (f != null) { f.onPageChanged(newPage); } } }
这一篇博客主要介绍了DeskClock程序中主UI部分的逻辑,主要分析了两点(多入口配置和ViewPager,ActionBar,适配器之间切换和数据绑定)现在四大功能部分还没有涉及,后续的系列就要开始介绍四大功能.
转载请注明出处:http://blog.csdn.net/l2show/article/details/46722999