1

I got the following problem and hope someone could give me a hint.

I have an activity that executes an AsyncTask< String, Void, ArrayList<Custom object >>. In the doInBackground() function, I set up a new ArrayList of custom objects which is also the return value. In the onPostExecute() method that ArrayList is used in a newly created ArrayAdapter<Custom object>, which is also set to a ListView with lv.setAdapter(adapter). so far so good!

now the thing is: back in the MainActivity I will need that adapter again, cause I wanna add new items to it by calling adapter.add(items). for now I had the AsyncTask as an inner class of my MainActivity and could use the same ListView & the same ArrayAdapter, that worked very well!

but because I have another class which needs to execute that AsyncTask too, I changed that inner class AsyncTask to a standalone .java file (CustomAsyncTask.java)

-> now when I try to add new items to the ArrayAdapter it throws a NullPointerException! of course that is, cause the ArrayAdapter belongs to the AsyncTask and is created there so I tried to give the ListView and the ArrayAdapter from the MainActivity as a parameter for the CustomAsyncTask constructor to use it in there but that did not work, the ArrayAdapter in MainActivity is always null causing the Exception

any ideas how to solve that? I would really appreciate it.

here the code of the MainActivity.java:

// global variables
ArrayAdapter<Custom object> arrayadapter;
ListView listview;
ProgressBar progressbar;

...

protected void myMethod() {
    CustomAsyncTask hTask = new CustomAsyncTask(this, listview, progressbar, arrayadapter);
    hTaskPlaylist.execute(String sth);
}

...

protected void anotherMethod() {
    arrayadapter.add(item);
}

and the code of CustomAsyncTask.java:

package com.mypackage.test;

import java.util.ArrayList;

import android.content.Context;
import android.os.AsyncTask;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;

public class CustomAsyncTask extends AsyncTask<String, Void, ArrayList<Custom object>>{

    Context context;
    ListView listview;
    ProgressBar progressbar;
    ArrayAdapter<Custom object> arrayadapter;

    public CustomAsyncTask(Context con, ListView lv, ProgressBar pb, ArrayAdapter<Custom object> aa) {
        this.context = con;
        this.listview = lv;
        this.progressbar = pb;
        this.arrayadapter = aa;
    }

    @Override
    protected void onPreExecute() {
        listview.setVisibility(ListView.GONE);
        progressbar.setVisibility(ProgressBar.VISIBLE);
        super.onPreExecute();
    }

    @Override
    protected ArrayList<Custom object> doInBackground(String... params) {
            ArrayList<Custom object> list = new ArrayList<Custom object>();

            ... doing something and populating list
            return list;
    }

    @Override
    protected void onPostExecute(ArrayList<Custom object> list) {
        super.onPostExecute(list);

        arrayadapter = new ArrayAdapter<Custom object>(context, android.R.layout.simple_list_item_1, list);
        listview.setAdapter(arrayadapter);

        progressbar.setVisibility(ProgressBar.GONE);
                listview.setVisibility(ListView.VISIBLE);
    }

    }
}
0

2 Answers 2

1

You could make your ArrayAdapter static.. Then anytime you want to access it you can simply say CustomAsyncTask.arrayadapter.add(items); You are also allowed to add your own functions to your custom asynctask class. You could create something like public ArrayAdapter<> getAdapter(). But careful, you are going to have multiple threads accessing/changing that object regardless, so it would be a good idea to synchronize access.

You could try something like this...

ArrayAdapter globalAdapter;
globalAdapter = new CustomAsyncTask().execute(/*your parameters here*/).get();
Sign up to request clarification or add additional context in comments.

10 Comments

thank you.. but isn't there a way to return the value back to MainActivity (not just in onPostExecute())?-> 'cause it works when the AsyncTask is an inner class of the MainActivity, somehow it should work if it is an external class too, shouldn't it`?
Was the adapter originally a variable in the main activity? because inner classes have access to the outer class's instance variables... And yes it should work to have your async task return an array adapter; however, any changes you make to that returned value will not persist for other instances.
the ArrayAdapter arrayadapter is defined globally in the MainActivity (so when Activity starts the adapter is null), then I create a new AsyncTask object with the arrayadapter & listview as a parameter and execute it. in the CustomAsyncTask I populate the listview with the arrayadapter, which was filled with an arraylist. (in onPostExecute()) the listview that also comes from the MainActivity is correctly set, only when I try to call arrayadapter.add(item) it throws a NullPointerException
Well they are not global if they are declared in your activity, because global would mean all classes and subclasses have access to them. When you give the arrayadapter to the AsyncTask, it is passed by value.. meaning that any changes you make to that arrayadapter will not affect the one that is in your main activity.
sry, with globally I meant for the class MainActivity. but how is it to explain that I can work with the passed listview in MainActivity AND AsyncTask isn't it some kind of strange that JAVA handles object by reference, but when passing method arguments its by value? so is there a way to pass in the arrayadapter by reference?
|
0

Now I tried that and pass the MainActivity as a parameter instead of the Context, here is what I changed:

public class CustomAsyncTask extends AsyncTask<String, Void, ArrayList<Custom object>>{

    **MainActivity activity**;
    ListView listview;
    ProgressBar progressbar;
    ArrayAdapter<Custom object> arrayadapter;

    public CustomAsyncTask(**MainActivity act**, ListView lv, ProgressBar pb, ArrayAdapter<Custom object> aa) {
        **this.activity = act;**
        this.listview = lv;
        this.progressbar = pb;
        this.arrayadapter = aa;
    }

    ...

    @Override
    protected void onPostExecute(ArrayList<Custom object> list) {
        super.onPostExecute(list);

        arrayadapter = new ArrayAdapter<Custom object>(context, android.R.layout.simple_list_item_1, list);
        listview.setAdapter(arrayadapter);
        **activity.arrayadapter = arrayadapter;**

        progressbar.setVisibility(ProgressBar.GONE);
        listview.setVisibility(ListView.VISIBLE);
    }

}

Yeah, it worked! Thank you Joel, but I'm still wondering why I can pass listview from MainActivity, call a function on that listview in AsyncTask and normally work with that listview back in MainActivity, any ideas?

And another question: is it right, that the only difference in passing an Activity object instead of a Context object, is you're having access to the available variables and methods you defined in your Activity?

4 Comments

You're welcome! When you pass listview to the AsyncTask, the task is given a copy of the listview that is in your activity. So it can do whatever it wants with that listview and it will not change the one in your activity. And yes, that is essentially it. With a context, you never really know what kind of object that is a representation of. If you want, you can cast a context as an instance of your activity by doing 'MainActivity activity = (MainActivity) context;' and then you have full access to any functions in the MainActivity class!
But it will throw a null pointer exception if you try and cast a context that is not an instance of your activity.
after what you said, am I right in assuming that Context is generally superfluous or am I missing sth?
Kind of... for example, in a call such as Toast.makeText(this,...); where this refers to an activity. activity is actually a subclass of context, so you can pass it as a context argument like in the make text method. Context is ambiguous, and has several subclasses. so if you have an instance of context, it also likely secretly an instance of one of its subclasses (such as activity). Maybe read the developer notes on context if you think that might help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.