日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

android系统应用之Settings

發布時間:2023/12/3 windows 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android系统应用之Settings 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Setting作為安卓一個比較重要的系統級應用,為用戶提供一些系統項的設置。原生android系統的源碼路徑:/packages/apps/Settings。但MTK廠商的源碼包中對該應用進行了重構其源碼路徑:/vendor/mediatek/proprietary/packages/apps/MtkSettings。

一、Setting

1、入口Activity

android應用程序的入口比較簡單,可以直接查看AndroidManifest.xml,里面有配置應用的包名、版本、權限、四大組件等。Setting配置文件代碼如下:

<!--packages/apps/Settings/AndroidManifest.xml--> <manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"package="com.android.settings"coreApp="true"android:sharedUserId="android.uid.system"> <!--標識系統應用--><!--包名--><original-package android:name="com.android.settings" /> <!--應用配置--><application android:label="@string/settings_label"android:icon="@drawable/ic_launcher_settings"android:theme="@style/Theme.Settings"android:hardwareAccelerated="true"android:requiredForAllUsers="true"android:supportsRtl="true"android:backupAgent="com.android.settings.backup.SettingsBackupHelper"android:usesCleartextTraffic="true"android:defaultToDeviceProtectedStorage="true"android:directBootAware="true"android:appComponentFactory="androidx.core.app.CoreComponentFactory"><uses-library android:name="org.apache.http.legacy" /><!-- Settings --><activity android:name=".homepage.SettingsHomepageActivity"android:label="@string/settings_label_launcher"android:theme="@style/Theme.Settings.Home"android:taskAffinity="com.android.settings.root"android:launchMode="singleTask"android:configChanges="keyboard|keyboardHidden"><intent-filter android:priority="1"><action android:name="android.settings.SETTINGS" /><category android:name="android.intent.category.DEFAULT" /></intent-filter><meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" android:value="true" /></activity><!--主界面,activity的別名,目標actvity是SettingsHomepageActivity--><activity-alias android:name="Settings"android:label="@string/settings_label_launcher"android:taskAffinity="com.android.settings.root"android:launchMode="singleTask"android:targetActivity=".homepage.SettingsHomepageActivity"><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><meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/></activity-alias><receiver android:name=".SettingsInitialize"><intent-filter><action android:name="android.intent.action.USER_INITIALIZE"/><action android:name="android.intent.action.PRE_BOOT_COMPLETED"/></intent-filter></receiver><activity android:name=".SubSettings"/><!--activity配置 省略......--></application> </manifest>

上面的配置文件第一個被android.intent.action.MAIN修飾的是一個activity-alias標簽,該標簽意思是一個activity的別名。即它是一個已經存在的activity的別名(這個已經存在的activity被屬性targetActivity修飾),因此我們可以認為Settings程序的主界面是SettingsHomepageActivity.java。值得注意的是該標簽的name屬性并不會指定某個java文件,它只是一個命名標志而已,與他綁定相關的java文件是targetActivity對應的內容,因此這里只是把主界面命名為Settings,但是與源代碼中的com.android.settings.Settings.java毫無關系。詳情參考《activity-alias詳解及應用》。

為了驗證上面的理論如上圖我分別在SettingsHomepageActivity.java和Settings.java的onCreate加了日志,在啟動Settings的時候看看打印的日志是什么?

2、SettingsHomepageActivity

