fix memory leaks

This commit is contained in:
Phillip Thelen 2017-07-25 12:48:25 +02:00
parent c7bf2bf034
commit d7ea9e9c6b
14 changed files with 105 additions and 148 deletions

View file

@ -48,7 +48,6 @@ import io.realm.RealmConfiguration;
//contains all HabiticaApplicationLogic except dagger componentInitialisation
public abstract class HabiticaBaseApplication extends MultiDexApplication {
public static Activity currentActivity = null;
private static AppComponent component;
public RefWatcher refWatcher;
@Inject
@ -123,7 +122,6 @@ public abstract class HabiticaBaseApplication extends MultiDexApplication {
setupLeakCanary();
setupFacebookSdk();
createBillingAndCheckout();
registerActivityLifecycleCallbacks();
if (!BuildConfig.DEBUG) {
try {
@ -198,47 +196,6 @@ public abstract class HabiticaBaseApplication extends MultiDexApplication {
}
}
private void registerActivityLifecycleCallbacks() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
HabiticaBaseApplication.currentActivity = activity;
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
HabiticaBaseApplication.currentActivity = activity;
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
if (currentActivity != null && currentActivity.equals(activity)) {
currentActivity = null;
}
}
});
}
@Override
public SQLiteDatabase openOrCreateDatabase(String name,
int mode, SQLiteDatabase.CursorFactory factory) {

View file

@ -2,19 +2,20 @@ package com.habitrpg.android.habitica.data.implementation;
import android.content.Context;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import com.amplitude.api.Amplitude;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.habitrpg.android.habitica.BuildConfig;
import com.habitrpg.android.habitica.HabiticaApplication;
import com.habitrpg.android.habitica.HabiticaBaseApplication;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.api.ApiService;
import com.habitrpg.android.habitica.api.HostConfig;
import com.habitrpg.android.habitica.api.Server;
import com.habitrpg.android.habitica.data.ApiClient;
import com.habitrpg.android.habitica.events.ShowConnectionProblemEvent;
import com.habitrpg.android.habitica.helpers.PopupNotificationsManager;
import com.habitrpg.android.habitica.models.AchievementResult;
import com.habitrpg.android.habitica.models.ContentResult;
@ -54,7 +55,6 @@ import com.habitrpg.android.habitica.models.shops.Shop;
import com.habitrpg.android.habitica.models.social.Challenge;
import com.habitrpg.android.habitica.models.social.ChatMessage;
import com.habitrpg.android.habitica.models.social.Group;
import com.habitrpg.android.habitica.models.tasks.RemindersItem;
import com.habitrpg.android.habitica.models.tasks.Task;
import com.habitrpg.android.habitica.models.tasks.TaskList;
import com.habitrpg.android.habitica.models.user.Items;
@ -92,6 +92,8 @@ import com.habitrpg.android.habitica.utils.TaskTagDeserializer;
import com.habitrpg.android.habitica.utils.TutorialStepListDeserializer;
import com.habitrpg.android.habitica.utils.UserDeserializer;
import org.greenrobot.eventbus.EventBus;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
@ -123,6 +125,7 @@ import rx.schedulers.Schedulers;
public class ApiClientImpl implements Action1<Throwable>, ApiClient {
private static final String TAG = "ApiClientImpl";
private final GsonConverterFactory gsonConverter;
private final HostConfig hostConfig;
private final Retrofit retrofitAdapter;
@ -363,21 +366,10 @@ public class ApiClientImpl implements Action1<Throwable>, ApiClient {
}
private void showConnectionProblemDialog(final String resourceTitleString, final String resourceMessageString) {
if (HabiticaApplication.currentActivity != null) {
HabiticaApplication.currentActivity.runOnUiThread(() -> {
if (!(HabiticaApplication.currentActivity).isFinishing() && displayedAlert == null) {
AlertDialog.Builder builder = new AlertDialog.Builder(HabiticaApplication.currentActivity)
.setTitle(resourceTitleString)
.setMessage(resourceMessageString)
.setNeutralButton(android.R.string.ok, (dialog, which) -> displayedAlert = null);
if (!resourceTitleString.isEmpty()) {
builder.setIcon(R.drawable.ic_warning_black);
}
displayedAlert = builder.show();
}
});
ShowConnectionProblemEvent event = new ShowConnectionProblemEvent(resourceTitleString, resourceMessageString);
EventBus.getDefault().post(event);
if (BuildConfig.DEBUG) {
Log.d(TAG, "showConnectionProblemDialog: " + resourceTitleString + " " + resourceMessageString);
}
}

View file

@ -0,0 +1,16 @@
package com.habitrpg.android.habitica.events;
/**
* Created by phillip on 25.07.17.
*/
public class ShowConnectionProblemEvent {
public String title;
public String message;
public ShowConnectionProblemEvent(String title, String message) {
this.title = title;
this.message = message;
}
}

View file

@ -77,7 +77,7 @@ public class PopupNotificationsManager {
TextView nextUnlockTextView = (TextView) view.findViewById(R.id.next_unlock_message);
nextUnlockTextView.setText(nextUnlockText);
AlertDialog.Builder builder = new AlertDialog.Builder(HabiticaApplication.currentActivity, R.style.AlertDialogTheme)
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AlertDialogTheme)
.setView(view)
.setCustomTitle(titleTextView)
.setPositiveButton(R.string.start_day, (dialog, which) -> {
@ -111,31 +111,22 @@ public class PopupNotificationsManager {
return false;
}
if (HabiticaApplication.currentActivity == null || HabiticaApplication.currentActivity.isFinishing()) {
return false;
if (this.seenNotifications == null) {
this.seenNotifications = new HashMap<>();
}
HabiticaApplication.currentActivity.runOnUiThread(() -> {
if (HabiticaApplication.currentActivity == null) return;
if ((HabiticaApplication.currentActivity).isFinishing()) return;
if (this.seenNotifications == null) {
this.seenNotifications = new HashMap<>();
for (Notification notification : notifications) {
if (this.seenNotifications.get(notification.getId()) != null) {
continue;
}
for (Notification notification : notifications) {
if (this.seenNotifications.get(notification.getId()) != null) {
continue;
}
if (!notification.getType().equals("LOGIN_INCENTIVE")) {
continue;
}
this.displayNotification(notification);
this.seenNotifications.put(notification.getId(), true);
if (!notification.getType().equals("LOGIN_INCENTIVE")) {
continue;
}
});
this.displayNotification(notification);
this.seenNotifications.put(notification.getId(), true);
}
return true;
}

View file

@ -1,5 +1,7 @@
package com.habitrpg.android.habitica.interactors;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@ -35,17 +37,17 @@ public class CheckClassSelectionUseCase extends UseCase<CheckClassSelectionUseCa
SelectClassEvent event = new SelectClassEvent();
event.isInitialSelection = true;
event.currentClass = user.getStats().getHabitClass();
displayClassSelectionActivity(user, event);
displayClassSelectionActivity(user, event, requestValues.activity);
}
} else {
displayClassSelectionActivity(user, requestValues.selectClassEvent);
displayClassSelectionActivity(user, requestValues.selectClassEvent, requestValues.activity);
}
return Observable.just(null);
});
}
private void displayClassSelectionActivity(User user, SelectClassEvent event) {
private void displayClassSelectionActivity(User user, SelectClassEvent event, Activity activity) {
Bundle bundle = new Bundle();
bundle.putString("size", user.getPreferences().getSize());
bundle.putString("skin", user.getPreferences().getSkin());
@ -58,21 +60,23 @@ public class CheckClassSelectionUseCase extends UseCase<CheckClassSelectionUseCa
bundle.putBoolean("isInitialSelection", event.isInitialSelection);
bundle.putString("currentClass", event.currentClass);
Intent intent = new Intent(HabiticaApplication.currentActivity, ClassSelectionActivity.class);
Intent intent = new Intent(activity, ClassSelectionActivity.class);
intent.putExtras(bundle);
HabiticaApplication.currentActivity.startActivityForResult(intent, SELECT_CLASS_RESULT);
activity.startActivityForResult(intent, SELECT_CLASS_RESULT);
}
public static final class RequestValues implements UseCase.RequestValues {
private final Activity activity;
private User user;
private SelectClassEvent selectClassEvent;
public RequestValues(User user, SelectClassEvent selectClassEvent) {
public RequestValues(User user, SelectClassEvent selectClassEvent, Activity activity) {
this.user = user;
this.selectClassEvent = selectClassEvent;
this.activity = activity;
}
}
}

View file

@ -1,5 +1,6 @@
package com.habitrpg.android.habitica.interactors;
import android.app.Activity;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
@ -43,7 +44,7 @@ public class LevelUpUseCase extends UseCase<LevelUpUseCase.RequestValues, Stats>
SuppressedModals suppressedModals = requestValues.user.getPreferences().getSuppressModals();
if (suppressedModals != null) {
if (suppressedModals.getLevelUp()) {
checkClassSelectionUseCase.observable(new CheckClassSelectionUseCase.RequestValues(requestValues.user, null))
checkClassSelectionUseCase.observable(new CheckClassSelectionUseCase.RequestValues(requestValues.user, null, requestValues.activity))
.subscribe(aVoid -> {
}, throwable -> {
});
@ -52,24 +53,24 @@ public class LevelUpUseCase extends UseCase<LevelUpUseCase.RequestValues, Stats>
}
}
View customView = requestValues.compatActivity.getLayoutInflater().inflate(R.layout.dialog_levelup, null);
View customView = requestValues.activity.getLayoutInflater().inflate(R.layout.dialog_levelup, null);
if (customView != null) {
TextView detailView = (TextView) customView.findViewById(R.id.levelupDetail);
detailView.setText(requestValues.compatActivity.getString(R.string.levelup_detail, requestValues.newLevel));
detailView.setText(requestValues.activity.getString(R.string.levelup_detail, requestValues.newLevel));
AvatarView dialogAvatarView = (AvatarView) customView.findViewById(R.id.avatarView);
dialogAvatarView.setAvatar(requestValues.user);
}
final ShareEvent event = new ShareEvent();
event.sharedMessage = requestValues.compatActivity.getString(R.string.share_levelup, requestValues.newLevel) + " https://habitica.com/social/level-up";
AvatarView avatarView = new AvatarView(requestValues.compatActivity, true, true, true);
event.sharedMessage = requestValues.activity.getString(R.string.share_levelup, requestValues.newLevel) + " https://habitica.com/social/level-up";
AvatarView avatarView = new AvatarView(requestValues.activity, true, true, true);
avatarView.setAvatar(requestValues.user);
avatarView.onAvatarImageReady(avatarImage -> event.shareImage = avatarImage);
AlertDialog alert = new AlertDialog.Builder(requestValues.compatActivity)
AlertDialog alert = new AlertDialog.Builder(requestValues.activity)
.setTitle(R.string.levelup_header)
.setView(customView)
.setPositiveButton(R.string.levelup_button, (dialog, which) -> checkClassSelectionUseCase.observable(new CheckClassSelectionUseCase.RequestValues(requestValues.user, null))
.setPositiveButton(R.string.levelup_button, (dialog, which) -> checkClassSelectionUseCase.observable(new CheckClassSelectionUseCase.RequestValues(requestValues.user, null, requestValues.activity))
.subscribe(aVoid -> {
}, throwable -> {
}))
@ -79,7 +80,7 @@ public class LevelUpUseCase extends UseCase<LevelUpUseCase.RequestValues, Stats>
})
.create();
if (!requestValues.compatActivity.isFinishing()) {
if (!requestValues.activity.isFinishing()) {
alert.show();
}
@ -91,12 +92,12 @@ public class LevelUpUseCase extends UseCase<LevelUpUseCase.RequestValues, Stats>
public static final class RequestValues implements UseCase.RequestValues {
private User user;
private int newLevel;
private AppCompatActivity compatActivity;
private Activity activity;
public RequestValues(User user, AppCompatActivity compatActivity) {
public RequestValues(User user, AppCompatActivity activity) {
this.user = user;
this.newLevel = user.getStats().getLvl();
this.compatActivity = compatActivity;
this.activity = activity;
}
}
}

View file

@ -8,6 +8,7 @@ import android.os.Build;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import com.habitrpg.android.habitica.HabiticaApplication;
@ -58,12 +59,10 @@ public class MaxHeightLinearLayout extends LinearLayout {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (HabiticaApplication.currentActivity != null) {
HabiticaApplication.currentActivity.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int height = (int) (displaymetrics.heightPixels * maxHeight);
heightMeasureSpec = Math.min(heightMeasureSpec, View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST));
}
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(displaymetrics);
int height = (int) (displaymetrics.heightPixels * maxHeight);
heightMeasureSpec = Math.min(heightMeasureSpec, View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

View file

@ -7,14 +7,18 @@ import android.os.PersistableBundle;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import com.habitrpg.android.habitica.HabiticaApplication;
import com.habitrpg.android.habitica.HabiticaBaseApplication;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.components.AppComponent;
import com.habitrpg.android.habitica.events.ShowConnectionProblemEvent;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import butterknife.ButterKnife;
import rx.subscriptions.CompositeSubscription;
@ -41,6 +45,20 @@ public abstract class BaseActivity extends AppCompatActivity {
compositeSubscription = new CompositeSubscription();
}
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
super.onStop();
}
protected abstract void injectActivity(AppComponent component);
protected void setupToolbar(Toolbar toolbar) {
@ -62,10 +80,6 @@ public abstract class BaseActivity extends AppCompatActivity {
protected void onDestroy() {
destroyed = true;
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
if (compositeSubscription != null && !compositeSubscription.isUnsubscribed()) {
compositeSubscription.unsubscribe();
}
@ -99,5 +113,19 @@ public abstract class BaseActivity extends AppCompatActivity {
startActivity(intent);
}
@Subscribe
public void onEvent(ShowConnectionProblemEvent event) {
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setTitle(event.title)
.setMessage(event.message)
.setNeutralButton(android.R.string.ok, (dialog, which) -> {
});
if (!event.title.isEmpty()) {
builder.setIcon(R.drawable.ic_warning_black);
}
builder.show();
}
}

View file

@ -240,8 +240,6 @@ public class CreateChallengeActivity extends BaseActivity {
challengeId = bundle.getString(CHALLENGE_ID_KEY, null);
}
EventBus.getDefault().register(this);
fillControls();
if (challengeId != null) {
@ -254,7 +252,6 @@ public class CreateChallengeActivity extends BaseActivity {
public void onDestroy() {
socialRepository.close();
challengeRepository.close();
EventBus.getDefault().unregister(this);
super.onDestroy();
}

View file

@ -190,9 +190,9 @@ public class FullProfileActivity extends BaseActivity {
String.format(getString(R.string.profile_message_sent_to), userName), SnackbarDisplayType.NORMAL), throwable -> {
});
UiUtils.dismissKeyboard(HabiticaApplication.currentActivity);
UiUtils.dismissKeyboard(this);
})
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> UiUtils.dismissKeyboard(HabiticaApplication.currentActivity))
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> UiUtils.dismissKeyboard(this))
.create();

View file

@ -277,7 +277,6 @@ public class MainActivity extends BaseActivity implements TutorialView.OnTutoria
MainActivity.this.setUserData(true);
}, RxErrorHandler.handleEmptyError());
EventBus.getDefault().register(this);
}
public int getStatusBarHeight() {
@ -545,7 +544,6 @@ public class MainActivity extends BaseActivity implements TutorialView.OnTutoria
@Override
public void onDestroy() {
EventBus.getDefault().unregister(this);
userRepository.close();
tagRepository.close();
inventoryRepository.close();
@ -800,10 +798,8 @@ public class MainActivity extends BaseActivity implements TutorialView.OnTutoria
@Subscribe
public void displayClassSelectionActivity(SelectClassEvent event) {
checkClassSelectionUseCase.observable(new CheckClassSelectionUseCase.RequestValues(user, event))
.subscribe(aVoid -> {
}, throwable -> {
});
checkClassSelectionUseCase.observable(new CheckClassSelectionUseCase.RequestValues(user, event, this))
.subscribe(aVoid -> {}, RxErrorHandler.handleEmptyError());
}
private void displayTutorialStep(TutorialStep step, String text, boolean canBeDeferred) {

View file

@ -125,18 +125,6 @@ public class SetupActivity extends BaseActivity implements ViewPager.OnPageChang
component.inject(this);
}
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
@Override
protected void onDestroy() {
userRepository.close();

View file

@ -1,5 +1,6 @@
package com.habitrpg.android.habitica.ui.adapter.social;
import android.content.Context;
import android.content.res.Resources;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.RecyclerView;
@ -76,7 +77,7 @@ public class AchievementAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
return itemList == null ? 0 : itemList.size();
}
class AchievementViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
static class AchievementViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
Achievement achievement;
@BindView(R.id.achievement_drawee)
@ -91,14 +92,14 @@ public class AchievementAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
@BindView(R.id.achievement_item_layout)
LinearLayout item_layout;
Resources resources;
Context context;
AchievementViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
item_layout = (LinearLayout) itemView;
resources = itemView.getResources();
context = itemView.getContext();
item_layout.setClickable(true);
item_layout.setOnClickListener(this);
@ -116,7 +117,6 @@ public class AchievementAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
})
.build());
this.achievement = item;
titleView.setText(item.title);
@ -130,7 +130,7 @@ public class AchievementAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
@Override
public void onClick(View view) {
AlertDialog.Builder b = new AlertDialog.Builder(HabiticaApplication.currentActivity);
AlertDialog.Builder b = new AlertDialog.Builder(context);
View customView = LayoutInflater.from(itemView.getContext())
.inflate(R.layout.dialog_achievement_details, null);

View file

@ -67,10 +67,6 @@ public class PopupNotificationsManagerTest {
@Test
// @TODO: Eventually, we should have a list of implemented notifications and only use those
public void itShouldNotDisplayNotificationsThatAreNotLoginIncentives() {
Activity activity;
activity = Robolectric.buildActivity(Activity.class).create().get();
HabiticaApplication.currentActivity = activity;
List<Notification> notifications = new ArrayList<>();
Notification notification = new Notification();
@ -89,10 +85,6 @@ public class PopupNotificationsManagerTest {
@Test
public void itShouldDisplayADialogueForANotification() {
Activity activity;
activity = Robolectric.buildActivity(Activity.class).create().get();
HabiticaApplication.currentActivity = activity;
String testTitle = "Test Title";
List<Notification> notifications = new ArrayList<>();
@ -117,10 +109,6 @@ public class PopupNotificationsManagerTest {
@Test
public void itShouldNotDisplayANotificationTwice() {
Activity activity;
activity = Robolectric.buildActivity(Activity.class).create().get();
HabiticaApplication.currentActivity = activity;
String testTitle = "Test Title";
List<Notification> notifications = new ArrayList<>();