Apply a new icon cache mechanism for memory improvement

- Avoid loading all app icons at once to decrease memory usage.
- Only load visible icons when entering the apps page.
- Reserve icon placeholder to alleviate icon loading flicker.
- Release icon cache when low memory or leaving apps page.

Bug: 187118427
Bug: 209898662
Test: manual check the smoothness and memory usage of apps pages.
Change-Id: Ifc3c2a73cc88d6e42739df4e8208445afa12e0ea
This commit is contained in:
Yanting Yang
2022-01-07 01:55:39 +08:00
parent 0128837312
commit 19bdc6ce67
6 changed files with 65 additions and 14 deletions

View File

@@ -25,6 +25,7 @@ import android.view.View;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.applications.AppIconCacheManager;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppFilter;
import com.android.settingslib.search.SearchIndexable;
@@ -112,6 +113,12 @@ public class UnrestrictedDataAccess extends DashboardFragment {
return R.xml.unrestricted_data_access_settings;
}
@Override
public void onDestroyView() {
super.onDestroyView();
AppIconCacheManager.getInstance().release();
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.unrestricted_data_access_settings);
}

View File

@@ -16,6 +16,7 @@ package com.android.settings.datausage;
import static com.android.settingslib.RestrictedLockUtilsInternal.checkIfMeteredDataRestricted;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.view.View;
@@ -26,8 +27,10 @@ import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedPreferenceHelper;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.AppSwitchPreference;
public class UnrestrictedDataAccessPreference extends AppSwitchPreference implements
@@ -39,6 +42,7 @@ public class UnrestrictedDataAccessPreference extends AppSwitchPreference implem
private final DataSaverBackend mDataSaverBackend;
private final DashboardFragment mParentFragment;
private final RestrictedPreferenceHelper mHelper;
private Drawable mCacheIcon;
public UnrestrictedDataAccessPreference(final Context context, AppEntry entry,
ApplicationsState applicationsState, DataSaverBackend dataSaverBackend,
@@ -56,8 +60,13 @@ public class UnrestrictedDataAccessPreference extends AppSwitchPreference implem
UserHandle.getUserId(entry.info.uid)));
updateState();
setKey(generateKey(mEntry));
if (mEntry.icon != null) {
setIcon(mEntry.icon);
mCacheIcon = AppUtils.getIconFromCache(mEntry);
if (mCacheIcon != null) {
setIcon(mCacheIcon);
} else {
// Set empty icon as default.
setIcon(R.drawable.empty_icon);
}
}
@@ -101,16 +110,13 @@ public class UnrestrictedDataAccessPreference extends AppSwitchPreference implem
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
if (mEntry.icon == null) {
holder.itemView.post(new Runnable() {
@Override
public void run() {
// Ensure we have an icon before binding.
mApplicationsState.ensureIcon(mEntry);
// This might trigger us to bind again, but it gives an easy way to only
// load the icon once its needed, so its probably worth it.
setIcon(mEntry.icon);
}
if (mCacheIcon == null) {
ThreadUtils.postOnBackgroundThread(() -> {
final Drawable icon = AppUtils.getIcon(getContext(), mEntry);
ThreadUtils.postOnMainThread(() -> {
setIcon(icon);
mCacheIcon = icon;
});
});
}
final boolean disabledByAdmin = isDisabledByAdmin();

View File

@@ -29,6 +29,7 @@ import com.android.settings.applications.AppStateBaseBridge;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.applications.ApplicationsState.AppFilter;
@@ -125,6 +126,10 @@ public class UnrestrictedDataAccessPreferenceController extends BasePreferenceCo
return;
}
// Preload top visible icons of app list.
AppUtils.preloadTopIcons(mContext, apps,
mContext.getResources().getInteger(R.integer.config_num_visible_app_icons));
// Create apps key set for removing useless preferences
final Set<String> appsKeySet = new TreeSet<>();
// Add or update preferences