//packages/apps/Settings/src/com/android/settings/homepage/SettingsHomepageActivity.java public class SettingsHomepageActivity extends FragmentActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 設置主界面布局文件:settings_homepage_container.xmlsetContentView(R.layout.settings_homepage_container);// 獲取布局文件中homepage_container:主題內容final View root = findViewById(R.id.settings_homepage_container);root.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);//獲取布局文件中search_action_bar:頂部搜索控件final Toolbar toolbar = findViewById(R.id.search_action_bar);FeatureFactory.getFactory(this).getSearchFeatureProvider().initSearchToolbar(this, toolbar, SettingsEnums.SETTINGS_HOMEPAGE);//設置contextual_cards_content對應的fragment,不是低內存手機顯示卡片布局視圖if (!getSystemService(ActivityManager.class).isLowRamDevice()) {showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content);}//設置main_content對應fragment為TopLevelSettings,即所有二級菜單選項showFragment(new TopLevelSettings(), R.id.main_content);((FrameLayout) findViewById(R.id.main_content)).getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);} } <!--packages/apps/Settings/res/layout/settings_homepage_container.xml--> <androidx.coordinatorlayout.widget.CoordinatorLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/settings_homepage_container"android:fitsSystemWindows="true"android:layout_width="match_parent"android:layout_height="match_parent"><androidx.core.widget.NestedScrollViewandroid:id="@+id/main_content_scrollable_container"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="com.android.settings.widget.FloatingAppBarScrollingViewBehavior"><!--主題內容布局--><LinearLayoutandroid:id="@+id/homepage_container"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><!--顯示一些通知卡片--><FrameLayoutandroid:id="@+id/contextual_cards_content"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginStart="@dimen/contextual_card_side_margin"android:layout_marginEnd="@dimen/contextual_card_side_margin"/><!--所有的二級菜單--><FrameLayoutandroid:id="@+id/main_content"android:layout_width="match_parent"android:layout_height="wrap_content"android:animateLayoutChanges="true"android:background="?android:attr/windowBackground"/></LinearLayout></androidx.core.widget.NestedScrollView><!--頂部搜索欄--><com.google.android.material.appbar.AppBarLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:touchscreenBlocksFocus="false"android:keyboardNavigationCluster="false"><include layout="@layout/search_bar"/></com.google.android.material.appbar.AppBarLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

如上Activity和對應的布局文件代碼,很容易理解,整個布局主要分兩大塊:

  • 首先頂部的搜索欄通過包含search_bar.xml文件(實現了Settings的搜索設置功能),通過工廠方式來創建并初始化SearchFeatureProvider,可通過它來搜索Settings所有的子菜單
  • 最后內容主體部分使用了NestedScrollView滑動控件,它包含了兩個部分:頂部的卡片內容和下面主體二級菜單選項。其中二級菜單選項視圖被設置成了TopLevelSettings

2.1、SearchFeatureProvider搜索子菜單

2.2、TopLevelSettings二級菜單布局

//packages/apps/Settings/src/com/android/settings/homepage/TopLevelSettings.java @SearchIndexable(forTarget = MOBILE) public class TopLevelSettings extends DashboardFragment implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {public TopLevelSettings() {final Bundle args = new Bundle();args.putBoolean(NEED_SEARCH_ICON_IN_ACTION_BAR, false); //是否禁用搜索圖標setArguments(args);}@Overrideprotected int getPreferenceScreenResId() {return R.xml.top_level_settings; //對于視圖布局文件}@Overridepublic void onAttach(Context context) {super.onAttach(context);use(SupportPreferenceController.class).setActivity(getActivity());}@Overridepublic boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref) {new SubSettingLauncher(getActivity()).setDestination(pref.getFragment()).setArguments(pref.getExtras()).setSourceMetricsCategory(caller instanceof Instrumentable ? ((Instrumentable) caller).getMetricsCategory() : Instrumentable.METRICS_CATEGORY_UNKNOWN).setTitleRes(-1).launch();return true;}@Overrideprotected boolean shouldForceRoundedIcon() {return getContext().getResources().getBoolean(R.bool.config_force_rounded_icon_TopLevelSettings);} }

從上面的代碼可以知道TopLevelSettings是一個fragment,大部分功能在DashboardFragment父類具體實現,這里只提供了幾個接口,從名字上可以看出getPreferenceScreenResId對應于視圖布局文件,top_level_settings.xml如下:

2.3、Preference偏好設置

如上小節,我們發現布局文件中在PreferenceScreen里面包含了一批Preference。這個是什么東西呢?其實Preference是android原生為了持久化數據的一種"控件",注意它并不是真正意義上的View。具體用法可以參考《Android之PreferenceFragment詳解》

  • Preference家族

Preference源碼路徑如下圖,其中比較重要的有前面已經見過的PreferenceScreen和Preference。

  • Preference是"控件"?

Preference并不是控件,它沒有繼承View,但是為什么我們的布局文件中可以使用他呢?其實只有繼承了PreferenceFragment或者PreferenceActivity的才能使用上面以PreferenceScreen標簽開頭的xml文件,因為他們內部作了一系列解析,同時Preference有方法返回一個View對象,如下代碼:

