Skip to content Skip to sidebar Skip to footer

How Can I Make Some Class, Running In The Main Thread, Await Concurrently For Other Class To Reach Some Specific State?

I am having serious difficulties to understand how can I make some AsyncTask children, declared and instantiated in the Main Thread, to await for a Service child instance to reach

Solution 1:

Well problem is with your application logic as follows,

If you are using AsyncTask that is obviously a separate thread from the main thread. But syncing to your database after retrieving data via HTTP call is a process which has a sequence ( Call through HTTP and retreive -> then persist to database ), it cannot perform asynchronously. So when you call,

List<MyModel> the_list = mService.getResponseAsObject();

this call happens in a particular thread and the program flow is in a different thread. Since these are asynchronous tasks, they work asynchronously. which means you will never know which one will execute first and which one is next. But as per your logic,

if (the_list == null) {

this part essentially need the_list to be initialized to run. But the problem is at that point, service thread has not finished his work to perform your next logic. so its obvious breaking.

Better if you can re-design this so that you wait for the HTTP request to complete and then persist to database. Because suppose if your HTTP request complets first but still it returns you null or whatever not-desired output. So in that case you need to handle it in your logic.

OK so let me tell you a quick workaround. Lets use just one thread instead of different threads. So consider changing following line

privateclassPopulateDbAsyncextendsAsyncTask<Void, Void, Void> {

to

privateclassPopulateDbAsync

then you will get an error with

@OverrideprotectedVoid doInBackground(finalVoid... params) {

since we no longer extend AsyncTask class.

so change it as follows, by removing @Override

publicVoid doInBackground(finalVoid... params) {

This should fix the stated problem here.

Solution 2:

I found a solution: creating custom listeners.

Steps to create a custom listener

1. Define an interface as an event contract with methods that define events and arguments which are relevant event data.

2. Setup a listener member variable and setter in the child object which can be assigned an implementation of the interface.

3. Owner passes in a listener which implements the interface and handles the events from the child object.

4. Trigger events on the defined listener when the object wants to communicate events to it's owner


I got the NullReferenceException because MyService didn't finish it's job yet. So, first I create the listener's structure within MyService class like this (steps 1 and 2):

private MyServiceListener listener;

publicinterfaceMyServiceListener {
    publicvoidonDataDownloaded();
}

publicvoidsetMyServiceListener(MyServiceListener listener) {
    this.listener = listener;
}

And, within the HTTP request's callback (step 4):

@OverridepublicvoidonResponse(Call call, Response response)throws IOException {
    finalStringmyResponse= response.body().string();
    //...and some code to hold data as JSONArray//[...]// XXX Trigger the custom eventif (listener != null) {
        listener.onDataDownloaded();
    }
}

Now, I just can wrap the code that triggered the NullReferenceException within the custom listener like this (step 3):

// Within DataRepository class
mService.setMyServiceListener(new MyService.MyServiceListener) {
    @OverridepublicvoidonDataDownloaded() {
        List<MyModel> the_list = mService.getResponseAsObject();
        if (the_list == null) {
            // HERE! I obtainED the NullReferenceException here.Log.e("MY_ERROR", "DataRepository.PopulateDbAsync --> error: response isn't ready yet.");
        }
        for (MyModel i_model : the_list) {
            Log.d("MY_LOG", "DataRepository.PopulateDbAsync --> Inserting data in local DB...");
            mModelDao.insert(i_model);
        }
        returnnull;
    }
}

Actually, the real implementation required to nest this code example into another custom listener following similar steps; but this worked for me.

Post a Comment for "How Can I Make Some Class, Running In The Main Thread, Await Concurrently For Other Class To Reach Some Specific State?"