From 9c4aa9127f1a5b2d5d9a6e20065d4132f13ef32c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Sun, 7 Jul 2013 00:27:12 +0200 Subject: [PATCH] Drastically improve performance after installs/uninstalls. - Only reload those apps that actually need reloading, not all of them - Reloading all the stuff inside DB.App is not necessary - only the install information can be changed --- src/org/fdroid/fdroid/AppDetails.java | 22 ++++---- src/org/fdroid/fdroid/DB.java | 62 ++++++++++++++++++++++ src/org/fdroid/fdroid/FDroidApp.java | 26 +++++++-- src/org/fdroid/fdroid/PackageReceiver.java | 5 +- src/org/fdroid/fdroid/Preferences.java | 2 +- src/org/fdroid/fdroid/UpdateService.java | 2 +- 6 files changed, 99 insertions(+), 20 deletions(-) diff --git a/src/org/fdroid/fdroid/AppDetails.java b/src/org/fdroid/fdroid/AppDetails.java index de2a6e334..07c3866e0 100644 --- a/src/org/fdroid/fdroid/AppDetails.java +++ b/src/org/fdroid/fdroid/AppDetails.java @@ -510,7 +510,7 @@ public class AppDetails extends ListActivity { new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { - install(); + install(app.id); } }); ask_alrt.setNegativeButton(getString(R.string.no), @@ -523,7 +523,7 @@ public class AppDetails extends ListActivity { AlertDialog alert = ask_alrt.create(); alert.show(); } else - install(); + install(app.id); } @Override @@ -601,7 +601,7 @@ public class AppDetails extends ListActivity { // Note that this handles updating as well as installing. curapk = app.getCurrentVersion(); if (curapk != null) - install(); + install(app.id); return true; case UNINSTALL: @@ -641,7 +641,7 @@ public class AppDetails extends ListActivity { } // Install the version of this app denoted by 'curapk'. - private void install() { + private void install(final String id) { String ra = null; try { @@ -666,7 +666,7 @@ public class AppDetails extends ListActivity { public void onClick(DialogInterface dialog, int whichButton) { downloadHandler = new DownloadHandler(curapk, - repoaddress); + repoaddress, id); } }); ask_alrt.setNegativeButton(getString(R.string.no), @@ -694,7 +694,7 @@ public class AppDetails extends ListActivity { alert.show(); return; } - downloadHandler = new DownloadHandler(curapk, repoaddress); + downloadHandler = new DownloadHandler(curapk, repoaddress, id); } private void removeApk(String id) { @@ -708,17 +708,15 @@ public class AppDetails extends ListActivity { Uri uri = Uri.fromParts("package", pkginfo.packageName, null); Intent intent = new Intent(Intent.ACTION_DELETE, uri); startActivityForResult(intent, REQUEST_UNINSTALL); - ((FDroidApp) getApplication()).invalidateApps(); } - private void installApk(File file) { + private void installApk(File file, String id) { Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file://" + file.getPath()), "application/vnd.android.package-archive"); startActivityForResult(intent, REQUEST_INSTALL); - ((FDroidApp) getApplication()).invalidateApps(); } private void launchApk(String id) { @@ -755,8 +753,10 @@ public class AppDetails extends ListActivity { private Downloader download; private ProgressDialog pd; private boolean updating; + private String id; - public DownloadHandler(DB.Apk apk, String repoaddress) { + public DownloadHandler(DB.Apk apk, String repoaddress, String appid) { + id = appid; download = new Downloader(apk, repoaddress); download.start(); startUpdates(); @@ -794,7 +794,7 @@ public class AppDetails extends ListActivity { case DONE: if (pd != null) pd.dismiss(); - installApk(download.localFile()); + installApk(download.localFile(), id); finished = true; break; case CANCELLED: diff --git a/src/org/fdroid/fdroid/DB.java b/src/org/fdroid/fdroid/DB.java index 4533d8bcd..658296b97 100644 --- a/src/org/fdroid/fdroid/DB.java +++ b/src/org/fdroid/fdroid/DB.java @@ -653,6 +653,17 @@ public class DB { } } + // Repopulate the details for the given app. + // If 'apkrepo' is non-zero, only apks from that repo are + // populated. + public void repopulateDetails(App app, int apkRepo) { + populateAppDetails(app); + + for (Apk apk : app.apks) { + populateApkDetails(apk, apkRepo); + } + } + // Return a list of apps matching the given criteria. Filtering is // also done based on compatibility and anti-features according to // the user's current preferences. @@ -784,6 +795,57 @@ public class DB { return result; } + public List refreshApps(List apps, List invalidApps) { + + List installedPackages = mContext.getPackageManager() + .getInstalledPackages(0); + long startTime = System.currentTimeMillis(); + for (String appid : invalidApps) { + App app = null; + int index = -1; + for (App oldapp : apps) { + index++; + if (oldapp.id.equals(appid)) { + app = oldapp; + break; + } + } + + if (app == null) continue; + + PackageInfo installed = null; + + for (PackageInfo appInfo : installedPackages) { + if (appInfo.packageName.equals(appid)) { + installed = appInfo; + break; + } + } + + if (installed != null) { + app.installedVersion = installed.versionName; + app.installedVerCode = installed.versionCode; + } else { + app.installedVersion = null; + app.installedVerCode = 0; + } + + Apk curver = app.getCurrentVersion(); + if (curver != null + && app.installedVersion != null + && app.installedVerCode < curver.vercode) { + app.hasUpdates = true; + app.updateVersion = curver.version; + } + + apps.set(index, app); + } + Log.d("FDroid", "Refreshing " + invalidApps.size() + " apps took " + + (System.currentTimeMillis() - startTime) + " ms"); + + return apps; + } + public List doSearch(String query) { List ids = new ArrayList(); diff --git a/src/org/fdroid/fdroid/FDroidApp.java b/src/org/fdroid/fdroid/FDroidApp.java index 5c1fb98b9..df9918701 100644 --- a/src/org/fdroid/fdroid/FDroidApp.java +++ b/src/org/fdroid/fdroid/FDroidApp.java @@ -65,6 +65,7 @@ public class FDroidApp extends Application { icon_path.mkdir(); apps = null; + invalidApps = new ArrayList(); Context ctx = getApplicationContext(); DB.initDB(ctx); UpdateService.schedule(ctx); @@ -76,15 +77,16 @@ public class FDroidApp extends Application { // Set when something has changed (database or installed apps) so we know // we should invalidate the apps. - private volatile boolean appsInvalid = false; + private volatile boolean appsAllInvalid = false; private Semaphore appsInvalidLock = new Semaphore(1, false); + private List invalidApps; // Set apps invalid. Call this when the database has been updated with // new app information, or when the installed packages have changed. - public void invalidateApps() { + public void invalidateAllApps() { try { appsInvalidLock.acquire(); - appsInvalid = true; + appsAllInvalid = true; } catch (InterruptedException e) { // Don't care } finally { @@ -92,6 +94,12 @@ public class FDroidApp extends Application { } } + // Invalidate a single app + public void invalidateApp(String id) { + Log.d("FDroid", "Invalidating "+id); + invalidApps.add(id); + } + // Get a list of all known applications. Should not be called when the // database is locked (i.e. between DB.getDB() and db.releaseDB(). The // contents should never be modified, it's for reading only. @@ -100,9 +108,9 @@ public class FDroidApp extends Application { boolean invalid = false; try { appsInvalidLock.acquire(); - invalid = appsInvalid; + invalid = appsAllInvalid; if (invalid) { - appsInvalid = false; + appsAllInvalid = false; Log.d("FDroid", "Dropping cached app data"); } } catch (InterruptedException e) { @@ -118,6 +126,14 @@ public class FDroidApp extends Application { } finally { DB.releaseDB(); } + } else if (!invalidApps.isEmpty()) { + try { + DB db = DB.getDB(); + apps = db.refreshApps(apps, invalidApps); + invalidApps.clear(); + } finally { + DB.releaseDB(); + } } if (apps == null) return new ArrayList(); diff --git a/src/org/fdroid/fdroid/PackageReceiver.java b/src/org/fdroid/fdroid/PackageReceiver.java index 83e48dda3..da05ba4f0 100644 --- a/src/org/fdroid/fdroid/PackageReceiver.java +++ b/src/org/fdroid/fdroid/PackageReceiver.java @@ -27,8 +27,9 @@ public class PackageReceiver extends BroadcastReceiver { @Override public void onReceive(Context ctx, Intent intent) { - Log.d("FDroid", "PackageReceiver invalidating apps"); - ((FDroidApp) ctx.getApplicationContext()).invalidateApps(); + String appid = intent.getData().getSchemeSpecificPart(); + Log.d("FDroid", "PackageReceiver invalidating "+appid); + ((FDroidApp) ctx.getApplicationContext()).invalidateApp(appid); } } diff --git a/src/org/fdroid/fdroid/Preferences.java b/src/org/fdroid/fdroid/Preferences.java index 0aea5f947..1b13a1c29 100644 --- a/src/org/fdroid/fdroid/Preferences.java +++ b/src/org/fdroid/fdroid/Preferences.java @@ -74,7 +74,7 @@ public class Preferences extends PreferenceActivity implements } finally { DB.releaseDB(); } - ((FDroidApp) getApplication()).invalidateApps(); + ((FDroidApp) getApplication()).invalidateAllApps(); File dp = DB.getDataPath(); deleteAll(dp); diff --git a/src/org/fdroid/fdroid/UpdateService.java b/src/org/fdroid/fdroid/UpdateService.java index 2e4b4a62b..7f4877603 100644 --- a/src/org/fdroid/fdroid/UpdateService.java +++ b/src/org/fdroid/fdroid/UpdateService.java @@ -248,7 +248,7 @@ public class UpdateService extends IntentService implements ProgressListener { sendStatus(STATUS_INFO, getString(R.string.status_downloading_icons)); for (DB.App app : acceptedapps) getIcon(app, repos); - ((FDroidApp) getApplication()).invalidateApps(); + ((FDroidApp) getApplication()).invalidateAllApps(); } }