搜索
查看
编辑修改
首页
UNITY
NODEJS
PYTHON
AI
GIT
PHP
GO
CEF3
JAVA
HTML
CSS
搜索
羊村懒王
这个屌丝很懒,什么也没留下!
关注作者
热门标签
jquery
HTML
CSS
PHP
ASP
PYTHON
GO
AI
C
C++
C#
PHOTOSHOP
UNITY
iOS
android
vue
xml
爬虫
SEO
LINUX
WINDOWS
JAVA
MFC
CEF3
CAD
NODEJS
GIT
Pyppeteer
article
热门文章
1
JetBrains 开发工具——免费教育许可申请流程_jetbrains教育
2
springboot集成kafka多线程消费端的实现_springboot kafka多线程消费
3
Python + Telnet基本使用_python telnet
4
安装能调用GPU的pytorch版本_python安装pytorch gpu版本
5
鸿蒙HarmonyOS4.0开发应用学习笔记_鸿蒙开发文档
6
【项目实战】python影片数据爬取与数据分析django电影数据网络爬虫与分析系统(源码+答疑+文档报告PPT)
7
WebSocket + Vue 简单聊天的实现_websocket+kafka+vue
8
Scrapy_redis+scrapyd搭建分布式架构爬取知乎用户信息_scrapy-redis分布式局域网多台电脑之间怎么建立关联的
9
基于STM32与FreeRTOS的四轴机械臂项目_基于stm32的机械臂项项目
10
编写相亲交友源码,应该掌握的简写小技巧_相亲源代码
当前位置:
article
> 正文
Android系统设置settings应用学习(三)--丰富的参考_android系统settings入口与其他app的关联
作者:羊村懒王 | 2024-04-20 15:56:07
赞
踩
android系统settings入口与其他app的关联
下面是Seeings应用的截图:
可以看出这是很典型的使用了Fragment后的界面,设置里面有WIFI、蓝牙、显示、存储、应用等众多功能。左边的每一项,对应着右边的一个设置界面,
Fragment有四个子类:
DialogFragment, ListFragment, PreferenceFragment, WebViewFragment。很明显,Settings用的是
PreferenceFragment。接着看一下Settings源码package结构:
主题部分的实现主要在com.android.settings下面,其他包主要是用于各自功能实现,所以重点说这个包下面的类。在AndroidManifest.xml文字中,看到程序入口是Settings类:
打开Settings类,是继承于PreferenceActivity:
其他的继承关系如下:
PreferenceActivity
-->
ListActivity --> Activity。
PreferenceActivity主要用于Settings,关于如何使用可以参考API(
http://developer.android.com/reference/android/preference/PreferenceActivity.html
)以及guide(
http://developer.android.com/guide/topics/ui/settings.html
)。和它相关联的类有header、fragment、preference。每一个header就是左边的一个选项条目,像蓝牙、应用等,选择之后右边就会显示对应的fragment(平板),然后fragment和preference联系在一起,组成了一个个设置项。一般在activity中设置布局,用的是setContentView(),在
PreferenceActivity中,是需要继承
onBuildHeaders(List)这个方法,
[html]
view plain
copy
@Override
ublic void onBuildHeaders(List
<
Header
>
target) {
loadHeadersFromResource(R.xml.preference_headers, target);
去生成选项表,点击选项表的一个条目,右边显示对应的Fragment,这就是很典型的header+fragment组合,所以如果想在Settings基础之上添加条目的话,在这个方法里面的xml文件中添加即可,然后对应上fragment。下面分析一下执行流程:
首先进入
onCreate(Bundle savedInstanceState)方法里面,代码如下:
[html]
view plain
copy
@Override
protected void onCreate(Bundle savedInstanceState) {
if (getIntent().getBooleanExtra(EXTRA_CLEAR_UI_OPTIONS, false)) {
getWindow().setUiOptions(0);
}
mAuthenticatorHelper
=
new
AuthenticatorHelper();
mAuthenticatorHelper.updateAuthDescriptions(this);
mAuthenticatorHelper.onAccountsUpdated(this, null);
mDevelopmentPreferences
=
getSharedPreferences
(DevelopmentSettings.PREF_FILE,
Context.MODE_PRIVATE);
getMetaData();
mInLocalHeaderSwitch
=
true
;
super.onCreate(savedInstanceState);
mInLocalHeaderSwitch
=
false
;
if (!onIsHidingHeaders() && onIsMultiPane()) {
highlightHeader(mTopLevelHeaderId);
// Force the title so that it doesn't get overridden by a direct launch of
// a specific settings screen.
setTitle(R.string.settings_label);
}
// Retrieve any saved state
if (savedInstanceState != null) {
mCurrentHeader
=
savedInstanceState
.getParcelable(SAVE_KEY_CURRENT_HEADER);
mParentHeader
=
savedInstanceState
.getParcelable(SAVE_KEY_PARENT_HEADER);
}
// If the current header was saved, switch to it
if (savedInstanceState != null && mCurrentHeader != null) {
//switchToHeaderLocal(mCurrentHeader);
showBreadCrumbs(mCurrentHeader.title, null);
}
if (mParentHeader != null) {
setParentTitle(mParentHeader.title, null, new OnClickListener() {
public void onClick(View v) {
switchToParent(mParentHeader.fragment);
}
});
}
// Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
if (onIsMultiPane()) {
getActionBar().setDisplayHomeAsUpEnabled(false);
getActionBar().setHomeButtonEnabled(false);
}
}
第一个if用于设置window ui的对修改来说不用考虑了,意义不大,
[html]
view plain
copy
mAuthenticatorHelper
=
new
AuthenticatorHelper();
mAuthenticatorHelper.updateAuthDescriptions(this);
mAuthenticatorHelper.onAccountsUpdated(this, null);
这个段代码用于认证以及更新账户信息,接着往下看:
[html]
view plain
copy
mDevelopmentPreferences
=
getSharedPreferences
(DevelopmentSettings.PREF_FILE,Context.MODE_PRIVATE);
用于之后保存数据,然后是getMetaData();这个方法,代码如下:
[html]
view plain
copy
private void getMetaData() {
try {
ActivityInfo
ai
=
getPackageManager
().getActivityInfo(getComponentName(),
PackageManager.GET_META_DATA);
if (
ai
== null ||
ai.metaData
== null) return;
mTopLevelHeaderId
=
ai
.metaData.getInt(META_DATA_KEY_HEADER_ID);
mFragmentClass
=
ai
.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
// Check if it has a parent specified and create a Header object
final int
parentHeaderTitleRes
=
ai
.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
String
parentFragmentClass
=
ai
.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
if (parentFragmentClass != null) {
mParentHeader
=
new
Header();
mParentHeader.fragment
=
parentFragmentClass
;
if (parentHeaderTitleRes != 0) {
mParentHeader.title
=
getResources
().getString(parentHeaderTitleRes);
}
}
} catch (NameNotFoundException nnfe) {
// No recovery
}
}
这个方法用于设置mParentHeader的Fragment以及title。下面具体举两个例子,关于如何修改Settings。
一、添加headers
header即是左边的菜单,如下图左侧。它的布局文件在res下的xml文件夹中,名字是settings_headers.xml。打开如下:
[html]
view plain
copy
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<!--
Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--
>
<
preference-headers
xmlns:android
=
"http://schemas.android.com/apk/res/android"
>
<!-- WIRELESS and NETWORKS -->
<
header
android:id
=
"@+id/wireless_section"
android:title
=
"@string/header_category_wireless_networks"
/>
<!-- Wifi -->
<
header
android:id
=
"@+id/wifi_settings"
android:fragment
=
"com.android.settings.wifi.WifiSettings"
android:icon
=
"@drawable/ic_settings_wireless"
android:title
=
"@string/wifi_settings_title"
/>
<!-- Bluetooth -->
<
header
android:id
=
"@+id/bluetooth_settings"
android:fragment
=
"com.android.settings.bluetooth.BluetoothSettings"
android:icon
=
"@drawable/ic_settings_bluetooth2"
android:title
=
"@string/bluetooth_settings_title"
/>
<!-- Data Usage -->
<
header
android:id
=
"@+id/data_usage_settings"
android:fragment
=
"com.android.settings.DataUsageSummary"
android:icon
=
"@drawable/ic_settings_data_usage"
android:title
=
"@string/data_usage_summary_title"
/>
<!-- Operator hook -->
<
header
android:id
=
"@+id/operator_settings"
android:fragment
=
"com.android.settings.WirelessSettings"
>
<
intent
android:action
=
"com.android.settings.OPERATOR_APPLICATION_SETTING"
/>
</
header
>
<!-- Other wireless and network controls -->
<
header
android:id
=
"@+id/wireless_settings"
android:breadCrumbTitle
=
"@string/wireless_networks_settings_title"
android:fragment
=
"com.android.settings.WirelessSettings"
android:icon
=
"@drawable/empty_icon"
android:title
=
"@string/radio_controls_title"
/>
<!-- DEVICE -->
<
header
android:id
=
"@+id/device_section"
android:title
=
"@string/header_category_device"
/>
<!-- Sound -->
<
header
android:id
=
"@+id/sound_settings"
android:fragment
=
"com.android.settings.SoundSettings"
android:icon
=
"@drawable/ic_settings_sound"
android:title
=
"@string/sound_settings"
/>
<!-- Display -->
<
header
android:id
=
"@+id/display_settings"
android:fragment
=
"com.android.settings.DisplaySettings"
android:icon
=
"@drawable/ic_settings_display"
android:title
=
"@string/display_settings"
/>
<!-- Storage -->
<
header
android:id
=
"@+id/storage_settings"
android:fragment
=
"com.android.settings.deviceinfo.Memory"
android:icon
=
"@drawable/ic_settings_storage"
android:title
=
"@string/storage_settings"
/>
<!-- Battery -->
<
header
android:id
=
"@+id/battery_settings"
android:fragment
=
"com.android.settings.fuelgauge.PowerUsageSummary"
android:icon
=
"@drawable/ic_settings_battery"
android:title
=
"@string/power_usage_summary_title"
/>
<!-- Application Settings -->
<
header
android:id
=
"@+id/application_settings"
android:fragment
=
"com.android.settings.applications.ManageApplications"
android:icon
=
"@drawable/ic_settings_applications"
android:title
=
"@string/applications_settings"
/>
<!-- Manage users -->
<
header
android:id
=
"@+id/user_settings"
android:fragment
=
"com.android.settings.users.UserSettings"
android:icon
=
"@drawable/ic_settings_multiuser"
android:title
=
"@string/user_settings_title"
/>
<!-- Manufacturer hook -->
<
header
android:id
=
"@+id/manufacturer_settings"
android:fragment
=
"com.android.settings.WirelessSettings"
>
<
intent
android:action
=
"com.android.settings.MANUFACTURER_APPLICATION_SETTING"
/>
</
header
>
<!-- PERSONAL -->
<
header
android:id
=
"@+id/personal_section"
android:title
=
"@string/header_category_personal"
/>
<!-- Location -->
<
header
android:id
=
"@+id/location_settings"
android:fragment
=
"com.android.settings.LocationSettings"
android:icon
=
"@drawable/ic_settings_location"
android:title
=
"@string/location_settings_title"
/>
<!-- Security -->
<
header
android:id
=
"@+id/security_settings"
android:fragment
=
"com.android.settings.SecuritySettings"
android:icon
=
"@drawable/ic_settings_security"
android:title
=
"@string/security_settings_title"
/>
<!-- Language -->
<
header
android:id
=
"@+id/language_settings"
android:fragment
=
"com.android.settings.inputmethod.InputMethodAndLanguageSettings"
android:icon
=
"@drawable/ic_settings_language"
android:title
=
"@string/language_settings"
/>
<!-- Backup and reset -->
<
header
android:id
=
"@+id/privacy_settings"
android:fragment
=
"com.android.settings.PrivacySettings"
android:icon
=
"@drawable/ic_settings_backup"
android:title
=
"@string/privacy_settings"
/>
<
header
android:id
=
"@+id/kytusers_settings"
android:fragment
=
"com.android.settings.KytUsersSettings"
android:icon
=
"@drawable/ic_settings_backup"
android:title
=
"考易通账户"
/>
<!-- ACCOUNTS section -->
<
header
android:id
=
"@+id/account_settings"
android:title
=
"@string/account_settings"
/>
<
header
android:id
=
"@+id/account_add"
android:icon
=
"@drawable/ic_menu_add"
android:title
=
"@string/add_account_label"
>
<
intent
android:action
=
"android.settings.ADD_ACCOUNT_SETTINGS"
/>
</
header
>
<!-- SYSTEM -->
<
header
android:id
=
"@+id/system_section"
android:title
=
"@string/header_category_system"
/>
<!-- Date & Time -->
<
header
android:id
=
"@+id/date_time_settings"
android:fragment
=
"com.android.settings.DateTimeSettings"
android:icon
=
"@drawable/ic_settings_date_time"
android:title
=
"@string/date_and_time_settings_title"
/>
<!-- Accessibility feedback -->
<
header
android:id
=
"@+id/accessibility_settings"
android:fragment
=
"com.android.settings.AccessibilitySettings"
android:icon
=
"@drawable/ic_settings_accessibility"
android:title
=
"@string/accessibility_settings"
/>
<!-- Development -->
<
header
android:id
=
"@+id/development_settings"
android:fragment
=
"com.android.settings.DevelopmentSettings"
android:icon
=
"@drawable/ic_settings_development"
android:title
=
"@string/development_settings_title"
/>
<!-- About Device -->
<
header
android:id
=
"@+id/about_settings"
android:fragment
=
"com.android.settings.DeviceInfoSettings"
android:icon
=
"@drawable/ic_settings_about"
android:title
=
"@string/about_settings"
/>
</
preference-headers
>
这些header分别对应着各自的菜单,如果想要添加还是删除就在这里修改即可。比如我们不想要蓝牙模块了,那就直接把下面这个header删除即可,添加的话类似。
[html]
view plain
copy
<!-- Bluetooth -->
<
header
android:id
=
"@+id/bluetooth_settings"
android:fragment
=
"com.android.settings.bluetooth.BluetoothSettings"
android:icon
=
"@drawable/ic_settings_bluetooth2"
android:title
=
"@string/bluetooth_settings_title"
/>
如果是做添加操作的话,不要忘了创建你的PreferenceFragment,然后在header里面添加id、fragment、icon、title等,如上面那样。
二、修改显示的应用
先看一下应用显示的部分:
看一下在源码中对应的包:
应用显示是一个滑动的界面,猜测是用ViewPager实现的,下面开始寻找实现。首先进入xml文件夹找到settings_headers,找到这一段代码:
[html]
view plain
copy
<!-- Application Settings -->
<
header
android:id
=
"@+id/application_settings"
android:fragment
=
"com.android.settings.applications.ManageApplications"
android:icon
=
"@drawable/ic_settings_applications"
android:title
=
"@string/applications_settings"
/>
然后打开对应的fragment,ManageApplications。发现这个它是继承于Fragment
既然继承于Fragment,那就直接定位到onCreate()方法,
[html]
view plain
copy
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
mApplicationsState
=
ApplicationsState
.getInstance(getActivity().getApplication());
Intent
intent
=
getActivity
().getIntent();
String
action
=
intent
.getAction();
int
defaultListType
=
LIST_TYPE_DOWNLOADED
;
String
className
=
getArguments
() != null
? getArguments().getString("classname") : null;
if (
className
== null) {
className
=
intent
.getComponent().getClassName();
}
if (className.equals(RunningServicesActivity.class.getName())
|| className.endsWith(".RunningServices")) {
defaultListType
=
LIST_TYPE_RUNNING
;
} else if (className.equals(StorageUseActivity.class.getName())
|| Intent.ACTION_MANAGE_PACKAGE_STORAGE.equals(action)
|| className.endsWith(".StorageUse")) {
mSortOrder
=
SORT_ORDER_SIZE
;
defaultListType
=
LIST_TYPE_ALL
;
} else if (Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS.equals(action)) {
// Select the all-apps list, with the default sorting
defaultListType
=
LIST_TYPE_ALL
;
}
if (savedInstanceState != null) {
mSortOrder
=
savedInstanceState
.getInt(EXTRA_SORT_ORDER, mSortOrder);
int
tmp
=
savedInstanceState
.getInt(EXTRA_DEFAULT_LIST_TYPE, -1);
if (tmp != -1)
defaultListType
=
tmp
;
mShowBackground
=
savedInstanceState
.getBoolean(EXTRA_SHOW_BACKGROUND, false);
}
mDefaultListType
=
defaultListType
;
final Intent
containerIntent
=
new
Intent().setComponent(
StorageMeasurement.DEFAULT_CONTAINER_COMPONENT);
getActivity().bindService(containerIntent, mContainerConnection, Context.BIND_AUTO_CREATE);
mInvalidSizeStr
=
getActivity
().getText(R.string.invalid_size_value);
mComputingSizeStr
=
getActivity
().getText(R.string.computing_size);
TabInfo
tab
=
new
TabInfo(this, mApplicationsState,
getActivity().getString(R.string.filter_apps_third_party),
LIST_TYPE_DOWNLOADED, this, savedInstanceState);
mTabs.add(tab);
if (!Environment.isExternalStorageEmulated()) {
tab
=
new
TabInfo(this, mApplicationsState,
getActivity().getString(R.string.filter_apps_onsdcard),
LIST_TYPE_SDCARD, this, savedInstanceState);
mTabs.add(tab);
}
tab
=
new
TabInfo(this, mApplicationsState,
getActivity().getString(R.string.filter_apps_running),
LIST_TYPE_RUNNING, this, savedInstanceState);
mTabs.add(tab);
tab
=
new
TabInfo(this, mApplicationsState,
getActivity().getString(R.string.filter_apps_all),
LIST_TYPE_ALL, this, savedInstanceState);
mTabs.add(tab);
}
这里主要是初始化TabInfo的数据,之后显示程序的时候会用到。接下来定位到onCreateView()方法,这个方法主要是初始化界面,
[html]
view plain
copy
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// initialize the inflater
mInflater
=
inflater
;
View
rootView
=
mInflater
.inflate(R.layout.manage_applications_content,
container, false);
mContentContainer
=
container
;
mRootView
=
rootView
;
mViewPager
= (ViewPager) rootView.findViewById(R.id.pager);
MyPagerAdapter
adapter
=
new
MyPagerAdapter();
mViewPager.setAdapter(adapter);
mViewPager.setOnPageChangeListener(adapter);
PagerTabStrip
tabs
= (PagerTabStrip) rootView.findViewById(R.id.tabs);
tabs.setTabIndicatorColorResource(android.R.color.holo_blue_light);
// We have to do this now because PreferenceFrameLayout looks at it
// only when the view is added.
if (container instanceof PreferenceFrameLayout) {
((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams())
.removeBorders
=
true
;
}
if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_RESET_DIALOG)) {
buildResetDialog();
}
if (
savedInstanceState
== null) {
// First time init: make sure view pager is showing the correct tab.
for (int
i
=
0
; i
<
mTabs.size
(); i++) {
TabInfo
tab
=
mTabs
.get(i);
if (
tab.mListType
== mDefaultListType) {
mViewPager.setCurrentItem(i);
break;
}
}
}
return rootView;
}
可以看到,正是使用了ViewPager,另外还有PagerTabStrip。先看一下最下面的:
[html]
view plain
copy
if (
savedInstanceState
== null) {
// First time init: make sure view pager is showing the correct tab.
for (int
i
=
0
; i
<
mTabs.size
(); i++) {
TabInfo
tab
=
mTabs
.get(i);
if (
tab.mListType
== mDefaultListType) {
mViewPager.setCurrentItem(i);
break;
}
}
}
这段代码的作用就是用于设置默认显示哪个选项卡的程序,所以就是“已下载”这个界面。然后回过头看一下上面的代码,
[html]
view plain
copy
MyPagerAdapter
adapter
=
new
MyPagerAdapter();
mViewPager.setAdapter(adapter);
这个就是熟悉的适配器了,所以显示程序的数据在这里面。开打这个类,
[html]
view plain
copy
class MyPagerAdapter extends PagerAdapter
implements ViewPager.OnPageChangeListener {
int
mCurPos
=
0
;
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
TabInfo
tab
=
mTabs
.get(position);
View
root
=
tab
.build(mInflater, mContentContainer, mRootView);
container.addView(root);
return root;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return
view
== object;
}
@Override
public CharSequence getPageTitle(int position) {
return mTabs.get(position).mLabel;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mCurPos
=
position
;
}
@Override
public void onPageScrollStateChanged(int state) {
if (
state
== ViewPager.SCROLL_STATE_IDLE) {
updateCurrentTab(mCurPos);
}
}
}
可以看到,有几个滑动的页卡,是通过mTabs这个类来控制的,而它就是
TabInfo类型。接着看一下绘制视图的方法:
[html]
view plain
copy
MyPagerAdapter @Override
public Object instantiateItem(ViewGroup container, int position) {
TabInfo
tab
=
mTabs
.get(position);
View
root
=
tab
.build(mInflater, mContentContainer, mRootView);
container.addView(root);
return root;
}
首先是获取到一个tab,然后这个tab用它的build()方法去生成一个视图,最后放到ViewPager显示。所以问题的重点分析就是TabInfo这个类了。先说buid()方法,
[html]
view plain
copy
public View build(LayoutInflater inflater, ViewGroup contentParent,
View contentChild) {
if (mRootView != null) {
return mRootView;
}
mInflater
=
inflater
;
mRootView
=
inflater
.inflate(
mListType
== LIST_TYPE_RUNNING ? R.layout.manage_applications_running
: R.layout.manage_applications_apps, null);
mLoadingContainer
=
mRootView
.findViewById(R.id.loading_container);
mLoadingContainer.setVisibility(View.VISIBLE);
mListContainer
=
mRootView
.findViewById(R.id.list_container);
if (mListContainer != null) {
// Create adapter and list view here
View
emptyView
=
mListContainer
.findViewById(com.android.internal.R.id.empty);
ListView
lv
= (ListView) mListContainer
.findViewById(android.R.id.list);
if (emptyView != null) {
lv.setEmptyView(emptyView);
}
lv.setOnItemClickListener(this);
lv.setSaveEnabled(true);
lv.setItemsCanFocus(true);
lv.setTextFilterEnabled(true);
mListView
=
lv
;
mApplications
=
new
ApplicationsAdapter(mApplicationsState,
this, mFilter);
mListView.setAdapter(mApplications);
mListView.setRecyclerListener(mApplications);
mColorBar
= (LinearColorBar) mListContainer
.findViewById(R.id.storage_color_bar);
mStorageChartLabel
= (TextView) mListContainer
.findViewById(R.id.storageChartLabel);
mUsedStorageText
= (TextView) mListContainer
.findViewById(R.id.usedStorageText);
mFreeStorageText
= (TextView) mListContainer
.findViewById(R.id.freeStorageText);
Utils.prepareCustomPreferencesList(contentParent, contentChild,
mListView, false);
if (
mFilter
== FILTER_APPS_SDCARD) {
mStorageChartLabel.setText(mOwner.getActivity().getText(
R.string.sd_card_storage));
} else {
mStorageChartLabel.setText(mOwner.getActivity().getText(
R.string.internal_storage));
}
applyCurrentStorage();
}
mRunningProcessesView
= (RunningProcessesView) mRootView
.findViewById(R.id.running_processes);
if (mRunningProcessesView != null) {
mRunningProcessesView.doCreate(mSavedInstanceState);
}
return mRootView;
}
第四行是生成了一view对象,
[html]
view plain
copy
mRootView
=
inflater
.inflate(
mListType
== LIST_TYPE_RUNNING ? R.layout.manage_applications_running: R.layout.manage_applications_apps, null);
这行代码用来判断加载哪个布局文件,确实viewpager虽然动态显示四个页面,但是其中三个的布局是一样的,唯一不一样的就是显示正在运行的界面。
[html]
view plain
copy
ListView
lv
= (ListView) mListContainer
.findViewById(android.R.id.list);
if (emptyView != null) {
lv.setEmptyView(emptyView);
}
lv.setOnItemClickListener(this);
lv.setSaveEnabled(true);
lv.setItemsCanFocus(true);
lv.setTextFilterEnabled(true);
mListView
=
lv
;
mApplications
=
new
ApplicationsAdapter(mApplicationsState,
this, mFilter);
mListView.setAdapter(mApplications);
这段代码就是用于显示app程序了,然后定位到
ApplicationsAdapter这个类,在它的构造方法里面,传入三个参数。一个是
mApplicationsState对象,以后用于对
ApplicationsState类进行操作;
一个是TabInfo,用来显示不同的界面;一个是过滤器,是标识显示哪个界面。进入这个构造方法,
[html]
view plain
copy
public ApplicationsAdapter(ApplicationsState state, TabInfo tab,
int filterMode) {
mState
=
state
;
mSession
=
state
.newSession(this);
mTab
=
tab
;
mContext
=
tab
.mOwner.getActivity();
mFilterMode
=
filterMode
;
}
发现没有在这里传入什么数据,然后看一下ApplicationsAdapter这个类,发现它继承了三个接口,第一个是过滤用的,第三个是系统SDK接口用于ListView循环处理。而第二个接口正是负责处理数据的,
它有六个回调方法:
[html]
view plain
copy
public static interface Callbacks {
public void onRunningStateChanged(boolean running);
public void onPackageListChanged();
public void onRebuildComplete(ArrayList
<
AppEntry
>
apps);
public void onPackageIconChanged();
public void onPackageSizeChanged(String packageName);
public void onAllSizesComputed();
}
第三个回调方法onRebuildComplete(ArrayList<AppEntry> apps)正是用于返回app Entities的,但是到这里如果我们还是按这条线是分析不下去了,找不到这个数据是从哪里来的。所以不能按照这个思路往下走了,也就是说app程序数据不是在这里获取的,那会是什么地方呢?一般情况下,我们是在onStart或者onCreat方法里面,但是Setting里面都没有这样做,那往下看一下onResume吧。果然Settings是在这个方法里面加载数据的,
[html]
view plain
copy
@Override
public void onResume() {
super.onResume();
mActivityResumed
=
true
;
updateCurrentTab(mViewPager.getCurrentItem());
updateOptionsMenu();
}
首先是调用了updateCurrentTab(mViewPager.getCurrentItem())方法,然后updateCurrentTab方法里面又调用了TabInfo的resume方法,在
TabInfo的resume方法里面接着调用了
ApplicationsAdapter 的
resume方法,又在
ApplicationsAdapter 的
resume方法里面调用
Session的resume方法,最后又在
Session的resume方法里面调用
doResumeIfNeededLocked()方法,这个方法就是从系统读取程序信息的,代码如下:
[html]
view plain
copy
void doResumeIfNeededLocked() {
if (mResumed) {
return;
}
mResumed
=
true
;
if (
mPackageIntentReceiver
== null) {
mPackageIntentReceiver
=
new
PackageIntentReceiver();
mPackageIntentReceiver.registerReceiver();
}
//这个mApplications就是所有程序数据,如果你想过滤哪些程序的信息,对这个集合进行修改即可。比如你在做定制机的时候,不想自己的程序显示在Settings里面,那就在这里修改。
mApplications
=
mPm
.getInstalledApplications(mRetrieveFlags);
if (
mApplications
== null) {
mApplications
=
new
ArrayList
<
ApplicationInfo
>
();
}
if (mInterestingConfigChanges.applyNewConfig(mContext.getResources())) {
// If an interesting part of the configuration has changed, we
// should completely reload the app entries.
mEntriesMap.clear();
mAppEntries.clear();
} else {
for (int
i
=
0
; i
<
mAppEntries.size
(); i++) {
mAppEntries.get(i)
.sizeStale
=
true
;
}
}
for (int
i
=
0
; i
<
mApplications.size
(); i++) {
final ApplicationInfo
info
=
mApplications
.get(i);
// Need to trim out any applications that are disabled by
// something different than the user.
if (!info.enabled
&& info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
mApplications.remove(i);
i--;
continue;
}
final AppEntry
entry
=
mEntriesMap
.get(info.packageName);
if (entry != null) {
entry.info
=
info
;
}
}
mCurComputingSizePkg
=
null
;
if (!mBackgroundHandler.hasMessages(BackgroundHandler.MSG_LOAD_ENTRIES)) {
mBackgroundHandler
.sendEmptyMessage(BackgroundHandler.MSG_LOAD_ENTRIES);
}
};
至此,完成了显示程序的剖析,其他模块类似,只要按照流程走就行了。
相似博文推荐:
1、
Android PreferenceActivity点击Header是如何处理的?
2、
android-setting
3、
Android4.0设置界面修改总结
4、
Android源码之“应用程序界面“分析一( 从settings开始)
5、
Android 应用程序分析之Settings
6、
菜鸟Android4.0 Settings分析(一)
7、
Android Settings源码结构分析与自实现
8、
Settings源码分析
9、
Settings修改记录
原文章连接:
http://blog.csdn.net/wangjinyu501/article/details/22077803
声明:
本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:
https://www.wpsshop.cn/w/羊村懒王/article/detail/458127
推荐阅读
article
Mybatis之XML配置文件之
properties
,
set
tings,
typeAliases
,ty...
MyBatis 的配置文件包含了影响 MyBatis 行为甚深的设置(
set
tings)和属性(
properties
)信...
赞
踩
article
android
aapt
.exe 应用程序错误,最新
Android
Studio3.1 运行错误Aa...
网上找了很多关于运行错误
Aapt2Exception
的原因,走了不少弯路一致没有解决这个问题,查阅很久,不外乎这么两个:...
赞
踩
article
2024
最新最全【
Android
studio
】
安装
入门教程
(非常详细)手把手教你
安装
使用!【附
安装
...
pwd=6789提取码:6789目录JDK
安装
与
配置
一、下载JDK二、JDK
安装
三、JDK的环境
配置
四、JDK的
配置
验证...
赞
踩
article
Android
Studio
通过修改文件
gradle
-
wrapper
.
properties
内容
下载
g...
Gradle project sync failed. Basic functionality (e.g. editin...
赞
踩
article
Cannot
find
runner
for
app
——Android Studio_
error
...
如图运行按钮不可点击。_
error
running
'
app
':
cannot
find
runner
for
app
e...
赞
踩
article
Android
Studio
搭建离线开发
环境
_
androidstudio
离线配置
环境
...
----常用快捷键 1.Ctrl+E,可以显示最近编辑的文件列表 2.Shift+Click可以关闭文件 3.Ct...
赞
踩
article
Android
Studio
怎么用?
Android
Studio
使用
教程图文详解以及快捷键_andr...
Android
Studio
1.0正式版终于发布了!谷歌表示
Android
Studio
1.0 能让开发者“更快更有...
赞
踩
article
[
Android
] 「送给最好的 TA」
App
逆向与
Lua
脚本
解密
实例_
androlua
解密
工具...
0x00 事由最近一些群里出现了会以最大音量外放音频且无法退出的恶搞
Android
App
,造成了一些不好的影响。恰好借...
赞
踩
article
抖音
Android
性能
优化
系列:启动
优化
实践...
动手点关注干货不迷路????启动
性能
是 APP 使用体验的门面,启动过程耗时较长很可能使用户削减使用 APP 的兴趣,抖...
赞
踩
article
Android
5.0
、
6.0
、
7.0
、
8.0
、9.0 新特性,
DownloadManager
踩坑记...
目录一、
5.0
新特性二、
6.0
新特性三、
7.0
新特性四、
8.0
新特性五、9.0新特性六、 一步步跟着案例进行版本升级踩坑...
赞
踩
article
Android
ViewPager
Fragment
切换刷新数据,解决
生命周期
只走一次的问题_an...
前言Activity的
生命周期
都应该熟悉,
Fragment
其标准
生命周期
也仅比Activity多出一些流程,如onCre...
赞
踩
article
Android
监听
Home
键
、Back
键
、
多任务
键
最新解决方法_
android
监听
导航栏
多任务
...
前言在开发中,我们可以经常看金融银行之类APP,退到后台都会给出提示,提高安全性。实现这种功能就需要去
监听
系统的按
键
操作...
赞
踩
article
Android
-高级-
UI
-进阶之路-(三)-理解-
View
-工作原理
并
带你入
自定义
-
View
-门_...
下面我们将详细介绍
自定义
View
。
自定义
View
的作用不用多说,这个大家应该都比较清楚,如果你想做出比较绚丽华彩的...
赞
踩
article
android
commit
规范_
android
studio
设置
commit
message
...
Commit规范在团队开发过程中,如果大家Commit Message不统一或者写的不清晰,很难看出一次提交修改了哪些内...
赞
踩
article
Android
,判断是否
快速
点击
...
在
Android
控件中,如果
快速
点击
容易造成一些不同的bug,尤其是那种在click事件中方有耗时操作的代码,容易引起a...
赞
踩
article
Android s
t
udio gi
t
upda
t
e
Projec
t
.. Can‘
t
upda
t
e
m...
报错信息 "Can'
t
upda
t
e
mas
t
er
has no
t
racked
branch
" 表示 Gi
t
在执行更...
赞
踩
article
Android
Apk
编译
打包流程,看完这篇文章直接变懂哥_
task
:
simpledemo
:
pr...
作为一个开发,每天都会有相当一部分的时间花在
编译
打包上,如果项目比较大的话
编译
一次可能就要十几分钟。那么在
编译
打包的过程...
赞
踩
article
最全总结 |
Android
系统
抓包
喂饭教程!
_
安卓
手机
抓包
...
由于高版本
系统
提高了安全策略,要
抓包
必须将 CA 证书放置到
系统
证书目录下才能进行正常
抓包
,而用户安装的证书默认为用户证...
赞
踩
article
Android
JetPack
Compose
+
Room
----实现
搜索
记录
功能...
搜索
功能是很多APP都会重点维护的功能,因为
搜索
功能可以很好的帮助用户找到自己需要的内容,与此同时,为了增强用户体验,引...
赞
踩
article
Android
Studio的笔记
--
okhttp
使用,
gson
使用_
android
studio
...
android
okhttp
POST参数格式JSON,json解析。采用RESTful技术,采用“HTTP(s)+JS...
赞
踩
相关标签
android aapt.exe 应用程序错误
android studio
android
ide
web安全
网络安全
数据库
ddos
大数据
Android
逆向工程
反编译
lua
破解
面试
java
编程语言
6.0
7.0
8.0
踩坑