Weak reference being nullified - android

I'm using a weak reference inside a static Handler to avoid memory leaks, however, sometimes this reference is being nullified, I cannot understand why.
The static handler is defined inside a repository class that has a method to perform an operation in the background, receives a callback to notify the caller when it's done:
public class MyRepository {
public void performOperation(ContentResolver cr, RepositoryCallback callback) {
MyHandler handler = new MyHandler(cr, callback);
handler.startQuery(...)
}
interface RepositoryCallback {
void onSuccess(MyModel model);
}
// Handler class code here
}
The code of the handler is the following:
private static class MyHandler extends AsyncQueryHandler {
private final WeakReference<RepositoryCallback> weakCallback;
public MyHandler(ContentResolver cr, RepositoryCallback callback) {
super(cr);
this.weakCallback = new WeakReference<>(callback);
}
#Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
RepositoryCallback callback = this.weakCallback.get();
if (callback != null) { // --> Here sometimes it is null
// Do some stuff with the cursor to create MyModel
callback.onSuccess(model);
}
}
}
For some reason, this.weakCallback.get() sometimes is null, and I'm trying to understand why.
The activity code looks like this:
public class MyActivity extends AppCompatActivity {
public void loadModel() {
showLoadingView();
myRepository.performOperation(context.getContentResolver(), new RepositoryCallback() {
#Override
public void onSuccess(MyModel model) {
hideLoadingView();
// Do something with model
}
});
}
}
As you can see I'm creating an anonymous class for the callback, but nobody is holding a reference to it.
Is this the cause of the weak reference being nullified?
Thanks.

That's the "classical" bug associated with weak references.
If the Observable holds the only reference to the Observer, and this reference is weak, then it can be cleared and Observer be garbage collected.
Since you're using anonymous class, Observable will hold the only reference to it, therefore it will be cleared.
As a side note - in my entire experience of Android development, whenever I saw devs using weak references, it always was a code smell. Usually it indicates that either devs don't understand how weak references work, or they don't trust their own code.
A good rule of thumb is that you should never use weak references.
EDIT:
I think that Handler is an anti-pattern in general. You can read more about this in this Reddit thread. There is also a thread there in which I helped one dev to see how he can get rid of HandlerThread in his codebase.
On the other hand, Jake Wharton disagreed with my statements.
Take what you'd like from there, but, in general, I would say that having a static Handler is anti-pattern for sure.
If you are worried about AndroidStudion warnings, then just remember that Google are responsible for AsyncTask and Loaders. This warning is not just useless, but actually bad. They should've made it you should not use static Hadlers.
If all you need is to offload work to BG thread and then get a callback on UI thread then you would be much better off with something like RxJava. Or even the evil AsyncTask.
I guess you're using AsyncQueryHandler in order to access ContentProvider. This is too a very controversial approach. If you don't need to share data with other apps, you might be better off by using some ORM that handles the multithreading for you.

Related

Use of static member in Android Application bad?

I've stumpled upon an Android Application Class which implements the Singleton pattern and bind a static object to it.
public class App extends Application
{
public static BigObject myObj;
private static App instance;
public static App getInstance()
{
return instance;
}
#Override
public void onCreate() {
super.onCreate();
instance = this;
myObj = new BigObject(this);
}
}
Are there any problems with this implementation, regarding performance, memory leaks or maybe Exceptions, when getInstance().myObj.something() is called form BroadcastReceiver or Service?
The only drawback I see is somewhat ugly code, using dependency injection would be better. I don't know, but if OS guarantees that all other components will be launched after Application::onCreate than there is no issues. Even non-main threads will not cache value of bigObject. But if you want set value of bigObject after onCreate, or it's creation takes long time you can face issues with data racing or slow startup.
I don't see any problems with this implementation. The Application object is basically a singleton.

AsyncQueryHandler with ContentProvider is necessary?

