Volley request leaks across activity/fragment boundaries should no longer be able to occur.

Also, the singleton allows contexts to be cleaned up instead of holding onto a dead reference.
main
Vavassor 8 years ago
parent 46fe328967
commit c1d4bdbdfb
  1. 12
      app/src/main/java/com/keylesspalace/tusky/AccountActivity.java
  2. 10
      app/src/main/java/com/keylesspalace/tusky/AccountFragment.java
  3. 3
      app/src/main/java/com/keylesspalace/tusky/MainActivity.java
  4. 9
      app/src/main/java/com/keylesspalace/tusky/NotificationsFragment.java
  5. 9
      app/src/main/java/com/keylesspalace/tusky/PullNotificationService.java
  6. 9
      app/src/main/java/com/keylesspalace/tusky/SFragment.java
  7. 9
      app/src/main/java/com/keylesspalace/tusky/TimelineFragment.java
  8. 10
      app/src/main/java/com/keylesspalace/tusky/VolleySingleton.java

@ -31,7 +31,6 @@ import android.util.TypedValue;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import com.android.volley.AuthFailureError; import com.android.volley.AuthFailureError;
@ -51,7 +50,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class AccountActivity extends BaseActivity { public class AccountActivity extends BaseActivity {
private static final String TAG = "AccountActivity"; // logging tag private static final String TAG = "AccountActivity"; // Volley request tag and logging tag
private String domain; private String domain;
private String accessToken; private String accessToken;
@ -121,6 +120,12 @@ public class AccountActivity extends BaseActivity {
} }
} }
@Override
protected void onDestroy() {
VolleySingleton.getInstance(this).cancelAll(TAG);
super.onDestroy();
}
private void obtainAccount() { private void obtainAccount() {
String endpoint = String.format(getString(R.string.endpoint_accounts), accountId); String endpoint = String.format(getString(R.string.endpoint_accounts), accountId);
String url = "https://" + domain + endpoint; String url = "https://" + domain + endpoint;
@ -151,6 +156,7 @@ public class AccountActivity extends BaseActivity {
return headers; return headers;
} }
}; };
request.setTag(TAG);
VolleySingleton.getInstance(this).addToRequestQueue(request); VolleySingleton.getInstance(this).addToRequestQueue(request);
} }
@ -241,6 +247,7 @@ public class AccountActivity extends BaseActivity {
return headers; return headers;
} }
}; };
request.setTag(TAG);
VolleySingleton.getInstance(this).addToRequestQueue(request); VolleySingleton.getInstance(this).addToRequestQueue(request);
} }
@ -301,6 +308,7 @@ public class AccountActivity extends BaseActivity {
return headers; return headers;
} }
}; };
request.setTag(TAG);
VolleySingleton.getInstance(this).addToRequestQueue(request); VolleySingleton.getInstance(this).addToRequestQueue(request);
} }

@ -46,7 +46,7 @@ import java.util.Map;
public class AccountFragment extends Fragment implements AccountActionListener, public class AccountFragment extends Fragment implements AccountActionListener,
FooterActionListener { FooterActionListener {
private static final String TAG = "Account"; // logging tag private static final String TAG = "Account"; // logging tag and Volley request tag
public enum Type { public enum Type {
FOLLOWS, FOLLOWS,
@ -94,6 +94,12 @@ public class AccountFragment extends Fragment implements AccountActionListener,
accessToken = preferences.getString("accessToken", null); accessToken = preferences.getString("accessToken", null);
} }
@Override
public void onDestroy() {
VolleySingleton.getInstance(getContext()).cancelAll(TAG);
super.onDestroy();
}
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@ -211,6 +217,7 @@ public class AccountFragment extends Fragment implements AccountActionListener,
return headers; return headers;
} }
}; };
request.setTag(TAG);
VolleySingleton.getInstance(getContext()).addToRequestQueue(request); VolleySingleton.getInstance(getContext()).addToRequestQueue(request);
} }
@ -300,6 +307,7 @@ public class AccountFragment extends Fragment implements AccountActionListener,
return headers; return headers;
} }
}; };
request.setTag(TAG);
VolleySingleton.getInstance(getContext()).addToRequestQueue(request); VolleySingleton.getInstance(getContext()).addToRequestQueue(request);
} }

@ -43,7 +43,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class MainActivity extends BaseActivity { public class MainActivity extends BaseActivity {
private static final String TAG = "MainActivity"; // logging tag private static final String TAG = "MainActivity"; // logging tag and Volley request tag
private AlarmManager alarmManager; private AlarmManager alarmManager;
private PendingIntent serviceAlarmIntent; private PendingIntent serviceAlarmIntent;
@ -141,6 +141,7 @@ public class MainActivity extends BaseActivity {
return headers; return headers;
} }
}; };
request.setTag(TAG);
VolleySingleton.getInstance(this).addToRequestQueue(request); VolleySingleton.getInstance(this).addToRequestQueue(request);
} }
} }

@ -42,7 +42,7 @@ import java.util.Map;
public class NotificationsFragment extends SFragment implements public class NotificationsFragment extends SFragment implements
SwipeRefreshLayout.OnRefreshListener, StatusActionListener, FooterActionListener { SwipeRefreshLayout.OnRefreshListener, StatusActionListener, FooterActionListener {
private static final String TAG = "Notifications"; // logging tag private static final String TAG = "Notifications"; // logging tag and Volley request tag
private SwipeRefreshLayout swipeRefreshLayout; private SwipeRefreshLayout swipeRefreshLayout;
private RecyclerView recyclerView; private RecyclerView recyclerView;
@ -58,6 +58,12 @@ public class NotificationsFragment extends SFragment implements
return fragment; return fragment;
} }
@Override
public void onDestroy() {
VolleySingleton.getInstance(getContext()).cancelAll(TAG);
super.onDestroy();
}
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@ -157,6 +163,7 @@ public class NotificationsFragment extends SFragment implements
return headers; return headers;
} }
}; };
request.setTag(TAG);
VolleySingleton.getInstance(getContext()).addToRequestQueue(request); VolleySingleton.getInstance(getContext()).addToRequestQueue(request);
} }

