Fix memory leak(s). (#2674)

This commit is contained in:
Dmitry Brant 2019-03-19 15:59:33 -04:00 committed by Adam Jones
parent d1ae88ca8b
commit 351109440f
6 changed files with 24 additions and 37 deletions

View file

@ -1,6 +1,5 @@
package fr.free.nrw.commons.category; package fr.free.nrw.commons.category;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -22,12 +21,10 @@ import fr.free.nrw.commons.R;
*/ */
public class GridViewAdapter extends ArrayAdapter { public class GridViewAdapter extends ArrayAdapter {
private Context context;
private List<Media> data; private List<Media> data;
public GridViewAdapter(Context context, int layoutResourceId, List<Media> data) { public GridViewAdapter(Context context, int layoutResourceId, List<Media> data) {
super(context, layoutResourceId, data); super(context, layoutResourceId, data);
this.context = context;
this.data = data; this.data = data;
} }
@ -81,8 +78,7 @@ public class GridViewAdapter extends ArrayAdapter {
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) { if (convertView == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater(); convertView = LayoutInflater.from(getContext()).inflate(R.layout.layout_category_images, null);
convertView = inflater.inflate(R.layout.layout_category_images, null);
} }
Media item = data.get(position); Media item = data.get(position);
@ -102,7 +98,7 @@ public class GridViewAdapter extends ArrayAdapter {
*/ */
private void setAuthorView(Media item, TextView author) { private void setAuthorView(Media item, TextView author) {
if (!TextUtils.isEmpty(item.getCreator())) { if (!TextUtils.isEmpty(item.getCreator())) {
String uploadedByTemplate = context.getString(R.string.image_uploaded_by); String uploadedByTemplate = getContext().getString(R.string.image_uploaded_by);
String uploadedBy = String.format(Locale.getDefault(), uploadedByTemplate, item.getCreator()); String uploadedBy = String.format(Locale.getDefault(), uploadedByTemplate, item.getCreator());
author.setText(uploadedBy); author.setText(uploadedBy);

View file

@ -87,6 +87,7 @@ public class ContributionsFragment
@Inject NearbyController nearbyController; @Inject NearbyController nearbyController;
@Inject OkHttpJsonApiClient okHttpJsonApiClient; @Inject OkHttpJsonApiClient okHttpJsonApiClient;
@Inject CampaignsPresenter presenter; @Inject CampaignsPresenter presenter;
@Inject LocationServiceManager locationManager;
private ArrayList<DataSetObserver> observersWaitingForLoad = new ArrayList<>(); private ArrayList<DataSetObserver> observersWaitingForLoad = new ArrayList<>();
private UploadService uploadService; private UploadService uploadService;
@ -105,8 +106,6 @@ public class ContributionsFragment
private LatLng curLatLng; private LatLng curLatLng;
private boolean firstLocationUpdate = true; private boolean firstLocationUpdate = true;
public LocationServiceManager locationManager;
private boolean isFragmentAttachedBefore = false; private boolean isFragmentAttachedBefore = false;
private View checkBoxView; private View checkBoxView;
private CheckBox checkBox; private CheckBox checkBox;
@ -496,7 +495,6 @@ public class ContributionsFragment
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
locationManager = new LocationServiceManager(getActivity());
firstLocationUpdate = true; firstLocationUpdate = true;
locationManager.addLocationListener(this); locationManager.addLocationListener(this);
@ -546,7 +544,7 @@ public class ContributionsFragment
private void checkLocationPermission() { private void checkLocationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (locationManager.isLocationPermissionGranted()) { if (locationManager.isLocationPermissionGranted(requireContext())) {
nearbyNotificationCardView.permissionType = NearbyNotificationCardView.PermissionType.NO_PERMISSION_NEEDED; nearbyNotificationCardView.permissionType = NearbyNotificationCardView.PermissionType.NO_PERMISSION_NEEDED;
locationManager.registerLocationManager(); locationManager.registerLocationManager();
} else { } else {
@ -638,8 +636,6 @@ public class ContributionsFragment
getChildFragmentManager().removeOnBackStackChangedListener(this); getChildFragmentManager().removeOnBackStackChangedListener(this);
locationManager.unregisterLocationManager(); locationManager.unregisterLocationManager();
locationManager.removeLocationListener(this); locationManager.removeLocationListener(this);
// Try to prevent a possible NPE
locationManager.context = null;
super.onDestroy(); super.onDestroy();
if (isUploadServiceConnected) { if (isUploadServiceConnected) {

View file

@ -2,6 +2,8 @@ package fr.free.nrw.commons.contributions;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import androidx.annotation.NonNull;
import androidx.cursoradapter.widget.CursorAdapter; import androidx.cursoradapter.widget.CursorAdapter;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -20,14 +22,12 @@ class ContributionsListAdapter extends CursorAdapter {
private final ContributionDao contributionDao; private final ContributionDao contributionDao;
private UploadService uploadService; private UploadService uploadService;
private Context context;
public ContributionsListAdapter(Context context, public ContributionsListAdapter(Context context,
Cursor c, Cursor c,
int flags, int flags,
ContributionDao contributionDao) { ContributionDao contributionDao) {
super(context, c, flags); super(context, c, flags);
this.context = context;
this.contributionDao = contributionDao; this.contributionDao = contributionDao;
} }
@ -53,12 +53,12 @@ class ContributionsListAdapter extends CursorAdapter {
new DisplayableContribution.ContributionActions() { new DisplayableContribution.ContributionActions() {
@Override @Override
public void retryUpload() { public void retryUpload() {
ContributionsListAdapter.this.retryUpload(contribution); ContributionsListAdapter.this.retryUpload(view.getContext(), contribution);
} }
@Override @Override
public void deleteUpload() { public void deleteUpload() {
ContributionsListAdapter.this.deleteUpload(contribution); ContributionsListAdapter.this.deleteUpload(view.getContext(), contribution);
} }
}); });
views.bindModel(context, displayableContribution); views.bindModel(context, displayableContribution);
@ -68,7 +68,7 @@ class ContributionsListAdapter extends CursorAdapter {
* Retry upload when it is failed * Retry upload when it is failed
* @param contribution contribution to be retried * @param contribution contribution to be retried
*/ */
private void retryUpload(Contribution contribution) { private void retryUpload(@NonNull Context context, Contribution contribution) {
if (NetworkUtils.isInternetConnectionEstablished(context)) { if (NetworkUtils.isInternetConnectionEstablished(context)) {
if (contribution.getState() == STATE_FAILED if (contribution.getState() == STATE_FAILED
&& uploadService!= null) { && uploadService!= null) {
@ -87,7 +87,7 @@ class ContributionsListAdapter extends CursorAdapter {
* Delete a failed upload attempt * Delete a failed upload attempt
* @param contribution contribution to be deleted * @param contribution contribution to be deleted
*/ */
private void deleteUpload(Contribution contribution) { private void deleteUpload(@NonNull Context context, Contribution contribution) {
if (NetworkUtils.isInternetConnectionEstablished(context)) { if (NetworkUtils.isInternetConnectionEstablished(context)) {
if (contribution.getState() == STATE_FAILED) { if (contribution.getState() == STATE_FAILED) {
Timber.d("Deleting failed contrib %s", contribution.toString()); Timber.d("Deleting failed contrib %s", contribution.toString());

View file

@ -9,6 +9,8 @@ import android.location.Location;
import android.location.LocationListener; import android.location.LocationListener;
import android.location.LocationManager; import android.location.LocationManager;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
@ -26,13 +28,12 @@ public class LocationServiceManager implements LocationListener {
private static final long MIN_LOCATION_UPDATE_REQUEST_TIME_IN_MILLIS = 2 * 60 * 100; private static final long MIN_LOCATION_UPDATE_REQUEST_TIME_IN_MILLIS = 2 * 60 * 100;
private static final long MIN_LOCATION_UPDATE_REQUEST_DISTANCE_IN_METERS = 10; private static final long MIN_LOCATION_UPDATE_REQUEST_DISTANCE_IN_METERS = 10;
public Context context;
private LocationManager locationManager; private LocationManager locationManager;
private Location lastLocation; private Location lastLocation;
//private Location lastLocationDuplicate; // Will be used for nearby card view on contributions activity //private Location lastLocationDuplicate; // Will be used for nearby card view on contributions activity
private final List<LocationUpdateListener> locationListeners = new CopyOnWriteArrayList<>(); private final List<LocationUpdateListener> locationListeners = new CopyOnWriteArrayList<>();
private boolean isLocationManagerRegistered = false; private boolean isLocationManagerRegistered = false;
public Set<Activity> locationExplanationDisplayed = new HashSet<>(); private Set<Activity> locationExplanationDisplayed = new HashSet<>();
/** /**
* Constructs a new instance of LocationServiceManager. * Constructs a new instance of LocationServiceManager.
@ -40,7 +41,6 @@ public class LocationServiceManager implements LocationListener {
* @param context the context * @param context the context
*/ */
public LocationServiceManager(Context context) { public LocationServiceManager(Context context) {
this.context = context;
this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
} }
@ -57,7 +57,7 @@ public class LocationServiceManager implements LocationListener {
* Returns whether the location permission is granted. * Returns whether the location permission is granted.
* @return true if the location permission is granted * @return true if the location permission is granted
*/ */
public boolean isLocationPermissionGranted() { public boolean isLocationPermissionGranted(@NonNull Context context) {
return ContextCompat.checkSelfPermission(context, return ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
} }
@ -101,8 +101,8 @@ public class LocationServiceManager implements LocationListener {
* @return last known LatLng * @return last known LatLng
*/ */
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
public LatLng getLKL() { public LatLng getLKL(@NonNull Context context) {
if (isLocationPermissionGranted()) { if (isLocationPermissionGranted(context)) {
Location lastKL = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); Location lastKL = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (lastKL == null) { if (lastKL == null) {
lastKL = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); lastKL = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
@ -225,6 +225,7 @@ public class LocationServiceManager implements LocationListener {
*/ */
public void unregisterLocationManager() { public void unregisterLocationManager() {
isLocationManagerRegistered = false; isLocationManagerRegistered = false;
locationExplanationDisplayed.clear();
try { try {
locationManager.removeUpdates(this); locationManager.removeUpdates(this);
} catch (SecurityException e) { } catch (SecurityException e) {

View file

@ -572,7 +572,7 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
*/ */
private void registerLocationUpdates() { private void registerLocationUpdates() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (locationManager.isLocationPermissionGranted()) { if (locationManager.isLocationPermissionGranted(requireContext())) {
locationManager.registerLocationManager(); locationManager.registerLocationManager();
} else { } else {
// Should we show an explanation? // Should we show an explanation?
@ -666,7 +666,7 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
private void checkLocationPermission() { private void checkLocationPermission() {
Timber.d("Checking location permission"); Timber.d("Checking location permission");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (locationManager.isLocationPermissionGranted()) { if (locationManager.isLocationPermissionGranted(requireContext())) {
refreshView(LOCATION_SIGNIFICANTLY_CHANGED); refreshView(LOCATION_SIGNIFICANTLY_CHANGED);
} else { } else {
// Should we show an explanation? // Should we show an explanation?

View file

@ -21,9 +21,6 @@ import timber.log.Timber;
* Custom card view for nearby notification card view on main screen, above contributions list * Custom card view for nearby notification card view on main screen, above contributions list
*/ */
public class NearbyNotificationCardView extends SwipableCardView { public class NearbyNotificationCardView extends SwipableCardView {
private Context context;
private Button permissionRequestButton; private Button permissionRequestButton;
private LinearLayout contentLayout; private LinearLayout contentLayout;
private TextView notificationTitle; private TextView notificationTitle;
@ -37,21 +34,18 @@ public class NearbyNotificationCardView extends SwipableCardView {
public NearbyNotificationCardView(@NonNull Context context) { public NearbyNotificationCardView(@NonNull Context context) {
super(context); super(context);
this.context = context;
cardViewVisibilityState = CardViewVisibilityState.INVISIBLE; cardViewVisibilityState = CardViewVisibilityState.INVISIBLE;
init(); init();
} }
public NearbyNotificationCardView(@NonNull Context context, @Nullable AttributeSet attrs) { public NearbyNotificationCardView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs); super(context, attrs);
this.context = context;
cardViewVisibilityState = CardViewVisibilityState.INVISIBLE; cardViewVisibilityState = CardViewVisibilityState.INVISIBLE;
init(); init();
} }
public NearbyNotificationCardView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { public NearbyNotificationCardView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
this.context = context;
cardViewVisibilityState = CardViewVisibilityState.INVISIBLE; cardViewVisibilityState = CardViewVisibilityState.INVISIBLE;
init(); init();
} }
@ -60,7 +54,7 @@ public class NearbyNotificationCardView extends SwipableCardView {
* Initializes views and action listeners * Initializes views and action listeners
*/ */
private void init() { private void init() {
View rootView = inflate(context, R.layout.nearby_card_view, this); View rootView = inflate(getContext(), R.layout.nearby_card_view, this);
permissionRequestButton = rootView.findViewById(R.id.permission_request_button); permissionRequestButton = rootView.findViewById(R.id.permission_request_button);
contentLayout = rootView.findViewById(R.id.content_layout); contentLayout = rootView.findViewById(R.id.content_layout);
@ -79,7 +73,7 @@ public class NearbyNotificationCardView extends SwipableCardView {
protected void onAttachedToWindow() { protected void onAttachedToWindow() {
super.onAttachedToWindow(); super.onAttachedToWindow();
// If you don't setVisibility after getting layout params, then you will se an empty space in place of nearby NotificationCardView // If you don't setVisibility after getting layout params, then you will se an empty space in place of nearby NotificationCardView
if (((MainActivity)context).defaultKvStore.getBoolean("displayNearbyCardView", true) && this.cardViewVisibilityState == NearbyNotificationCardView.CardViewVisibilityState.READY) { if (((MainActivity)getContext()).defaultKvStore.getBoolean("displayNearbyCardView", true) && this.cardViewVisibilityState == NearbyNotificationCardView.CardViewVisibilityState.READY) {
this.setVisibility(VISIBLE); this.setVisibility(VISIBLE);
} else { } else {
this.setVisibility(GONE); this.setVisibility(GONE);
@ -88,14 +82,14 @@ public class NearbyNotificationCardView extends SwipableCardView {
private void setActionListeners() { private void setActionListeners() {
this.setOnClickListener(view -> ((MainActivity)context).viewPager.setCurrentItem(1)); this.setOnClickListener(view -> ((MainActivity)getContext()).viewPager.setCurrentItem(1));
} }
@Override public boolean onSwipe(View view) { @Override public boolean onSwipe(View view) {
view.setVisibility(GONE); view.setVisibility(GONE);
// Save shared preference for nearby card view accordingly // Save shared preference for nearby card view accordingly
((MainActivity) context).defaultKvStore.putBoolean("displayNearbyCardView", false); ((MainActivity) getContext()).defaultKvStore.putBoolean("displayNearbyCardView", false);
ViewUtil.showLongToast(context, ViewUtil.showLongToast(getContext(),
getResources().getString(R.string.nearby_notification_dismiss_message)); getResources().getString(R.string.nearby_notification_dismiss_message));
return true; return true;
} }