my question is very simple: if I insert or update or delete a single row in a SQLLite database through a ContentProvider from a UIThread, is the AsyncQueryHandler's implementation necessary?
I know that the best practice is to implement the CRUD operations in a async task but also that the CRUD stantment about one row is not so heavy to perform.
Infact also Android Studio does not alert his stantment that shouldn't run on UI Thread and all the guides that I found on the net about the ContentProvider don't mention the ASyncQueryHandler. All the CRUD operations are performed on the UI Thread invoked directly the ContentProvider.
It's probably best to just go the Async route for all your ContentProvider operations. I know it can be a pain but consider this:
Your simple, one-row insert that usually takes a few milliseconds having to wait for a larger transaction to complete. Maybe you're busy in a SyncAdapter doing lots of stuff? Your little tiny insert suddenly takes much longer and might even cause an ANR.
I know it's a pretty low chance, but the chance is still there. Much better to just accept the boilerplate code and get on with it ;-)
Example boilerplate code to paste into an activity class:
private class UpdateHandler extends AsyncQueryHandler {
private final WeakReference<YourActivityClass> mActivityRef;
public UpdateHandler(YourActivityClass activity, ContentResolver cr) {
super(cr);
mActivityRef = new WeakReference<>(activity); // do a weak reference incase the update takes ages and the activity gets destroyed during
}
#Override
protected void onUpdateComplete(int token, Object cookie, int result) {
super.onUpdateComplete(token, cookie, result);
YourActivityClass exampleActivity = mActivityRef.get();
if (exampleActivity != null) {
exampleActivity .onUpdateCompleted(token);
}
}
}
public void saveStuffToDatabase() {
// do some stuff like show a progress bar or whatever
// actually do the update operation
new UpdateHandler(this, getContentResolver()).startUpdate(
0, // this will be passed to "onUpdatedComplete" in the updateHandler
null, // so will this!
uri,
values
);
}
private void onUpdateCompleted(int token) {
// this runs in the main thread after the update you started in saveStuffToDatabase() is complete
}

Prevent Thread from being garbage collected, and prevent context leak

