At runtime, I am using a callback pattern to have generic code run and use the callback when finished to execute code on the GUI. So in my handler I use the runOnUiThread function against the callback.
These are all async http calls. At runtime if I interrupt and use the back button and go to another fragment for example, the system will swap out the fragments and run both callbacks (the new fragment one on the correct callback, and the old callback that should have ran on the old fragment on the new current fragment). This is wrong, the new fragment gets both callbacks but when it was initialized it was assigned to the other fragment...
This makes no sense and you can only observe the behavior by switching fragments at runtime before an async call finishes. I don't see how it's possible, in the code I check if callback is null so it should have been garbage collected and how it runs on the new callback I don't know how it's possible....there's no additional assignment happening to change this. It's almost like it's just looking in memory for the function signature and running it even though when it does it's on the wrong object.
Does anyone have any clue what's going on? I've surpressed it with an ugly piece code, I just don't know how this is possible?
I understand the obvious candidates are if I assigned it again somewhere, but the answer is no. When the fragment is created it creates an object, assigns itself as the callback, and processing begins so when the fragment is destroyed it should be too. But the async task is still executing which is fine, why it does a callback on the new thread on the main gui I guess is because of runOnUiThread, so that function is somehow changing what the callback object points to in memory?
Its your code :-)
There is no magic happening 'behind the scenes' in Android and no references are changed.
Many have problems like yours, and its always because they assume that the Android system is somehow cleaning up when a fragment or activity instance is replaced or removed. It isn't, and therefore the callbacks are still executed, on a obsolete fragment or activity.
runOnUiThread takes a Runnable and runs it when the UI thread have spare time (after invoking lifecycle methods and finished rendering). Its not magic either :-)
Related
im getting a string from callback and storing in a variable call channel. it's fine now but when accessing the value outside the callback method it returns null why?
it's not accessable outside of that method.
callback is working fine while inside of callback method
but i
please help me
ch = new Channel(fuser.getUid(),userid);
ch.getChann();
ch.Back(new Channel.MyCallback() {
#Override
public void onCallback(String value) {
channel = value;
Log.e("Channel",channel);
}
});
channel+="1";
Log.e("Channel1",channel);
unfortunately, there's not all text visible on your screenshot. On Stackoverflow, it's generally preferred if you paste the source code directly into your question rather than sharing a screenshot. It's a bit more effort, at the same time, please consider that the people answering your question also take effort to help you - and by posting the source code as text, you make it easier for everyone to help you.
For your question, there's a couple of things that might happen:
the callback is never called - and therefore there's nothing written into that variable
the callback is not called immediately, but later (maybe by another thread). Therefore, you will find that the variable will not be set immediately after you pass that callback to the Back method, but maybe a few seconds or milliseconds later. That's a long time for a computer, so when you access the variable later, you might just be too early.
if there's threads involved, your code is not thread save. That means - it might also happen that channel=value and channel+="1" might happen at the same time, which could give you unpredictable results.
To solv the problem, you will need to trigger whatever action should happen after your callback at a time when you know that the callback has been called. I am no expert on Android; there might be listeners available for that. If not, then the simplest way would be to call the code that should happen after the callback was called from the callback itself (be aware, that this is most likely a bad practise in android as it might make the UI become unresponsive. To solve that, you will need to execute your code on a different thread than the UI thread)
I got an AsyncTask for URL connection. Now I want to have a loading spinner everytime I do the URL connection. I display the loading spinner in onPreExecute() and dismiss it in onPostExecute.
I tested this with an endless while loop in doInBackgroung().
The big problem is the GUI is freezing and the loading spinner is not shown.
In my opinion the reason is URLconnection.execute().get(). But I need the get() because the activity need the result to working with it.
My question is now: What is the best way to do this to achieve my wishes? (By the way it is not important to get a solution with an "AsyncTask solution" because there are maybe better solutions and AsyncTask will be deprecated with SDK version 30)
Thank you very much and stay healthy!
As you said AsyncTask will be deprecated.
So it is better to go for an alternative.
Since you mentioned you are not relying on AsyncTask, I will present to you another approach.
Let me introduce you to coroutines and convince you that they will solve your problem and "get the job done".
When I got to know about coroutines, this video was one of the first example that has demonstrated to me the potential of using coroutines in my app. At that point I was still using 100% Java, probably like you are right now.
The good part is: getting started with Kotlin is really easy! Not only you can call Kotlin functions from Java Code, you can also call Java functions from Kotlin code.
To "do something in background" in Kotlin, all you need to do is to launch a coroutine (on a background thread).
Do you have a ViewModel to fetch your data? If it is an option to transfer this file to kotlin, then starting (and scoping) a coroutine becomes as simple as this.
For fragments or activitities you could use other copes as well. However, using the global scope is usually discouraged.
Executing coroutines is as simple as that:
class MyViewModel: ViewModel() {
fun loadDataInBackgroundAndShowSpinner {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
// start your spinning
// do all the heave data work on a background thread
doInBackground()
// end your spinning here
}
}
suspend fun doInBackground(inputURL: String) {
withContext(Dispatchers.IO) {
// Execute all your data fetching here
...
// Assign your data to your viewModel variables, post it to a LiveData object, etc.
}
}
}
You do not need any loops in the main thread or anything. By using withContext on a background thread you can achieve main-safety.
Within a launched coroutine, everything (by default) gets executed in order.
Still you will not block the Main Thread. How did you achieve that?
The key here is that your doInBackground function has the suspend keyword. Therefore your loadDataInBackgroundAndShowSpinner on the main thread will "suspend" your doInBackground function and the main thread is able to do whatever you want (i.e. nothing freezes). Then, once your doInBackground is finished, it will resume execution and you can just dismiss your spinner again on the main thread.
Kotlin coroutines make it so much easier to do something in the background and I really want to encourage you to give it a try! It will definitely solve your problem and I can not think of a more easy way.
Google also tried to make it as easy as possible to get you started when coming from Java.
So I have a problem and I am wondering how to solve it if it can be solved at all.
I have an external library class called Messenger that defines the method sendMessage(String msg). I also have the following MessengerManager class
public class MessengerManager{
private Messenger messenger;
public MessengerManager(Context context){
messenger = new Messenger(context);
}
public void message(){
String msg = "12435";
messenger.sendMessage(msg);
// Do more stuff
.....
.....
.....
}
}
So the issue is that sendMessage runs asynchronously and starts a new activity. Probably using startActivity() (lets call this Activity A). Hence, the code after sendMessage ("Do more stuff") gets run immediately. However, I need to wait for the newly created activity (Activity A) to return to carry on with the "Do more stuff".
As sendMessage is a method defined in an external library, I cannot change it in any way nor do I have access to its source code.
So, in short, my problem is that sendMessage creates a new thread (using startActivity() probably) and I need to know when this newly created activity ends. However, I have no way of monitoring it since it is defined in an external library. Anyone know how to solve this?
AsyncTask should be what you are looking for.
Let your message() starts an AsyncTask that calls messenger.sendMessage(msg) in doInBackground(). If you care about the result of the AsyncTask, get it in onPostExecute().
http://developer.android.com/reference/android/os/AsyncTask.html
One admittedly ugly way to get around this is to call
Thread.sleep(int milliseconds)
after sendMessage(), and before you continue with the rest of your code. Of course, this will only be helpful if you can fairly accurately estimate how long it will take to get the callback.
The better alternative is as Kaifei is saying. But you won't want the "do more stuff" where it is now. Instead, put it in a new method, and call that method in onPostExecute(). That way, the code will not continue until the AsyncTask has returned.
Edit: Saw your addition about needing the created activity to finish. If that's the case, you're going to somehow need to communicate with that activity (which I can't speak to without seeing all the code). But if you have that, then before "do more stuff", insert
while(!activity.isFinished()) {}
and in that activity, have it set a finished variable to true when it is done (however you define done). So the main thread will run this loop until the activity on the second thread is done, and then the first thread will continue.
Double Edit: Another idea. Let's say that the other activity the user has to complete is some form. In your main activity, after you call sendMessage(), have some popup where the user selects "finished" when they have completed the new activity. Have the program only continue when "finished" has been selected. A bit annoying for the user, but if it's only a single additional tap, that should work.
As you mentioned, sendMessage() runs asynchronously. If it's written properly, it must also have provided a callback interface, whose method will be called when messaging is finished. Move the code in that callback method.
I have a question regarding this simple frequently occurring situation in android .
We have a main activity , we invoke an AsyncTask alongwith the reference of the mainactivity , so that that the AsyncTask can update the views on the MainActivity.
I will break down the event into steps
MainActivity creates an AyncTask , passes its reference to it .
AysncTask , starts it's work , downloading ten files for example
The user changed the orientation of the device. This results in an orphan pointer in the AsyncTask
When the AsyncTask completes , and tries to access the activity to update the status , it crashes , because of the null pointer .
The solution for the above is to keep a WeakReference in the AsyncTask as recommended by the book "Pro Android 4"
WeakReference<Activity> weakActivity;
in method onPostExecute
Activity activity = weakActivity.get();
if (activity != null) {
// do your stuff with activity here
}
How does this resolve the situation ?
My question it , if my asynctask is downloading ten files , and upon completion of 5 the activity is restarted (because of an orientation change) then would my FileDownloadingTask be invoked once again ?.
What would happen to the previous AsyncTask that was initially invoked ?
Thank you , and I apologize for the length of the question .
How does this resolve the situation ?
The WeakReference allows the Activity to be garbage collected, so you don't have a memory leak.
A null reference means that the AsyncTask cannot blindly try to update a user-interface that is no longer attached, which would throw exceptions (e.g. view not attached to window manager). Of course you have to check for null to avoid NPE.
if my asynctask is downloading ten files , and upon completion of 5 the activity is restarted (because of an orientation change) then would my FileDownloadingTask be invoked once again ?.
Depends on your implementation, but probably yes - if you don't deliberately do something to make a repeat download unnecessary, such as caching the results somewhere.
What would happen to the previous AsyncTask that was initially invoked ?
In earlier versions of Android it would run to completion, downloading all of the files only to throw them away (or perhaps cache them, depending on your implementation).
In newer Android's I am suspicious that AsyncTask's are being killed along with the Activity that started them, but my basis for suspicion is only that the memory-leak demo's for RoboSpice (see below) do not actually leak on my JellyBean devices.
If I may offer some advice: AsyncTask is not suitable for performing potentially long running tasks such as networking.
IntentService is a better (and still relatively simple) approach, if a single worker thread is acceptable to you. Use a (local) Service if you want control over the thread-pool - and be careful not to do work on the main thread!
RoboSpice seems good if you are looking for a way to reliably perform networking in the background (disclaimer: I have not tried it; I am not affiliated). There is a RoboSpice Motivations demo app in the play store which explains why you should use it by demo-ing all the things that can go wrong with AsyncTask - including the WeakReference workaround.
See also this thread: Is AsyncTask really conceptually flawed or am I just missing something?
Update:
I created a github project with an example of downloading using IntentService for another SO question (How to fix android.os.NetworkOnMainThreadException?), but it is also relevant here, I think. It has the added advantage that, by returning the result via onActivityResult, a download that is in flight when you rotate the device will deliver to the restarted Activity.
The WeakReference class basically just prevents the JRE to increase the reference counter for the given instance.
I won't go into Java's memory management and answer your question directly: The WeakReference resolves the situation by providing the AsyncTask a way to learn if its parent activity is still valid.
The orientation change itself will not automatically restart the AsyncTask. You have to code the desired behavior with the known mechanisms (onCreate/onDestroy, onSave/RestoreInstanceState).
Concerning the original AsyncTask, I'm not 100 % sure which of these options will happen:
Either Java stops the thread and disposes the AsyncTask, because the only object holding a reference to it (the original Activity) is destroyed
Or some internal Java object maintains a reference to the AsyncTask object, blocking its garbage collection, effectively leaving the AsyncTask to finish in the background
Either way, it would be good practice to abort/pause and restart/resume the AsyncTask manually (or handing it over to the new Activity), or use a Service instead.
How does this resolve the situation ?
It doesn't.
The referent of a WeakReference is set to null when the garbage collector determines that the referent is weakly reachable. This does not happen when an activity is paused, and does not necessarily happen immediately when the activity is destroyed and the framework discards all references to it. If the GC has not run, it is entirely possible for the AsyncTask to complete while its WeakReference still contains a reference to a dead activity.
Not only that, but this approach does nothing to prevent the AsyncTask from uselessly consuming CPU.
A better approach is to have the Activity maintain a strong reference to the AsyncTask and cancel(...) it in the appropriate teardown lifecycle method. The AsyncTask should monitor isCancelled() and stop working if it is no longer needed.
If you want an AsyncTask to survive across configuration changes (but not other forms of activity destruction) you can host it in a retained fragment.
Consider a simple Android application: there are two TabActivities and a thread in the background getting integer values from a server. If the number is even, it must be displayed in the first tab otherwise in the second. Obviously I will be doing something more complicated, but this is the basic pattern. How do I go about doing this? I have been scratching my head for about a day now and here are things I have come across:
Use of EventHandlers. The two TabActivities register for listening for my_events and when a value is received by the thread, it 'throws my_event' and then specific methods in both these activites are called and the value is passed.
The use of Handlers.
I have not used both of these concepts before and I would like to know which might be the better/correct route to take. Further, any more tips along the chosen route will be appreciated. Also, should this thread be run from a service class?
When you create your thread just pass the objects of your tabs into it, then in your execution you can easily put the text you want into tabs.
Possibly you want to look at using an AysncTask. If you do this you want to insert the values into the appropriate tab in the onProgressUpdate() method. Since the arguments passed to this method may not actually be able to represent the incoming data sufficiently you'll just want to put the new data somewhere that it can be accessed from the onProgressUpdate() method, probably in a member variable. Keep in mind that access to this member variable probably needs to be synchronized because code in onProgressUpdate is running on the application's main thread, while code in doInBackground is running on a background thread so code in these methods will be running concurrently.
AsyncTask uses Handlers transparently for you, but you could use raw Handlers if you wanted. The basic things you need to keep in mind are
You can/should only update the UI from the main application thread
Code in a Handler will always run on the Thread that created the Handler
Handlers must be created on a Thread that has a Looper (the main Thread has a Looper)
Be careful if creating the Handler as an anonymous inner class or handing it a reference to a Context since this creates the potential for a memory leak
Possibly the Thread should be invoked by a Service, but if the Thread only needs to exist when there is a UI for it to update there may be little point to this.