@ -44,12 +44,18 @@ import java.util.Map;
public class PullNotificationService extends IntentService { public class PullNotificationService extends IntentService {
private static final int NOTIFY_ID = 6; // This is an arbitrary number. private static final int NOTIFY_ID = 6; // This is an arbitrary number.
private static final String TAG = "PullNotifications"; private static final String TAG = "PullNotifications"; // logging tag and Volley request tag
public PullNotificationService() { public PullNotificationService() {
super("Tusky Pull Notification Service"); super("Tusky Pull Notification Service");
} }
@Override
public void onDestroy() {
VolleySingleton.getInstance(this).cancelAll(TAG);
super.onDestroy();
}
@Override @Override
protected void onHandleIntent(Intent intent) { protected void onHandleIntent(Intent intent) {
SharedPreferences preferences = getSharedPreferences( SharedPreferences preferences = getSharedPreferences(
@ -94,6 +100,7 @@ public class PullNotificationService extends IntentService {
return headers; return headers;
} }
}; };
request.setTag(TAG);
VolleySingleton.getInstance(this).addToRequestQueue(request); VolleySingleton.getInstance(this).addToRequestQueue(request);
} }

@ -47,7 +47,7 @@ import java.util.Map;
* overlap functionality. So, I'm momentarily leaving it and hopefully working on those will clear * overlap functionality. So, I'm momentarily leaving it and hopefully working on those will clear
* up what needs to be where. */ * up what needs to be where. */
public class SFragment extends Fragment { public class SFragment extends Fragment {
private static final String TAG = "SFragment"; // logging tag private static final String TAG = "SFragment"; // logging tag and Volley request tag
protected String domain; protected String domain;
protected String accessToken; protected String accessToken;
@ -66,6 +66,12 @@ public class SFragment extends Fragment {
loggedInUsername = preferences.getString("loggedInAccountUsername", null); loggedInUsername = preferences.getString("loggedInAccountUsername", null);
} }
@Override
public void onDestroy() {
VolleySingleton.getInstance(getContext()).cancelAll(TAG);
super.onDestroy();
}
protected void sendRequest( protected void sendRequest(
int method, String endpoint, JSONObject parameters, int method, String endpoint, JSONObject parameters,
@Nullable Response.Listener<JSONObject> responseListener) { @Nullable Response.Listener<JSONObject> responseListener) {
@ -92,6 +98,7 @@ public class SFragment extends Fragment {
return headers; return headers;
} }
}; };
request.setTag(TAG);
VolleySingleton.getInstance(getContext()).addToRequestQueue(request); VolleySingleton.getInstance(getContext()).addToRequestQueue(request);
} }

@ -41,7 +41,7 @@ import java.util.Map;
public class TimelineFragment extends SFragment implements public class TimelineFragment extends SFragment implements
SwipeRefreshLayout.OnRefreshListener, StatusActionListener, FooterActionListener { SwipeRefreshLayout.OnRefreshListener, StatusActionListener, FooterActionListener {
private static final String TAG = "Timeline"; // logging tag private static final String TAG = "Timeline"; // logging tag and Volley request tag
public enum Kind { public enum Kind {
HOME, HOME,
@ -78,6 +78,12 @@ public class TimelineFragment extends SFragment implements
return fragment; return fragment;
} }
@Override
public void onDestroy() {
VolleySingleton.getInstance(getContext()).cancelAll(TAG);
super.onDestroy();
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
@ -221,6 +227,7 @@ public class TimelineFragment extends SFragment implements
return headers; return headers;
} }
}; };
request.setTag(TAG);
VolleySingleton.getInstance(getContext()).addToRequestQueue(request); VolleySingleton.getInstance(getContext()).addToRequestQueue(request);
} }

@ -24,14 +24,18 @@ import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader; import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley; import com.android.volley.toolbox.Volley;
import java.lang.ref.WeakReference;
public class VolleySingleton { public class VolleySingleton {
private static VolleySingleton instance; private static VolleySingleton instance;
private RequestQueue requestQueue; private RequestQueue requestQueue;
private ImageLoader imageLoader; private ImageLoader imageLoader;
private static Context context; /* This is a weak reference to account for the case where it might be held onto beyond the
* lifetime of the Activity/Fragment/Service, so it can be cleaned up. */
private static WeakReference<Context> context;
private VolleySingleton(Context context) { private VolleySingleton(Context context) {
VolleySingleton.context = context; VolleySingleton.context = new WeakReference<>(context);
requestQueue = getRequestQueue(); requestQueue = getRequestQueue();
imageLoader = new ImageLoader(requestQueue, imageLoader = new ImageLoader(requestQueue,
new ImageLoader.ImageCache() { new ImageLoader.ImageCache() {
@ -60,7 +64,7 @@ public class VolleySingleton {
if (requestQueue == null) { if (requestQueue == null) {
/* getApplicationContext() is key, it keeps you from leaking the /* getApplicationContext() is key, it keeps you from leaking the
* Activity or BroadcastReceiver if someone passes one in. */ * Activity or BroadcastReceiver if someone passes one in. */
requestQueue= Volley.newRequestQueue(context.getApplicationContext()); requestQueue= Volley.newRequestQueue(context.get().getApplicationContext());
} }
return requestQueue; return requestQueue;
} }

Loading…
Cancel
Save