Android source code-javasclock (2), androidjavasclock
I. Overview
I introduced the export of the program source code in DeskClock (1). Now I start to analyze the application source code. DeskClock mainly has four functions: alarm clock, clock, timing, and stopwatch, this blog mainly analyzes the entry of mongoclock and the logical structure of the main UI. These four functions will be serialized in the subsequent series.
Ii. Source Code Analysis
1. activity-alias multi-entry Configuration
In the past, some applications used to generate two icons on the desktop. Some of these two icons are the portals of the same Activity and others are the portals of another Activity, how can this effect be achieved? When viewing the Android native javasclock program, you can see the implementation of this function, using activity-alias:
1). Syntax format
<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>
2). Applications in dirty clock
From the following configuration, we can see that this is the two portals of the same activity (Clock), and the two portals have the same name icon. What is the significance of this operation? You can see that activity-alias marks a category named android. intent. category. category _dock. This triggers the alias portal only when the android device is plugged in to the Base Seat of the desktop Dock.
<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 determines the activity connected to the portal by specifying targetActivity, change a different label (ClockAlias) and icon (chrysanthemum) for the program, and replace the category of the Dock base, as shown in the lower code configuration.
<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>
After the configuration is modified, the dual portal icon on the android device can be implemented. You can click the two icons to enter the javasclock program. The specific effect is shown in.
2. the main structure of the home page consists of three parts: Action bar, ViewPager, and FragmentPagerAdapter, four Action bar tabs and abstract Fragment are used to switch between the four main functions of the worker clock by the custom FragmentPagerAdapter.
When the primary clock is created, an ActionBar is obtained first, and then the Views are initialized. note that the ViewPager sets the pre-loaded Fragment through the setOffscreenPageLimit method. Here there are four main fragment, and the lifecycle clock displays a fragment, and then pre-load the other three fragment to improve the smoothness of the UI display.
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);Most of the main page switching logic on the home page is in the Custom FragmentPagerAdapter. Here we mainly analyze the adapter. TabsAdapter can obtain the context, actionbar, and viewpager of DeskClock during construction and bind the adapter to the page change listener.
public TabsAdapter(Activity activity, ViewPager pager) { super(activity.getFragmentManager()); mContext = activity; mMainActionBar = activity.getActionBar(); mPager = pager; mPager.setAdapter(this); mPager.setOnPageChangeListener(this); }An internal TabInfo class is defined to mark attributes and features of each ItemView. TabInfo is constructed when the adapter item is filled, bind TabInfo to the corresponding ActionBar tab.
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(); }When the tab is selected, because the detailed information of fragment has been bound to the tab, you can directly obtain all information of TabInfo (mainly position) through the tab ), then the fragment can be converted based on the location information. but what is getRtlPosion? RTL is right to left. reading habits of most countries on Earth are LTR. However, RTL is also available in a few regions, and google must be compatible with these users, it provides RTL support. When the getRtlPosion method does not support RTL locally, first determine whether the RTL is set in the configuration file, if it is set, you can use switch case to adjust the position of the page item to provide RTL support. Although this technology is generally not used in China, you can also briefly understand it. when the page changes, you can directly notify the ActionBar through position to synchronize the changes.
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 is also the same when loading different fragment. The data of TagInfo is obtained through positon, and then the Fragment corresponding to positon is obtained by ClassLoader according to the instantiate method of 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; }There is also a page change listener registration and logout in TabsAdapter. When there is a page change, TabsAdapter will notify this change to the Fragment of the registration listener, in this program, there are two functions: Fragment (timer and stopwatch), which need to perform different business logic processing based on the page changing status, these two functions will be analyzed in detail later.
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); } } }Iii. Summary
This blog mainly introduces the logic of the main UI in the javasclock program. It mainly analyzes two points (multi-entry configuration and switching between ViewPager, ActionBar, and adapter and data binding) the four functions are not involved yet. The four functions will be introduced in the subsequent series.
Reprinted please indicate the source: http://blog.csdn.net/l2show/article/details/46722999