Skip to content

Commit

Permalink
Fixed performance issues in the applications selection activity
Browse files Browse the repository at this point in the history
  • Loading branch information
httpdispatch committed Aug 15, 2017
1 parent b7df608 commit becca88
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package com.app.missednotificationsreminder.binding.model;

import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.view.View;

import com.app.missednotificationsreminder.binding.util.BindableBoolean;
import com.app.missednotificationsreminder.binding.util.RxBindingUtils;
import com.app.missednotificationsreminder.data.model.ApplicationItem;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.RequestCreator;

Expand All @@ -17,16 +15,15 @@
*
* @author Eugene Popovich
*/
public class ApplicationItemViewModel extends BaseViewModel{
public class ApplicationItemViewModel extends BaseViewModel {
/**
* Data binding field to store application checked state
*/
public BindableBoolean checked = new BindableBoolean();

ApplicationItem mApplicationItem;
private ApplicationCheckedStateChangedListener mApplicationCheckedStateChangedListener;
private PackageInfo mPackageInfo;
private Picasso mPicasso;
private PackageManager mPackageManager;

/**
* @param checked the current application checked state
Expand All @@ -37,23 +34,22 @@ public class ApplicationItemViewModel extends BaseViewModel{
* state changed event
*/
public ApplicationItemViewModel(
boolean checked, PackageInfo packageInfo,
PackageManager packageManager, Picasso picasso,
ApplicationItem applicationItem,
Picasso picasso,
ApplicationCheckedStateChangedListener applicationCheckedStateChangedListener) {
Timber.d("Constructor");
mPackageInfo = packageInfo;
mPackageManager = packageManager;
mApplicationItem = applicationItem;
mPicasso = picasso;
mApplicationCheckedStateChangedListener = applicationCheckedStateChangedListener;
this.checked.set(checked);
this.checked.set(applicationItem.isChecked());
if (mApplicationCheckedStateChangedListener != null) {
monitor(RxBindingUtils
.valueChanged(this.checked)
.skip(1) // skip the current value processing, which is passed automatically
.subscribe(value -> {
Timber.d("Checked property changed for %1$s", toString());
mApplicationCheckedStateChangedListener.onApplicationCheckedStateChanged
(mPackageInfo, value);
(mApplicationItem, value);
}));
}
}
Expand All @@ -65,7 +61,7 @@ public ApplicationItemViewModel(
*/
public CharSequence getName() {
Timber.d("getName for %1$s", toString());
return mPackageInfo.applicationInfo.loadLabel(mPackageManager);
return mApplicationItem.getApplicationName();
}

/**
Expand All @@ -75,7 +71,7 @@ public CharSequence getName() {
*/
public String getDescription() {
Timber.d("getDescription for %1$s", toString());
return mPackageInfo.packageName;
return mApplicationItem.getPackageName();
}

/**
Expand All @@ -85,13 +81,8 @@ public String getDescription() {
*/
public RequestCreator getIcon() {
Timber.d("getIcon for %1$s", toString());
Uri result = null;
int icon = mPackageInfo.applicationInfo.icon;
if (icon != 0) {
result = Uri.parse("android.resource://" + mPackageInfo.packageName + "/" + icon);
}
return result == null ? null : mPicasso.load(result)
.fit();
return mApplicationItem.hasIcon() ? mPicasso.load(mApplicationItem.getIconUri())
.fit() : null;
}

/**
Expand All @@ -107,13 +98,13 @@ public void onItemClicked(View v) {

@Override
public String toString() {
return String.format("%1$s(checked=%2$b, package=%3$s)", getClass().getSimpleName(), checked.get(), mPackageInfo.packageName);
return String.format("%1$s(checked=%2$b, package=%3$s)", getClass().getSimpleName(), checked.get(), mApplicationItem.getPackageName());
}

/**
* The interface subscribers to the onApplicationCheckedStateChanged event should implement
*/
public static interface ApplicationCheckedStateChangedListener {
void onApplicationCheckedStateChanged(PackageInfo packageInfo, boolean checked);
void onApplicationCheckedStateChanged(ApplicationItem applicationItem, boolean checked);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ public class ApplicationsSelectionViewModel extends BaseViewModel {
private PublishSubject<Set<String>> dataLoadSubject;

/**
* @param view the related view
* @param view the related view
* @param selectedApplications preference to store/retrieve selected applications
* @param mainThreadScheduler
* @param ioThreadScheduler
* @param packageManager
*/
@Inject public ApplicationsSelectionViewModel(ApplicationsSelectionView view, @SelectedApplications Preference<Set<String>> selectedApplications, @MainThreadScheduler Scheduler mainThreadScheduler,
@Inject public ApplicationsSelectionViewModel(ApplicationsSelectionView view, @SelectedApplications Preference<Set<String>> selectedApplications,
@MainThreadScheduler Scheduler mainThreadScheduler,
@IoThreadScheduler Scheduler ioThreadScheduler,
PackageManager packageManager) {
this.mMainThreadScheduler = mainThreadScheduler;
Expand All @@ -62,7 +63,6 @@ private void init() {

Observable<List<ApplicationItem>> result = dataLoadSubject //
.flatMap(packagesList) // load data
.subscribeOn(mIoThreadScheduler)
.observeOn(mMainThreadScheduler) //
.share();
monitor(result //
Expand All @@ -82,15 +82,15 @@ public void loadData() {
* checked/unchecked state information
*/
private final Func1<Set<String>, Observable<List<ApplicationItem>>> packagesList =
selectedPreferences -> {
selectedPreferences -> Observable.fromCallable(() -> {
List<ApplicationItem> result = new ArrayList<>();
List<PackageInfo> packages = mPackageManager.getInstalledPackages(0);
for (PackageInfo packageInfo : packages) {
boolean selected = selectedPreferences.contains(packageInfo.packageName);
result.add(new ApplicationItem(selected, packageInfo));
result.add(new ApplicationItem(selected, packageInfo, mPackageManager));
}
return Observable.just(result);
};
return result;
}).subscribeOn(mIoThreadScheduler);


/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.app.missednotificationsreminder.data.model;

import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;

import com.app.missednotificationsreminder.binding.model.ApplicationsSelectionViewModel;

Expand All @@ -11,17 +13,25 @@
*/
public class ApplicationItem {
private boolean mChecked;
private PackageInfo mPpackageInfo;
private CharSequence mApplicationName;
private String mPackageName;
private Uri mIconUri;

/**
* Creates the ApplicationItem object
*
* @param checked whether the application is already checked by user
* @param ppackageInfo the application package information
* @param checked whether the application is already checked by user
* @param packageInfo the application package information
* @param packageManager the package manager instance
*/
public ApplicationItem(boolean checked, PackageInfo ppackageInfo) {
public ApplicationItem(boolean checked, PackageInfo packageInfo, PackageManager packageManager) {
mChecked = checked;
mPpackageInfo = ppackageInfo;
mApplicationName = packageInfo.applicationInfo.loadLabel(packageManager);
mPackageName = packageInfo.packageName;
int icon = packageInfo.applicationInfo.icon;
if (icon != 0) {
mIconUri = Uri.parse("android.resource://" + packageInfo.packageName + "/" + icon);
}
}

public boolean isChecked() {
Expand All @@ -32,11 +42,19 @@ public void setChecked(boolean checked) {
mChecked = checked;
}

public PackageInfo getPpackageInfo() {
return mPpackageInfo;
public CharSequence getApplicationName() {
return mApplicationName;
}

public void setPpackageInfo(PackageInfo ppackageInfo) {
mPpackageInfo = ppackageInfo;
public String getPackageName() {
return mPackageName;
}

public boolean hasIcon() {
return mIconUri != null;
}

public Uri getIconUri() {
return mIconUri;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ public final class ApplicationsSelectionActivityModule {

@Provides
@Singleton ApplicationItemViewModel.ApplicationCheckedStateChangedListener provideApplicationsCheckedStateChangeListener(@SelectedApplications Preference<Set<String>> selectedApplications) {
return (packageInfo, checked) -> {
Timber.d("Update selected application value %1$s to %2$b", packageInfo.packageName, checked);
return (applicationItem, checked) -> {
Timber.d("Update selected application value %1$s to %2$b", applicationItem.getPackageName(), checked);
Observable<Pair<String, Set<String>>> selection = Observable
.just(new Pair<>(packageInfo.packageName, selectedApplications.get()))
.just(new Pair<>(applicationItem.getPackageName(), selectedApplications.get()))
.share();
// for sure we may use if condition here instead of concatenation of 2 observables. Just wanted to achieve
// same result with RxJava usage.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public int compare(ApplicationItem t0, ApplicationItem t1) {
}

String getLabel(ApplicationItem item){
CharSequence result = item.getPpackageInfo().applicationInfo.loadLabel(mPackageManager);
CharSequence result = item.getApplicationName();
if(result == null){
result = "";
}
Expand All @@ -60,7 +60,7 @@ public boolean areContentsTheSame(ApplicationItem oldItem,

@Override
public boolean areItemsTheSame(ApplicationItem item1, ApplicationItem item2) {
return item1.getPpackageInfo() == item2.getPpackageInfo();
return item1 == item2;
}
});

Expand Down Expand Up @@ -117,7 +117,7 @@ public ViewHolder(ApplicationSelectableItemViewBinding binding) {

public void bindTo(final ApplicationItem item) {
binding.setModel(
new ApplicationItemViewModel(item.isChecked(), item.getPpackageInfo(), mPackageManager,
new ApplicationItemViewModel(item,
mPicasso,
(packageInfo, checked) -> {
Timber.d("Update checked value to %1$b", checked);
Expand Down

0 comments on commit becca88

Please sign in to comment.