From bf4ebe0fe3b93f5ad70f172047d9b3a65ebd7a6a Mon Sep 17 00:00:00 2001 From: Tilman Dilo Date: Mon, 5 Sep 2016 21:27:58 +0200 Subject: [PATCH] android: avoid excessive UI updates On some devices, updating notifications and status text at a high rate causes whole-system UI lag and even complete system freezes. On a Nexus 5, the uploader is completely unusable and requires a hard phone restart almost every time "upload all" is triggered from the UI. The device freezes happen across multiple stock Android releases. This commit reduces the update rate of the UI significantly by updating the notification only when the integer percent value of the upload progress changes. It also reduces the update rate of the status text to around 30 fps, which should still be plenty. With both of the changes, the uploader behaves as expected. Either change alone is not enough to get rid of the device freezes. Change-Id: I2c170772d29c4670c8c10d09cdaea96207fc9e61 --- .../android/src/org/camlistore/CamliActivity.java | 7 ++++--- .../android/src/org/camlistore/UploadService.java | 15 +++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/clients/android/src/org/camlistore/CamliActivity.java b/clients/android/src/org/camlistore/CamliActivity.java index 2730b952c..d6216206f 100644 --- a/clients/android/src/org/camlistore/CamliActivity.java +++ b/clients/android/src/org/camlistore/CamliActivity.java @@ -205,14 +205,15 @@ public class CamliActivity extends Activity { public void setUploadStatsText(final String text) throws RemoteException { // We were getting these status updates so quickly that the calls to TextView.setText // were consuming all CPU on the main thread and it was stalling the main thread - // for seconds. Ridiculous. So instead, only update this every 5 milliseconds, - // otherwise wait for the looper to be idle to update it. + // for seconds, sometimes even triggering device freezes. Ridiculous. So instead, + // only update this every 30 milliseconds, otherwise wait for the looper to be idle + // to update it. mHandler.post(new Runnable() { @Override public void run() { mStatusTextWant = text; long now = System.currentTimeMillis(); - if (mLastStatusUpdate < now - 5) { + if (mLastStatusUpdate < now - 30) { mStatusTextCurrent = mStatusTextWant; textStats.setText(mStatusTextWant); mLastStatusUpdate = System.currentTimeMillis(); diff --git a/clients/android/src/org/camlistore/UploadService.java b/clients/android/src/org/camlistore/UploadService.java index 4a45ba1d8..79e984c35 100644 --- a/clients/android/src/org/camlistore/UploadService.java +++ b/clients/android/src/org/camlistore/UploadService.java @@ -71,6 +71,7 @@ public class UploadService extends Service { // thread exits private Notification.Builder mNotificationBuilder; // null until upload is // started/resumed + private int mLastNotificationProgress = 0; // last computed value of the uploaded bytes, to avoid excessive notification updates private final Map mFileBytesRemain = new HashMap(); private final LinkedList mQueueList = new LinkedList(); private final Map mStatValue = new TreeMap(); @@ -408,11 +409,16 @@ public class UploadService extends Service { Notification notification = null; synchronized (this) { if (mNotificationBuilder != null) { - int kBUploaded = (int)(mBytesUploaded / 1024L); - int kBTotal = (int)(mBytesTotal / 1024L); + int progress = (int)(100 * (double)mBytesUploaded/(double)mBytesTotal); - mNotificationBuilder.setProgress(kBTotal, kBUploaded, false); - notification = mNotificationBuilder.build(); + // Only build new notification when progress value actually changes. Some + // devices slow down and finally freeze completely when updating too often. + if (mLastNotificationProgress != progress) { + mLastNotificationProgress = progress; + + mNotificationBuilder.setProgress(100, progress, false); + notification = mNotificationBuilder.build(); + } } try { mCallback.setByteStatus(mBytesUploaded, mBytesInFlight, mBytesTotal); @@ -700,6 +706,7 @@ public class UploadService extends Service { .setContentText("Camlistore uploader running") .setSmallIcon(android.R.drawable.stat_sys_upload); mNotificationManager.notify(NOTIFY_ID_UPLOADING, mNotificationBuilder.build()); + mLastNotificationProgress = -1; mUploading = true; mUploadThread = new UploadThread(UploadService.this, hp, mPrefs.trustedCert(), mPrefs.username(), mPrefs.password());