读源码,从AndroidManifest.xml文件入手,android版本8.0
<activity android:name="Settings"
android:taskAffinity="com.android.settings.root">
activity>
<activity-alias android:name="Settings"
android:taskAffinity="com.android.settings.root">
activity-alias>
<activity android:name=".SubSettings"
android:taskAffinity="com.android.settings"
android:parentActivityName="Settings"/>
...
1.主启动页面为Settings
2.通过taskAffinity将activity分为几个部分(Task)
com.android.settings.root
com.android.settings
与application一致的" "
com.android.settings.storage_wizard
3.通过:parentActivityName指定为某个Activity的逻辑子类
4.meta-data:
元数据,可以为application、activity、recevier等提供附加数据项
android:name:唯一名称
android:resource:对资源的引用,该资源ID可以通过该metaData.getInt()获得
<meta-data android:name="android.app.shortcuts" android.resource="@xml/shortcuts" />
android:value:分配给该标签的值
获取元数据:
//SettingsActivity.java中的getMetaData()
ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),PackageManager.GET_META_DATA);
mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
由于只看了xml文件,并不确定是否有使用其他属性配合实现效果(Intent.FLAG_ACTIVITY_NEW_TASK或者allowTaskReparenting)
public class Settings extends SettingsActivity{
/*静态内部类,且全部继承自SettingsActivity*/
}
1.没有实现内容,但继承自SettingsActivity,且SettingsActivity有实现内容
2.在点击其中一部分静态内部类时会跳转至其他java文件,说明会在其他具体的方法、广播以及activity时引入
protected void onCreate(Bundle savedState){
...
final FeatureFactory factory = FeatureFactory.getFactory(this);
mDashboardFeatureProvider = factory.getDashboardFeatureProvider(this);
//加载元数据,初始化字符串mFragmentClass
getMetaData();
...
final ComponentName cn = intent.getComponent();
final String className = cn.getClassName();
//当前intent的类名与settings是否一致(意味着启动settings主页面)
mIsShowingDashboard = className.equals(Settings.class.getName());
//通过mIsShowingDashboard来加载主页面的布局
setContentView(mIsShowingDashboard?R.layout.settings_main_dashboard:R.layout.settings_main_prefs);
...
//如果之前已经启动过,有保存的状态和一些值,那么用它来进行初始化,而不是新建
if(savedState != null){
setTitleFromIntent(intent);
ArrayList<DashboardCategory> categories = savedState.getParcelableArrayList(SAVE_KEY_CATEGORIES);
if(categories != null){
mCategories.clear();
mCategories.addAll(categories);
setTitleFromBackStack();
}else{//否则就调用这个函数进行第一次页面的加载
launchSettingFragment(initialFragmentName,isSubSettings,intent);
}
}
}
1.进入一个Activity时,习惯性的按照生命周期进行查看,所以跳转到onCreate
2.之前没有细读,所以一直存在疑惑:为什么首次进入是执行launchSettingFragment()这个方法?
在onCreate()中对之前是否进行状态保存的值(savedState)进行了判断,不为空就意味着不是首次启动,可以拿之前保存的值来初始化,而我们第一次进入的时候是没有值的,所以才会执行launchSettingFragment()
3.R.layout.settings_main_dashboard是主页面
void launchSettingFragment(String initialFragmentName,boolean isSubSettings,Intent intent){
if(!mIsShowDashboard && initialFragmentName != null){
setTitleFromIntent(intent);
Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
switchToFragment(initialFragmentName,initialArguments,true,false,mInitialTitleResId,mInitialTitle,false);
}else{
mInitialTitleResId = R.string.dashboard_titlel
switchToFragment(DashboardSummary.class.getName(),null,false,false,mInitialTitleResId,mInitialTitle,false);
}
}
1.mIsShowDashboard为true,所以if不会执行,直接到else后面的语句
2.R.string.dashboard_title=mInitialTitleResId=>“Settings”
private Fragment switchToFragment(String fragmentName,Bundle args,boolean validate,boolean addToBackStack,int titleResId,CharSequence title,boolean withTransition){
...
//实例化DashboardSummary类,替换main_content
Fragment f = Fragment.instantiate(this,fragmentName,args);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.main_content, f);
...
if(titleResId > 0){
transcation.setBreadCrumbTitle(titleResId);
}else if(title != null){
transcation.setBreadCrumbTitle(title);
}
transaction.commitAllowingStateLoss();
getFragmentManager().executePendingTransactions();
return f;
}
1.在Fragment.instantiate()中,完成DashboardSummary类的实例化,在这里进行数据的加载,并且替换掉main_content,呈现出进入的页面效果
2.设置标题的时候,会先对titleResId进行判断,如果没有再去判断title,由于之前找到title的时候只有定义并未赋值,推测应该为null,如果是进行初始化而非创建,title不会为null,但也不会调用launchSettingFragment,所以只会判断titleResId,且以它的值作为标题(搜索栏的hint提示)
public void onAttach(Context context){
final SuggestionFeatureProvider suggestionFeatureProvider = FeatureFactory
.getFactory(context)
.getSuggestionFeatureProvider(context);
if(suggestionFeatureProvider.isSuggestionEnable(context)){//true
//初始化mSuggestionControllerMixin,
mSuggestionControllerMixin = new SuggestionControllerMixin(context, this /* host */,
getLifecycle(), suggestionFeatureProvider
.getSuggestionServiceComponent());
}
}
1.实际上是一个Fragment,继承自InstrumentedFragment,按照生命周期进行查看
2.suggestionFeatureProvider.isSuggestionEnable(context)实现类是SuggestionFeatureProviderImpl.java中,其最后返回的结果是以设备是否为低内存设备的结果进行取非
public boolean isSuggestionEnabled(Context context) {
final ActivityManager am =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
return !am.isLowRamDevice();
}
3.在这里对mSuggestionControllerMixin进行了初始化,实例化一个SuggestionController对象,并添加了监听事件,在实例化SuggestionController对象时,新建了ServiceConnection对象管理服务连接与失去连接事件
public void onCreate(Bundle savedInstanceState){
mDashboardFeatureProvider = FeatureFactory.getFactory(activity).getDashboardFeatureProvider(activity);
//开启一个后台工作线程
mSummaryLoader = new SummaryLoader(activity,CategoryKey.CATEGORY_HOMEPAGE);
//开启一个异步任务
mConditionManager = ConditionManager.get(activity, false);
getLifecycle().addObserver(mConditionManager);
...
}
1.CategoryKey.CATEGORY_HOMEPAGE定义在CategoryKey.java文件中(frameworks/base/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java)
//Activities in this category shows up in Settings homepage
//显示在设置主页的活动,在AndroidManifest.xml中meta-data设置的一些活动
public static final String CATEGORY_HOMEPAGE = "com.android.settings.category.ia.homepage";
3.mConditionManager最终会实例化ConditionLoader类开启异步任务,去加载模块
//位于ConditionManager.java中,内部类
private class ConditionLoader extends AsyncTask<Void,Void,ArrayList<Condition>>{
@Override
protected ArrayList<Condition> doInBackground(Void... params) {
Log.d(TAG, "loading conditions from xml");
ArrayList<Condition> conditions = new ArrayList<>();
mXmlFile = new File(mContext.getFilesDir(), FILE_NAME);
if (mXmlFile.exists()) {//如果xml文件存在,则读取
readFromXml(mXmlFile, conditions);
}
addMissingConditions(conditions);//添加不在xml文件中的类
return conditions;
}
@Override
protected void onPostExecute(ArrayList<Condition> conditions) {
Log.d(TAG, "conditions loaded from xml, refreshing conditions");
mConditions.clear();
mConditions.addAll(conditions);
refreshAll();//刷新
}
}
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle bundle){
final View root = inflater.inflate(R.layout.dashboard, container, false);
mDashboard = root.findViewById(R.id.dashboard_container);
...
/*对mDashboard进行一些初始化,如绑定布局、添加监听事件等*/
//设置适配器,添加数据
mAdapter = new DashboardAdapter(getContext(),bundle,mConditionManager.getConditions(),mSuggestionControllerMixin,getLifecycle());
mDashboard.setAdapter(mAdapter);
...
rebuildUI();
}
1.root加载的布局是拓展的RecycleView,并且布局文件只有它一个View,没有设置任何布局,是在java中动态添加的线性布局
2.所有的数据加载都是在DashboardAdapter中
public DashboardAdapter(Context context,Bundle savedInstanceState,
List<Condition> conditions,SuggestionControllerMixin suggestionControllerMixin,
Lifecycle lifecycle){
...
mSuggestionAdapter = new SuggestionAdapter(mContext,suggestionControllerMixin,
savedInstanceState,this,lifecycle);
...
mDashboardData = new DashboardData.Builder()
.setConditions(conditions)
.setSuggestions(mSuggestionAdapter.getSuggestions())
.setCategory(catrgory)
.setConditionExpanded(conditionExpanded)
.build();
}
1.通过new SuggestionAdapter,和Lifecycle绑定,并初始化mSuggestionShowLogged=new ArrayList<>()
2.mDashboardData为数据来源,通过DashboardData.Builder设置值,调用builf方法来创建
public DashboardData build(){
return new DashboardData(this);
}
private DashboardData(Builder builder){
...
buildItemsData();
}
private void buildItemsData(){
...
//主页面搜索框下的条目呈现
if(mCategory != null){
final List<Tile> tiles = mCategory.getTiles();
for(int i = 0; i < tiles.size(); i++){
final Tile tile = tiles.get(i);
addToItemList(tile,R.layout.dashboard_tile,Ojects.hash(tile.title),true);
}
}
}
1.使用addToItemList对suggestions和conditions添加到mItem中
数据加载,页面呈现流程走完,分析跳转子页面,以及子页面的逻辑