As we know asynctask works as a background thread and returns control to the gui when task is complete and requests through volley can be made in the main activity thread ,
Lets say i assign the JSON response to a string variable upon the completion of the request , the string is initially null , the program further processes that reponse,
the problem that i got was i was thrown a NullPointerException while processing the response string even after the successful response ,
it would be absurd to say but is it possible if the response is slow the program may continue without initializing the string variable ??
It sounds like you are not using a proper callback on your data. In other words, after you start AsyncTask, you have to wait until it is done until you reference global variables that it might impact.
So, if you didn't write a proper callback method, then yes the program will continue. The idea behind AsyncTask that - to let the thread it is called on continue while it does a long process of some kind.
Related
I am trying to set up a test for my project - to test that a progress bar is displayed when my app performs a server request.
The code under test uses an AsyncTask to perform the network call.
I have created a blocking server (MockWebServer) to catch and hold the network call - it receives request but doesn't provide a response until i call ".release()". This allows me to verify before the server response occurs.
My logic flows like this:
// Mock server will catch the next network request
BlockingServer blockingServer = createBlockingServer();
// onResume() activity performs network request and shows Progress Spinner
activityTestRule.launchActivity(null);
// onView() waits on UiController.loopUntilIdle() <- Fails here due to timeout.
onView(withId(progressBar)).check(matches(isDisplayed()));
// Tells the server to respond to the network request
blockingServer.release();
onView(withId(progressBar)).check(matches(not(isDisplayed())));
My problem is that because the Code Under Test uses AsyncTask for the server request, Espresso naturally blocks on the verify call (onView()) in order to wait for the AsyncTask to complete before verifying.
What I need is to temporarily stop Espresso idling while waiting for AsyncTask in order to perform the verify while the server is blocking the app logic flow.
(Changing the Code Under Test is not an option)
Can someone help?
So... this is the answer I've arrived at and some working out behind it:
Espresso (specifically calls to onView(), onData(), injectEvent and Actions) uses UiControllerImpl.loopMainThreadUntilIdle() to wait until all "idle-causing" signals are false. It loops over AsyncTask, CompatAsyncTask and something called dynamicIdle to all be idle.
When this method returns the main flow continues.
loopMainThreadUtilIdle() checks an IdleNotifier to check the idle state of each of those three elements. Obviously if you want to stop espresso waiting for AsyncTask the asyncIdle is of particular interest to you.
The IdleNotifier classes are fed into UiControllerImpl at it's construction - this takes place via dagger so you'll need to look at DaggerBaseLayerComponent which uses Providers to grab the construction arguments and pass them into the UiControllerProvider to construct it.
Everything in all of these classes is locked down very tightly. Method and class visibility is usually protected or package-private and final.
The only way I found was to create my own Espresso.java class (onView() and onData()) which used custom DaggerBaseLayerComponent allowing me to use either: My own Providers or My own UiController.
I found however this doesn't solve the whole problem. There is one more mechanism that needs to be coded around - When you're starting activities they use a waitForIdleSync in the Instrumentation class. Usually this is the Runner which is provided in your gradle file. I created my own AndroidJUnitRunner and provided this in gradle to allow me to return from waitForIdleSync on command.
And finally, in startActivitySync in the Instrumentation base class, it uses an array of ActivityWaiter objects to hold up your launchIntent() calls. I couldn't think of a reasonable way of avoiding this so I cheated and created this method in my Runner:
public void clearActivityWaitQueue() {
Object mSync = Whitebox.getInternalState(this, "mSync");
List mWaitingActivities = Whitebox.getInternalState(this, "mWaitingActivities");
if (mSync != null && mWaitingActivities != null) {
mWaitingActivities.clear();
synchronized (mSync) {
mSync.notifyAll();
}
}
}
It uses PowerMock to give me the convenience Whitebox methods to set internal state of Instrumentation:
// Used to give access to Whitebox
androidTestImplementation 'org.powermock:powermock-reflect:1.6.5'
And that's it! Easy right?
(Please tell me it's easier than this and how!!)
i am new on xamarin android apps.I want to build an app and i have read that connections with database or the execution of queries should happen asynchronously from the main thread otherwise the UIthread will may collapse.I have found 2 ways to do that:
First way:
WebClient client = new WebClient();
Uri uri = new Uri("http://192.168.2.8/CreateUsername.php");
NameValueCollection parameters = new NameValueCollection();
parameters.Add("Name", txtname.text);
client.UploadValuesCompleted += Client_UploadValuesCompleted;
client.UploadValuesAsync(uri,parameters); ---> is this gonna create a new thread and run asynchronously???
(here i found the first way: https://www.youtube.com/watch?v=jF3D__ibrx8 )
SecondWay:
https://developer.xamarin.com/recipes/android/web_services/consuming_services/call_a_rest_web_service/
Both ways are correct?both of ways are gonna create a new thread and run asynchronously?Thanks!!!!
Both examples are ok but I'd usually trust the official documentation by Xamarin first. What might confuse you with the first example is the lack of await keyword when calling the UploadValuesAsync method. Here's what actually happens:
Call to UploadValuesAsync is made from the UI thread.
UI thread blocks until the method returns because it's running synchronously.
However, the method returns very quickly because it launches the upload process asynchronously on another thread internally and doesn't wait for the process to complete.
When the whole upload process is finished, Client_UploadValuesCompleted will be called.
As you can see on the WebClient.UploadValuesAsync page on MSDN, it states that:
These methods do not block the calling thread.
Also, when looking at the source code for UploadValuesAsync, you'll notice the following attribute defined on top:
[HostProtection(ExternalThreading=true)]
which means the following:
Code that exposes external threading creates or manipulates threads other than its own, which might be harmful to the host.
To sum it up, the upload process is handled on another background thread but otherwise, your code will run synchronously. There's a bit more asynchronicity going on in Xamarin's sample.
I have simple Activity that calls AsyncTask, so I print some id's regarding Proces and Thread:
From onCreate android.os.Process.myUid(): 10137
From onCreate android.os.Process.myPid(): 29776
From onCreate android.os.Process.myTid(): 29776
From onCreate Thread.currentThread().getId(): 1
/****************************************************************/
From Async doInBackground android.os.Process.myUid(): 10137
From Async doInBackground android.os.Process.myPid(): 29776
From Async doInBackground android.os.Process.myTid(): 30426
From Async doInBackground Thread.currentThread().getId(): 12556
Uid is same because its app-specific sandbox
Similar with Pid: Each app is one Process
3rd line in onCreate same as Pid because it's the UIThread and in Android OS as based on Linux we know that issue regarding Process is actually Thread etc... And in the Async the ThreadId is different because AsyncTask runs on different Thread rather then the UIThread
The thing I'm struggling to understand is Thread.currentThread().getId(). What I expect is to get same id as Thread.currentThread().getId() for the same execution environment. e.g. for onCreate I want lines 3,4 to be same (29776), and for Async I expect lines 3,4 to be the same (30426). What is going on here?
Thanks,
Very interesting question by the OP and I decided to dig (love open source).
The short answer is: they're different because they're different, because they were never meant to be the same.
Process.myTid() is the linux thread ID
Thread.getId() is a simple sequential long number.
But the short answer is boring, so let's explore where the answer comes from (links in the answer points to the relevant source codes).
In Process.myTid(), you'll see that is simply calls from Os.gettid() that in itself calls a native method on Libcore for that method is below:
public static int gettid() { return Libcore.os.gettid(); }
furthermore the docs for Os.gettid(); you'll find a link to Linux Programmer's Manual
gettid() returns the caller's thread ID (TID). In a single-threaded
process, the thread ID is equal to the process ID (PID, as returned
by getpid(2)). In a multithreaded process, all threads have the same
PID, but each one has a unique TID.
That means, Process.myTid() returns the thread ID as given by the Linux kernel.
On the other hand Thread.getId() is simply returning a long. This long is assigned during init(...) as tid = nextThreadId();. Then the last piece of this puzzle, below is the code for nextThreadId()
/* For generating thread ID */
private static long threadSeqNumber;
private static synchronized long More ...nextThreadID() {
return ++threadSeqNumber;
}
That means, Thread.getId() is simply a "java layer" static long being auto-increment for each thread.
I am extending AsyncTaskLoader which I use later in a Fragment through LoaderManager. Is there suggested way to handle errors which occur during async task? I would like to popup message asking user to cancel or retry when internet connection error occurs.
Only way which I can think of now is to make Loader to return null on error or wrap loaded object into another which would have status code.
What we did in our last project: Create a Wrapper that holds a generic and an excpetion like this:
public class AsyncTaskResult<T> {
private final T result;
private final Exception error;
//getter & setter
}
Catch all Exceptions in your doInBackground(...) and pack them into the result wrapper (or the result if no error). In your UI check the wrapper if it's an exception, then show according error message, otherwise populate the fields with the result.
For us it was also good practice to define what unique types of exceptions, there are (e.g. exception with a recoverable error where you only show a dialog or an app failure where you need to kick the user to the main menu) and only throw these kinds (on catching the specific in your asynctask), so you don't have to bother with hundreds of different exceptions and also abstract your error handling. You could also provide String keys with the correct I18n error message so you only have to write e.getMessage()
I've seen good results when returning a composite object that contains the payload (if any) and a status code, as you suggested. Then the Fragment that's hosting the AsyncTaskLoader can display an appropriate and informative error. This approach has the added advantage that it uses the built-in loader lifecycle.
Another option is to register a listener that your AsyncTaskLoader will notify when errors occur. The Facebook SDK has an example of using error listeners with loaders.
I have a C thread that is making requests and receiving updates from a server. The updates are sent to Java through JNI calls. My problem happens when I'm receiving a player's inventory which can contain up to 100 items (100 responses from the server, I cannot modify this part). Sometimes the problem happens, sometimes not but the bigger the inventory is, the more often I have this issue.
I don't get any exception in the logcat except the following message :
06-10 10:09:46.085: I/Choreographer(23815): Skipped 87 frames! The application may be doing too much work on its main thread.
And then my app closes. I also need to say that even when I comment the lines where I update the UI with runOnUiThread the app crash.
I tried to check if I'm on the UI Thread when I return to Java with JNI but Looper.myLooper() == Looper.getMainLooper() return false.
Anyone experienced the same problem ? Are the C threads related to the main thread somehow ? Thanks
EDIT
When I receive an update from the server the following calls are made :
From a Java Thread (not the UI thread) : call a C function named notifyAll
From notifyAll call a C function named update which will call its equivalent in Java (see code below)
void UpdateListenerWrapper::update(Update& u) {
// Retrieve the current JNIEnv* with the cached JVM
int status;
JNIEnv* env;
bool isAttached = false;
status = gCachedJVM->GetEnv((void **) &env, JNI_VERSION_1_2);
if(status < 0) {
__android_log_print(ANDROID_LOG_ERROR, "UpdateListenerWrapper", "Failed to get JNI environment");
status = gCachedJVM->AttachCurrentThread(&env, NULL);
if(status < 0) {
__android_log_print(ANDROID_LOG_ERROR, "UpdateListenerWrapper", "Failed to attach current thread");
return;
}
isAttached = true;
}
jmethodID update = env->GetMethodID(gClazzUpdateListenerWrapper, "update", "(J)V"); // J stands for Java long type
// Call Java method update from jUpdateListener object
env->CallVoidMethod(jUpdateListener, update, (jlong)(intptr_t)&u); // Pointer as agument, we'll build the Update object in Java
if (isAttached) {
gCachedJVM->DetachCurrentThread();
}
}
I think the problem is at this line gCachedJVM->GetEnv((void **) &env, JNI_VERSION_1_2); and maybe GetEnv return a pointer for the UI thread. Could that be the problem ? How can I fix this ?
The app crash is unrelated to the Choreographer complaints. Those are just a warning that indicates the animation is being starved.
You really want to be viewing the logcat output in a mode that shows thread IDs. I recommend adb logcat -v threadtime from the command line. If you put a log message at the start of your server interaction you can easily see if it's running on the UI thread (thread ID and process ID are the same -- not guaranteed by the system, but reliably true in apps).
Never do network or database I/O on the main thread. If it takes too long, the system gets bored and decides that your app is not responding.
Calling into native code through JNI does not switch you to a different thread. There are not C threads and Java threads, just threads, which can call in and out of code written in C and Java.
Re: question updates...
GetEnv always returns a pointer to data for the current thread. Also, CallVoidMethod always happens in the current thread; even if you passed in the wrong JNIEnv it wouldn't "jump" threads.
The GetMethodID call can be expensive in a class with a lot of methods, so you should try to cache that at the same point where gClassUpdateListenerWrapper is set up. Attaching and detaching the thread from the VM can also be expensive and is something best avoided -- and if you're calling here from a Java method, then by definition it's attached already. I would guess that isAttached is never being set.
That doesn't really explain why the Choreographer is starving though. I think you still need to add a log message to C update() and use logcat -v threadtime to get a sense for what is happening on which threads, and use traceview to see where the time is going.
I found the solution to my problem but it's kind of specific to my app. In the update function (Java side), I had a case which had no break and each updates were triggering new network calls (not in the UI thread). Nasty to find but thanks for your time and your answers, you helped me to solve this :)