問題現象 上圖展示的很清楚,當系統語言為中文時,PreferenceScreen 中的摺疊項 summary 描述重覆顯示的 bug,系統語言為英文時正常。 修改歷程 先搜索 當前顯示了 字元串,還真找到了 prebuilts\sdk\current\support\v7\preference\re ...
問題現象
上圖展示的很清楚,當系統語言為中文時,PreferenceScreen 中的摺疊項 summary 描述重覆顯示的 bug,系統語言為英文時正常。
修改歷程
先搜索 當前顯示了 字元串,還真找到了
prebuilts\sdk\current\support\v7\preference\res\values-zh-rCN\values-zh-rCN.xml
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:ns1="urn:oasis:names:tc:xliff:document:1.2">
<string msgid="3265458434114353660" name="expand_button_title">"高級"</string>
<string msgid="5255557321652385027" name="summary_collapsed_preference_list">"當前顯示了 <ns1:g id="CURRENT_ITEMS">%1$s</ns1:g> 項(已添加 <ns1:g id="ADDED_ITEMS">%2$s</ns1:g> 項)"</string>
<string msgid="2082379519172883894" name="v7_preference_off">"關閉"</string>
<string msgid="7922757586228621900" name="v7_preference_on">"開啟"</string>
</resources>
再接著搜索 summary_collapsed_preference_list,又找到如下的地方
看著 androidTest 相關的可以忽略,直接看 CollapsiblePreferenceGroupController.java
frameworks\support\preference\src\main\java\androidx\preference\CollapsiblePreferenceGroupController.java
private void setSummary(List<Preference> collapsedPreferences) {
CharSequence summary = null;
final List<PreferenceGroup> parents = new ArrayList<>();
for (Preference preference : collapsedPreferences) {
final CharSequence title = preference.getTitle();
if (preference instanceof PreferenceGroup && !TextUtils.isEmpty(title)) {
parents.add((PreferenceGroup) preference);
}
if (parents.contains(preference.getParent())) {
if (preference instanceof PreferenceGroup) {
parents.add((PreferenceGroup) preference);
}
continue;
}
if (!TextUtils.isEmpty(title)) {
if (summary == null) {
summary = title;
} else {
summary = getContext().getString(
R.string.summary_collapsed_preference_list, summary, title);
}
}
}
setSummary(summary);
}
哈,這下證實了 bug 的由來,summary_collapsed_preference_list 字元串經過格式化 for 迴圈的疊加自然會出現 當前顯示了 當前顯示了 當前顯示了....
那就簡單了,把 summary_collapsed_preference_list 對應的中文字元串修改了就行唄,但是事情沒有那麼簡單,經過修改重新編譯測試 bug 依舊,然後又繼續搜索,
在 out 目錄下還發現了另一個 當前顯示了 字元串,文件內容和 prebuilts 下的是一模一樣的,但是文件時間卻是 2018-05-25 06:04
這就很詭異了,感覺此路不通啊,那好吧,乖乖去捋一捋源碼吧
經過簡單的分析,找到 Settings 中的 HighlightablePreferenceGroupAdapter 類
vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\widget\HighlightablePreferenceGroupAdapter.java
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceGroupAdapter;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.PreferenceViewHolder;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
public class HighlightablePreferenceGroupAdapter extends PreferenceGroupAdapter {
可以看到繼承的是 PreferenceGroupAdapter,而且還是 v7 包下麵的,繼續搜索 PreferenceGroupAdapter.java
https://segmentfault.com/a/1190000020956652
對比 8.1 和 9.0 一看,9.0 已經沒有 v7 包支持了,而是改用 androidx 替代,具體介紹可看 Preference組件探究之Base,Support及AndroidX對比
難怪我們上面修改 summary_collapsed_preference_list 沒用,上面調用的類 CollapsiblePreferenceGroupController 也是在 androidx 包下,查看 Settings 下的 mk
LOCAL_STATIC_ANDROID_LIBRARIES := \
android-slices-builders \
android-slices-core \
android-slices-view \
android-support-compat \
android-support-v4 \
android-support-v13 \
android-support-v7-appcompat \
android-support-v7-cardview \
android-support-v7-preference \
android-support-v7-recyclerview \
android-support-v14-preference \
android-support-v7-preference 導入靜態庫,而源碼中並沒有對應的目錄,已經替代為 androidx,悲催了,這下想改資源文件解決bug看來是不行了。
看了下 Android10.0 下 Settings 的 mk,發現已經全部替換為 androidx
LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx-constraintlayout_constraintlayout \
androidx.slice_slice-builders \
androidx.slice_slice-core \
androidx.slice_slice-view \
androidx.core_core \
androidx.appcompat_appcompat \
androidx.cardview_cardview \
androidx.preference_preference \
androidx.recyclerview_recyclerview \
com.google.android.material_material \
setupcompat \
setupdesign
解決辦法
通過進一步分析,找到一個關鍵欄位 initialExpandedChildrenCount
vendor\mediatek\proprietary\packages\apps\MtkSettings\res\xml\network_and_internet.xml
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="network_and_internet_screen"
android:title="@string/network_dashboard_title"
settings:initialExpandedChildrenCount="5">
該欄位在 PreferenceGroup 中獲取並賦值,用來區分當前 Preference 要顯示的數量,剩餘的需要摺疊顯示
frameworks\support\preference\src\main\java\androidx\preference\PreferenceGroup.java
public PreferenceGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mPreferenceList = new ArrayList<>();
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.PreferenceGroup, defStyleAttr, defStyleRes);
mOrderingAsAdded =
TypedArrayUtils.getBoolean(a, R.styleable.PreferenceGroup_orderingFromXml,
R.styleable.PreferenceGroup_orderingFromXml, true);
if (a.hasValue(R.styleable.PreferenceGroup_initialExpandedChildrenCount)) {
setInitialExpandedChildrenCount((TypedArrayUtils.getInt(
a, R.styleable.PreferenceGroup_initialExpandedChildrenCount,
R.styleable.PreferenceGroup_initialExpandedChildrenCount, Integer.MAX_VALUE)));
}
a.recycle();
}
最終在 CollapsiblePreferenceGroupController 中讀取該欄位,判斷是否需要添加 ExpandButton 即高級摺疊下拉按鈕
所以我們只需要將 initialExpandedChildrenCount 設置成最大即可,Preference 將不再摺疊,當然這是一種偷懶的做法,這樣會失去原來的用戶體驗
vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\widget\HighlightablePreferenceGroupAdapter.java
/**
* Tries to override initial expanded child count.
* <p/>
* Initial expanded child count will be ignored if:
* 1. fragment contains request to highlight a particular row.
* 2. count value is invalid.
*/
public static void adjustInitialExpandedChildCount(SettingsPreferenceFragment host) {
Log.e("HighlightablePreferenceGroupAdapter"," adjustInitialExpandedChildCount()");
if (host == null) {
return;
}
final PreferenceScreen screen = host.getPreferenceScreen();
if (screen == null) {
return;
}
final Bundle arguments = host.getArguments();
if (arguments != null) {
final String highlightKey = arguments.getString(EXTRA_FRAGMENT_ARG_KEY);
if (!TextUtils.isEmpty(highlightKey)) {
// Has highlight row - expand everything
screen.setInitialExpandedChildrenCount(Integer.MAX_VALUE);
return;
}
}
final int initialCount = host.getInitialExpandedChildCount();
//cczheng add for expand everything preference S
Log.e("HighlightablePreferenceGroupAdapter","initialCount="+initialCount);
if (true) {
screen.setInitialExpandedChildrenCount(Integer.MAX_VALUE);
return;
}
//E
if (initialCount <= 0) {
return;
}
screen.setInitialExpandedChildrenCount(initialCount);
}