I want to customize the process of obtaining the authentication token from AccountManager.
AccountManager has getAuthToken() and getAuthTokenByFeatures() methods, but I want to implement a customized flow, which includes switching between activities, etc...
I wanted to implement it the following way:
public AccountManagerFuture<Bundle> getAuthTokenForActiveAccount() {
GetAuthTokenForActiveAccountFuture future =
new GetAuthTokenForActiveAccountFuture(MyActivity.this);
future.start();
return future;
}
Using the following nested class in my activity:
private static class GetAuthTokenForActiveAccountFuture extends Thread implements
AccountManagerFuture<Bundle> {
private final Activity mActivity;
public GetAuthTokenForActiveAccountFuture(Activity activity) {
mActivity = activity;
// TODO: write this method
}
#Override
public void run() {
// TODO: write this method
}
#Override
public boolean cancel(boolean b) {
// TODO: write this method
return false;
}
#Override
public boolean isCancelled() {
// TODO: write this method
return false;
}
#Override
public boolean isDone() {
// TODO: write this method
return false;
}
#Override
public Bundle getResult() throws
OperationCanceledException, IOException, AuthenticatorException {
return internalGetResult(null, null);
}
#Override
public Bundle getResult(long timeout, TimeUnit timeUnit) throws
OperationCanceledException, IOException, AuthenticatorException {
return internalGetResult(timeout, timeUnit);
}
private Bundle internalGetResult(Long timeout, TimeUnit timeUnit) throws
OperationCanceledException, IOException, AuthenticatorException {
// TODO: write this method
return null;
}
}
My idea was that I could create my own AccountManagerFuture object and "unblock" its getResult() method only after all the required steps were done (some of them include activity switching).
I got two issues here:
I need Activity context for switching to other activities when necessary, but the Activity I pass into constructor should be destroyed when I switch to other activity, but it won't because my Thread holds a reference to it... So I create a memory leak here. It seems that making the inner class non-static won't resolve this issue - the reference returned from getAuthTokenForActiveAccount() will still prevent from the outer Activity to be garbage collected. Is there any way I could achieve what I try to do without leaking the context?
Thread is eligible for garbage collection once its run() method returns, right? But in my case I want this thread to stick around because it also functions as AccountManagerFuture - it should be kept in memory until all references to it are gone. My question is this: is it enough to keep a (strong) reference to Thread for preventing it from being garbage collected? If not, how could I force this Thread to stick around until all references are gone?
At first. Making your Future non-static would make it having an implicit reference to its outer class - the Activity.
You should used some form of indirect communication between your future and your Activities..You should probably move it into Service anyway - did you think about any configuration change? Where do you hold the reference for your Future?
I would advice you to either move your flow into fragments - then you wouldn't have to switch Activities - and place your future into a retained Fragment (to make it survive orientation change) or move it into a background service and communicate with your activities (or any sort of UI) through broadcastreceivers or event bus.
Thread won't be garbage collected as long as you keep some reference to it. No matter if its finished or not. I think that you are confusing this with the fact that a running Thread won't be garbage collected even without keeping references to it. (I guess tha JVM does so, but I have to admit I'm not sure about this)
issue 1 solution:
use private WeakReference mContextHolder. when you need context - call mContextHolder.get() and check on null;
issue 2 solution:
Use Service which will host your threads.

How to implement a "fire-and-forget" async call in Android?

I am reviewing/cleaning up some Android code. The code did some "asynchronous" network and data operations using this pattern:
new Thread() { public void run() { { ... runOnUiThread( { .. } ) }
A lot. With all the ugly consequences (no error checks, Sleeps, boolean finish variables...).
Till now, I ended up using (few) AsyncTasks and (more) Loaders as replacements.
Now I have stumbled upon a couple of "fire-and-forget" network communications: the code (currently, a Thread, as always) calls a web service posting some data.
I do not need to know if the data was received, and I do not need to know if there was any error.
Which is the best way of doing this? A Runnable or AsyncTask (static nested class, so I do not "leak" a reference to "this" activity?)
Or is there something better (more "lightweight" and cleaner?)
If you don't need to know when task execution is finished then you definitely don't need AsyncTask at all. Therefore the most lightweight solution is just a Thread. You can use Executor which will create threads for you. To get rid of nested classes you could predefine tasks. Sample:
Predefined task:
public static class TaskA implements Runnable{
private int someParam;
public TaskA(int someParam) {
this.someParam = someParam;
}
#Override
public void run() {
//
}
}
Static Executor
public static class FireAndForgetExecutor{
private static Executor executor = Executors.newFixedThreadPool(5);
public static void exec(Runnable command){
executor.execute(command);
}
}
And usage:
FireAndForgetExecutor.exec(new TaskA(10));
PS don't forget that a Thread is connected to the GC root! So if you pass heavy object like an activity or a bitmap into the task it could lead to memory leak.

Is WeakReference a good type in order to reference my custom view inside a static inner class?

I am writing a custom view by directly inheriting from the View class, and I am wondering whether I am making a good use of the WeakReference class. First, this is the most relevant part of my class :
public class ChessView extends View {
public ChessView(Context context, AttributeSet attrs, int defStyle) {
/* some code removed */
invalidateHandler = new InvalidateHandler(this);
new Thread(new Runnable() {
#Override
public void run() {
invalidateHandler.sendMessage(invalidateHandler.obtainMessage());
}
}).start();
}
/* some code removed */
private static class InvalidateHandler extends Handler {
public InvalidateHandler(ChessView view){
relatedChessView = new WeakReference<ChessView>(view);
}
#Override
public void handleMessage(Message msg) {
relatedChessView.get().invalidate();
}
private WeakReference<ChessView> relatedChessView;
};
private InvalidateHandler invalidateHandler;
}
As you can see :
I am creating a static inner class, subclass of the Handler class : as the android developpers guide recommands to avoid direct inner classes inside View subclasses
The Handler static inner class makes a call to the invalidate() method of my custom ChessView : so I decided to "wrap it" inside a WeakReference, as the android developper guide recommands to avoid hard references on View instances.
So here my questions :
Do I avoid memory leaks this way ?
Is WeakReference the best type, or should I use a SoftReference instead ?
And finally, will the custom view remains on the heap as long as the view is visible (or the related activity active) or may it be collected by the GC before, letting me with a null reference when calling relatedChessView.get() ?
Thanks in advance, and apologizes if my question is bad formulated.
Do I avoid memory leaks this way ?
Yes, but this isn't necessary.
Is WeakReference the best type, or should I use a SoftReference instead ?
WeakReference is the way to go in your case. SoftReference and WeakReference will be both available as long as there is a hard reference pointing to them. If there is no strong reference though, WeakReference will more likely to be collected while SoftReference will retain your object as long as there is no need to clean up memory (eg. SoftReference will stick around longer).
And finally, will the custom view remains on the heap as long as the view is visible (or the related activity active) or may it be collected by the GC before, letting me with a null reference when calling relatedChessView.get()?
Yes, it will. As i mentioned above WeakReference won't be collected while there are any Objects holding the contained Object's reference.
UPDATE: Fixed the information regarding Weak and Soft references based on #DeeV's answer to be more accurate.

Categories

Resources