//android/frameworks/base/core/java/android/preference/Preference.java @Deprecated public class Preference implements Comparable<Preference> {private boolean mShouldDisableView = true;@UnsupportedAppUsageprivate int mLayoutResId = com.android.internal.R.layout.preference;@UnsupportedAppUsageprivate int mWidgetLayoutResId;public void setLayoutResource(@LayoutRes int layoutResId) {if (layoutResId != mLayoutResId) mRecycleEnabled = false;mLayoutResId = layoutResId;}@LayoutRespublic int getLayoutResource() {return mLayoutResId;}//返回一個視圖控件Viewpublic View getView(View convertView, ViewGroup parent) {//如果第一次就創建視圖Viewif (convertView == null) convertView = onCreateView(parent);//給視圖View填充數據和更新uionBindView(convertView);return convertView;}//創建視圖控件View,實際上還是inflate對應的資源ID文件@CallSuperprotected View onCreateView(ViewGroup parent) {final LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);final View layout = layoutInflater.inflate(mLayoutResId, parent, false);final ViewGroup widgetFrame = (ViewGroup) layout.findViewById(com.android.internal.R.id.widget_frame);if (widgetFrame != null) {if (mWidgetLayoutResId != 0) layoutInflater.inflate(mWidgetLayoutResId, widgetFrame);else widgetFrame.setVisibility(View.GONE);}return layout;}//主要是給上面創建的視圖View設置數據@CallSuperprotected void onBindView(View view) {final TextView titleView = (TextView) view.findViewById(com.android.internal.R.id.title);if (titleView != null) {final CharSequence title = getTitle();if (!TextUtils.isEmpty(title)) {titleView.setText(title);titleView.setVisibility(View.VISIBLE);if (mHasSingleLineTitleAttr) titleView.setSingleLine(mSingleLineTitle);} else {titleView.setVisibility(View.GONE);}}final TextView summaryView = (TextView) view.findViewById( com.android.internal.R.id.summary);if (summaryView != null) {final CharSequence summary = getSummary();if (!TextUtils.isEmpty(summary)) {summaryView.setText(summary);summaryView.setVisibility(View.VISIBLE);} else {summaryView.setVisibility(View.GONE);}}final ImageView imageView = (ImageView) view.findViewById(com.android.internal.R.id.icon);if (imageView != null) {if (mIconResId != 0 || mIcon != null) {if (mIcon == null) mIcon = getContext().getDrawable(mIconResId);if (mIcon != null) imageView.setImageDrawable(mIcon);}if (mIcon != null) imageView.setVisibility(View.VISIBLE);else imageView.setVisibility(mIconSpaceReserved ? View.INVISIBLE : View.GONE);}final View imageFrame = view.findViewById(com.android.internal.R.id.icon_frame);if (imageFrame != null) {if (mIcon != null) imageFrame.setVisibility(View.VISIBLE);else imageFrame.setVisibility(mIconSpaceReserved ? View.INVISIBLE : View.GONE);}if (mShouldDisableView) setEnabledStateOnViews(view, isEnabled());}//界面更改條目欄public void setTitle(CharSequence title) {if (title == null && mTitle != null || title != null && !title.equals(mTitle)) {mTitleRes = 0;mTitle = title;notifyChanged();}}//界面更改圖標public void setIcon(Drawable icon) {if ((icon == null && mIcon != null) || (icon != null && mIcon != icon)) {mIcon = icon;notifyChanged();}}//界面有改變回調監聽器protected void notifyChanged() {if (mListener != null) mListener.onPreferenceChange(this);} }
  • Preference如何持久化?

Settings為什么大量使用了Preference,而沒有使用到我們常見的View和TextView呢,因為這里邏輯功能上主要是為了給系統進行一些設置,所有就涉及到了設置參數持久化(即斷電后還繼續生效),如下代碼它內部已經通過PreferenceManager來進行對數據的持久化,實際上還是使用了四大存儲方式之一。

//android/frameworks/base/core/java/android/preference/Preference.java @Deprecated public class Preference implements Comparable<Preference> {@Nullableprivate PreferenceManager mPreferenceManager;public SharedPreferences getSharedPreferences() {if (mPreferenceManager == null || getPreferenceDataStore() != null) return null;return mPreferenceManager.getSharedPreferences();}public SharedPreferences.Editor getEditor() {if (mPreferenceManager == null || getPreferenceDataStore() != null) return null;return mPreferenceManager.getEditor();}public boolean shouldCommit() {if (mPreferenceManager == null) return false;return mPreferenceManager.shouldCommit();}public PreferenceManager getPreferenceManager() {return mPreferenceManager;} }
  • Preference唯一標識
  • Preference如何自動跳轉android:fragment?

總結

以上是生活随笔為你收集整理的android系统应用之Settings的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。