Lazy loading LauncherAppState
Separating InvarantDeviceProfile out of LauncherAppState and creating
LauncherAppState only when it is actually used
Change-Id: I2ee55f53cae01f11203f94675bb5f70c65ad2b9d
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index f63cce5..22bc162 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -29,6 +29,8 @@
import android.view.WindowManager;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.ConfigMonitor;
+import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Thunk;
import org.xmlpull.v1.XmlPullParser;
@@ -41,8 +43,12 @@
public class InvariantDeviceProfile {
- // This is a static that we use for the default icon size on a 4/5-inch phone
- private static float DEFAULT_ICON_SIZE_DP = 60;
+ // We do not need any synchronization for this variable as its only written on UI thread.
+ public static final MainThreadInitializedObject<InvariantDeviceProfile> INSTANCE =
+ new MainThreadInitializedObject<>((c) -> {
+ new ConfigMonitor(c).register();
+ return new InvariantDeviceProfile(c);
+ });
private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
@@ -118,7 +124,7 @@
}
@TargetApi(23)
- public InvariantDeviceProfile(Context context) {
+ private InvariantDeviceProfile(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index a46692b..5159de1 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -16,12 +16,13 @@
package com.android.launcher3;
+import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
+
import android.content.ComponentName;
import android.content.ContentProviderClient;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.os.Looper;
import android.util.Log;
import com.android.launcher3.compat.LauncherAppsCompat;
@@ -29,21 +30,17 @@
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.notification.NotificationListener;
-import com.android.launcher3.util.ConfigMonitor;
+import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SettingsObserver;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-
-import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
-
public class LauncherAppState {
public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher";
// We do not need any synchronization for this variable as its only written on UI thread.
- private static LauncherAppState INSTANCE;
+ private static final MainThreadInitializedObject<LauncherAppState> INSTANCE =
+ new MainThreadInitializedObject<>((c) -> new LauncherAppState(c));
private final Context mContext;
private final LauncherModel mModel;
@@ -53,27 +50,11 @@
private final SettingsObserver mNotificationBadgingObserver;
public static LauncherAppState getInstance(final Context context) {
- if (INSTANCE == null) {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- INSTANCE = new LauncherAppState(context.getApplicationContext());
- } else {
- try {
- return new MainThreadExecutor().submit(new Callable<LauncherAppState>() {
- @Override
- public LauncherAppState call() throws Exception {
- return LauncherAppState.getInstance(context);
- }
- }).get();
- } catch (InterruptedException|ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- }
- return INSTANCE;
+ return INSTANCE.get(context);
}
public static LauncherAppState getInstanceNoCreate() {
- return INSTANCE;
+ return INSTANCE.getNoCreate();
}
public Context getContext() {
@@ -89,7 +70,7 @@
Preconditions.assertUIThread();
mContext = context;
- mInvariantDeviceProfile = new InvariantDeviceProfile(mContext);
+ mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(mContext);
mIconCache = new IconCache(mContext, mInvariantDeviceProfile);
mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext));
@@ -112,7 +93,6 @@
mContext.registerReceiver(mModel, filter);
UserManagerCompat.getInstance(mContext).enableAndResetCache();
- new ConfigMonitor(mContext).register();
if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) {
mNotificationBadgingObserver = null;
@@ -171,7 +151,7 @@
* Shorthand for {@link #getInvariantDeviceProfile()}
*/
public static InvariantDeviceProfile getIDP(Context context) {
- return LauncherAppState.getInstance(context).getInvariantDeviceProfile();
+ return InvariantDeviceProfile.INSTANCE.get(context);
}
private static LauncherProvider getLocalProvider(Context context) {
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
new file mode 100644
index 0000000..5747db1
--- /dev/null
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+package com.android.launcher3.util;
+
+import android.content.Context;
+import android.os.Looper;
+
+import com.android.launcher3.MainThreadExecutor;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Utility class for defining singletons which are initiated on main thread.
+ */
+public class MainThreadInitializedObject<T> {
+
+ private final ObjectProvider<T> mProvider;
+ private T mValue;
+
+ public MainThreadInitializedObject(ObjectProvider<T> provider) {
+ mProvider = provider;
+ }
+
+ public T get(Context context) {
+ if (mValue == null) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ mValue = mProvider.get(context.getApplicationContext());
+ } else {
+ try {
+ return new MainThreadExecutor().submit(() -> get(context)).get();
+ } catch (InterruptedException|ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ return mValue;
+ }
+
+ public T getNoCreate() {
+ return mValue;
+ }
+
+ public interface ObjectProvider<T> {
+
+ T get(Context context);
+ }
+}