diff --git a/src/main/java/com/nutomic/syncthingandroid/activities/FolderPickerActivity.java b/src/main/java/com/nutomic/syncthingandroid/activities/FolderPickerActivity.java index 279f5fb4..9445bd1e 100644 --- a/src/main/java/com/nutomic/syncthingandroid/activities/FolderPickerActivity.java +++ b/src/main/java/com/nutomic/syncthingandroid/activities/FolderPickerActivity.java @@ -109,6 +109,12 @@ public class FolderPickerActivity extends SyncthingActivity getService().registerOnApiChangeListener(this); } + @Override + protected void onDestroy() { + super.onDestroy(); + getService().unregisterOnApiChangeListener(this); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { if (mListView.getAdapter() == mRootsAdapter) diff --git a/src/main/java/com/nutomic/syncthingandroid/activities/MainActivity.java b/src/main/java/com/nutomic/syncthingandroid/activities/MainActivity.java index 2823429d..7c50c642 100644 --- a/src/main/java/com/nutomic/syncthingandroid/activities/MainActivity.java +++ b/src/main/java/com/nutomic/syncthingandroid/activities/MainActivity.java @@ -44,8 +44,6 @@ public class MainActivity extends SyncthingActivity private AlertDialog mDisabledDialog; - private boolean mIsDestroyed = false; - /** * Causes population of folder and device lists, unlocks info drawer. */ @@ -55,7 +53,7 @@ public class MainActivity extends SyncthingActivity runOnUiThread(new Runnable() { @Override public void run() { - if (currentState != SyncthingService.State.ACTIVE && !isFinishing() && !mIsDestroyed) { + if (currentState != SyncthingService.State.ACTIVE && !isFinishing()) { if (currentState == SyncthingService.State.DISABLED) { if (mLoadingDialog != null) { mLoadingDialog.dismiss(); @@ -215,7 +213,9 @@ public class MainActivity extends SyncthingActivity if (mLoadingDialog != null) { mLoadingDialog.dismiss(); } - mIsDestroyed = true; + getService().unregisterOnApiChangeListener(this); + getService().unregisterOnApiChangeListener(mFolderFragment); + getService().unregisterOnApiChangeListener(mDevicesFragment); } @Override diff --git a/src/main/java/com/nutomic/syncthingandroid/fragments/DeviceSettingsFragment.java b/src/main/java/com/nutomic/syncthingandroid/fragments/DeviceSettingsFragment.java index 93d68bb3..0565fd21 100644 --- a/src/main/java/com/nutomic/syncthingandroid/fragments/DeviceSettingsFragment.java +++ b/src/main/java/com/nutomic/syncthingandroid/fragments/DeviceSettingsFragment.java @@ -124,18 +124,22 @@ public class DeviceSettingsFragment extends PreferenceFragment implements mSyncthingService.registerOnApiChangeListener(this); } + @Override + public void onDestroy() { + super.onDestroy(); + mSyncthingService.unregisterOnApiChangeListener(this); + } + @Override public void onApiChange(SyncthingService.State currentState) { - if (getActivity() == null || getActivity().isFinishing()) { + if (currentState != SyncthingService.State.ACTIVE) { + getActivity().finish(); return; } - else if (currentState != SyncthingService.State.ACTIVE) { - getActivity().finish(); - } - if (mIsCreate) { + if (mIsCreate) getActivity().setTitle(R.string.add_device); - } else { + else { RestApi.Device device = null; getActivity().setTitle(R.string.edit_device); List devices = mSyncthingService.getApi().getDevices(false); diff --git a/src/main/java/com/nutomic/syncthingandroid/fragments/FolderSettingsFragment.java b/src/main/java/com/nutomic/syncthingandroid/fragments/FolderSettingsFragment.java index 53b0de63..bfd39820 100644 --- a/src/main/java/com/nutomic/syncthingandroid/fragments/FolderSettingsFragment.java +++ b/src/main/java/com/nutomic/syncthingandroid/fragments/FolderSettingsFragment.java @@ -121,10 +121,7 @@ public class FolderSettingsFragment extends PreferenceFragment @Override public void onApiChange(SyncthingService.State currentState) { - if (getActivity() == null || getActivity().isFinishing()) { - return; - } - else if (currentState != SyncthingService.State.ACTIVE) { + if (currentState != SyncthingService.State.ACTIVE) { getActivity().finish(); return; } @@ -185,6 +182,12 @@ public class FolderSettingsFragment extends PreferenceFragment mSyncthingService.registerOnApiChangeListener(this); } + @Override + public void onDestroy() { + super.onDestroy(); + mSyncthingService.unregisterOnApiChangeListener(this); + } + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); diff --git a/src/main/java/com/nutomic/syncthingandroid/fragments/SettingsFragment.java b/src/main/java/com/nutomic/syncthingandroid/fragments/SettingsFragment.java index 20ba64ec..fde35863 100644 --- a/src/main/java/com/nutomic/syncthingandroid/fragments/SettingsFragment.java +++ b/src/main/java/com/nutomic/syncthingandroid/fragments/SettingsFragment.java @@ -160,6 +160,12 @@ public class SettingsFragment extends PreferenceFragment mSyncthingService.registerOnApiChangeListener(this); } + @Override + public void onDestroy() { + super.onDestroy(); + mSyncthingService.unregisterOnApiChangeListener(this); + } + /** * Handles ActionBar back selected. */ diff --git a/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java b/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java index 74e58f4f..7f78d92a 100644 --- a/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java +++ b/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java @@ -14,6 +14,7 @@ import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Build; import android.os.Environment; +import android.os.Handler; import android.os.IBinder; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; @@ -31,7 +32,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.lang.ref.WeakReference; import java.nio.channels.FileChannel; import java.security.SecureRandom; import java.util.HashSet; @@ -92,6 +92,8 @@ public class SyncthingService extends Service { private final SyncthingServiceBinder mBinder = new SyncthingServiceBinder(this); + private Handler mMainHandler; + /** * Callback for when the Syncthing web interface becomes first available after service start. */ @@ -106,7 +108,7 @@ public class SyncthingService extends Service { public void onApiChange(State currentState); } - private final HashSet> mOnApiChangeListeners = + private final HashSet mOnApiChangeListeners = new HashSet<>(); /** @@ -139,10 +141,10 @@ public class SyncthingService extends Service { */ @Override public int onStartCommand(Intent intent, int flags, int startId) { - // Just catch the empty intent and return. - if (intent == null) { - } - else if (ACTION_RESTART.equals(intent.getAction()) && mCurrentState == State.ACTIVE) { + if (intent == null) + return START_STICKY; + + if (ACTION_RESTART.equals(intent.getAction()) && mCurrentState == State.ACTIVE) { mApi.shutdown(); mCurrentState = State.INIT; updateState(); @@ -253,6 +255,7 @@ public class SyncthingService extends Service { .putString("gui_password", sb.toString()).commit(); } + mMainHandler = new Handler(); mDeviceStateHolder = new DeviceStateHolder(SyncthingService.this); registerReceiver(mDeviceStateHolder, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); new StartupTask().execute(); @@ -347,13 +350,24 @@ public class SyncthingService extends Service { * Register a listener for the syncthing API state changing. * * The listener is called immediately with the current state, and again whenever the state - * changes. + * changes. The call is always from the GUI thread. + * + * @see {@link #unregisterOnApiChangeListener} */ public void registerOnApiChangeListener(OnApiChangeListener listener) { // Make sure we don't send an invalid state or syncthing might show a "disabled" message // when it's just starting up. listener.onApiChange(mCurrentState); - mOnApiChangeListeners.add(new WeakReference<>(listener)); + mOnApiChangeListeners.add(listener); + } + + /** + * Unregisters a previously registered listener. + * + * @see {@link #registerOnApiChangeListener} + */ + public void unregisterOnApiChangeListener(OnApiChangeListener listener) { + mOnApiChangeListeners.remove(listener); } private class PollWebGuiAvailableTaskImpl extends PollWebGuiAvailableTask { @@ -382,15 +396,20 @@ public class SyncthingService extends Service { * Must only be called from SyncthingService or {@link RestApi}. */ private void onApiChange() { - for (Iterator> i = mOnApiChangeListeners.iterator(); - i.hasNext(); ) { - WeakReference listener = i.next(); - if (listener.get() != null) { - listener.get().onApiChange(mCurrentState); - } else { - i.remove(); + mMainHandler.post(new Runnable() { + @Override + public void run() { + for (Iterator i = mOnApiChangeListeners.iterator(); + i.hasNext(); ) { + OnApiChangeListener listener = i.next(); + if (listener != null) { + listener.onApiChange(mCurrentState); + } else { + i.remove(); + } + } } - } + }); } /**