In my main activity I got an arraylist called data. I call an asynctask and do some stuff that gives me a different arraylist called values.
In the post execute of the asynctask I want to use items in 'values' to add some objects to 'data'. However, when debugging I noticed that the objects dont get added.
public class MainActivity extends Activity
{
ArrayList<DataItem> data;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
data = new ArrayList<DataItem>();
update();
}
public void update()
{
AsyncCallAWS thisTask = new AsyncCallAWS();
thisTask.execute();
}
private class AsyncCallAWS extends AsyncTask<String, Void, Void>
{
ArrayList<String> values = new ArrayList<String>();
protected void onPostExecute(Void result)
{
Log.i(TAG, "onPostExecute");
DataItem d;
for(String s : values)
{
d = new DataItem();
d.setValue(s);
d.setDataStreamName("test");
data.add(d);
}
}
//code to fill array
I'm guessing it's because I try to add items from the asynctask? Idk how to solve this, I need the data arraylist for a listview.
In AsyncTask class override method onProgressUpdate(), where you will add elements to array. Then in doInBackground() call publishProgress() for sending elements to onProgressUpdate(). Here http://developer.android.com/reference/android/os/AsyncTask.html -is great example.
private class TestAsyncTask extends AsyncTask<Object, String, Object> {
#Override
protected Object doInBackground(Object... params) {
String item = "";
//Do some stuff
publishProgress(item);
return null;
}
#Override
public void onProgressUpdate(String... value) {
data.add(value[0]);
}
#Override
protected void onPostExecute(Object result) {
}
}
I dont think you should create objects in the onPostExecute-method. Instead create it in the doInBackground-method of the class that extends AsyncTask, and then use set-methods in the onPostExecute-metod.
Related
How can I add elements to an Array or ArrayList from the AsyncTask class(Inner) , from where I am receiving data from server .
I tried adding elements from doInBackgroud() and printing them in onPostExecute() ,it works fine then .
But the Array and List are both empty when I am trying to access them outside the AsyncTask class.
Code :-
public String[][] mov_details ;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.vpmovies);
mov_details=new String[NUM_OF_MOVIES][9];
new MyHttpMovies().execute();
Toast.makeText(this,mov_details[0][2],Toast.LENGTH_LONG).show(); //prints blank
doInBackgroud() and onPostExecute() -
for(int i=0; i < jsonArray.length(); i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
//parsing some json
mov_details[i][0] = (jsonObject.optString("name").toString());
mov_details[i][1] = (jsonObject.optString("lang").toString());
mov_details[i][2] = (jsonObject.optString("genre").toString());
.
.
.
.
return mov_details;
}
protected void onPostExecute(String[][] strings) {
super.onPostExecute(strings);
Toast.makeText(VPmovies.this,strings[0][1],Toast.LENGTH_LONG).show();
// prints successfully
}
public class MainActivity extends AppCompatActivity {
ArrayList<String> list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public class fetchData extends AsyncTask<Void,Void,Void> {
#Override
protected Void onPreExecute() {
super.onPreExecute();
list = new ArrayList<String>();
}
#Override
protected Void onPostExecute(Void... params) {
...
list.add("bla bla");
...
return null;
}
}
}
Use publishProgress("data") inside your doInBackgroung and pass data from AsyncTask to your Activity/Fragment. Keep in mind doInBackgroung runs in separate thread you can not directly update your main GUI from doInBackgroung, if you will call some methods directly from doInBackgroung than your calling method should run in main thread.
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
// send data to your required location its recommended to use interfaces for communication
}
Solved by simply using the get() method on the AsyncTask instance that would return the output/result of the AsyncTask backgroud thread.
mov_details = new MyHttpMovies().execute().get(); //returns 2d array
and instead of using mov_details variable inside doInBackground() , I used some other 2d array variable local to the just AsyncTask.
I am quite new to Android Development. I am working in a app where i need to make a lot of async calls to api. For each and every API call, I have to write the similar looking AsyncTask class over and over again. So, is there any way to make these Async Calls modular?
yes it is possible use Listener and AsyncTask with parameterized constructor
Check it
Create an interface
public interface OnTaskCompletListerner {
void oncompleteListerner(String name);
}
create an AsyncTask class as follows
public class AsyncTaskModuler extends AsyncTask<Void, Void, String> {
private Context context;
private HashMap<String, String> data;
private String URL;
private OnTaskCompletListerner taskdone;
public AsyncTaskModuler(Context ctx,HashMap<String, String> data,String url,OnTaskCompletListerner taskdone){
this.context=ctx;
this.data=data;
this.URL=url;
this.taskdone=taskdone;
}
#Override
protected String doInBackground(Void... params) {
//Do the task here and return the value if needed
return null;
}
#Override
protected void onPostExecute(String result) {
taskdone.oncompleteListerner(result);
}
and call it in your activity like this
public class CallAync extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String url="";
HashMap<String, String> data=new HashMap<String, String>();
AsyncTaskModuler moduler=new AsyncTaskModuler(CallAync.this, data, url, completListerner);
moduler.execute();
}
OnTaskCompletListerner completListerner=new OnTaskCompletListerner() {
#Override
public void oncompleteListerner(String name) {
}
};
}
Create an general async task and pass your url as param to it .Hence you can reuse the same async task for all your api calls
public class myTask extends AsyncTask<Void, Void, Void> {
String muUrl;
public myTask(Context context, Activity activity,
String url) {
contxt = context;
myUrl=url;
}
#Override
protected Void doInBackground(Void... params) {
makeApiCalls();
return null;
}
}
Start the task in the following way :
new myTask(this, this, urlStr).execute();
EDIT
How can I perform different logic onPostExecute() ?
You can add another param in the constructor of myTask.
Ex.
public MyTask(Context context, Activity activity,
String url,String postExecuteAction) {
}
In your post executes just check of each case in if else and perform the respective task
Dummy Background class
private class BackGroundClass extends AsyncTask<String, Void, Bitmap> //<arg to do InBackground,,returntype of do inBackground and arg of onPostExecut>
{
public BackGroundClass()
{
}
#Override
protected void onPreExecute() //forground work in UI thread prior to doInbackground
{
super.onPreExecute();
}
#Override
protected Bitmap doInBackground(String... urls) //background work in parallel thread
{
Bitmap b=null;
// your background work
return b;
}
#Override
protected void onPostExecute(Bitmap result) //forground work in UI thread post to doInbackground
{
super.onPostExecute(result);
if(result!=null)
{
//use bitmap image in result
}
else
{
//Image is not available
}
}
}
Calling for one parellel execution
new BackGroundClass().execute(StringArg1,stringArg2,StringArg3);
Calling for multiple parellel execution
when tou need to call more than one background task at same time
new BackGroundClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,StringArg1,stringArg2,StringArg3);
Called from single activity
use this as an inner class to your activity for making it easy to share variable if not called from more than one activity
Called from more than one activity
use constructor to pass activity context,and other variable
new BackGroundClass(constructor arguments).execute(StringArg1,stringArg2,StringArg3);
new BackGroundClass(constructor arguments).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,StringArg1,stringArg2,StringArg3);
I am pretty much new in Java (& android), hence I can't solve it with my limited knowledge despite searching extensively.
In the code below, I want to get a JASONArray from a weblink through AsyncTask. After that I want to populate my database from the array data.
To do that I created the RemoteConnectivity class where I can populate an ArrayList importdata with all the data from JASONArray. But the problem is, I cannot access my database class mylibmandbhandler from inside RemoteConnectivity class (I guess because that is not extended to Activity). And in ImportExport class, if I write the code to insert into database just after calling RemoteConnectivity().execute() [as in code below], it starts inserting before execution ends (very obvious because it is property of AsyncTask).
Now, can anybody please guide me through this? Or any link please to understand the whole process (I am lost in at least 50 pages I read about it :( ).
P.S. mylibmandbhandler is a Class I created (not activity) in my package src folder for my database operations.
public class ImportExport extends Activity {
public void webimport(View v){
new RemoteConnectivity().execute(); // START OF ASYNCTASK
//INSERT importdata INTO DATABASE AFTER EXECUTE
mylibmandbhandler db = new mylibmandbhandler(this);
for (String[] s : importdata){
db.addRecord(new mylibman(s));
}
}
final ArrayList<String[]> importdata = new ArrayList<String[]>();
private class RemoteConnectivity extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
..................
..................
importdata.add(dataline); // POPULATE ARRAYLIST IMPORTDATA
return null;
}
#Override
protected void onPostExecute(Void result1)
{
// WHAT TO WRITE HERE
}
}
}
You should insert the data in the onPostExecute as follows:
public class ImportExport extends Activity {
public void webimport(View v){
new RemoteConnectivity().execute(); // START OF ASYNCTASK
}
final ArrayList<String[]> importdata = new ArrayList<String[]>();
private class RemoteConnectivity extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
..................
..................
importdata.add(dataline); // POPULATE ARRAYLIST IMPORTDATA
return null;
}
#Override
protected void onPostExecute(Void result1)
{
//INSERT importdata INTO DATABASE AFTER EXECUTE FINISH (POST EXECUTE)
mylibmandbhandler db = new mylibmandbhandler(ImportExport.this);
for (String[] s : importdata){
db.addRecord(new mylibman(s));
}
}
}
}
The reason is because, onPostExecute is the method (callback) which is executed after the data has been done downloading in the doInBackground method.
Alternatively: You can also put the insert statements inside the doInBackground if you want the inserting to be done by background thread. This may be helpful, if inserting into the database is time consuming. In such a case the UI thread won't block. '
public class ImportExport extends Activity {
public void webimport(View v){
new RemoteConnectivity().execute(); // START OF ASYNCTASK
}
final ArrayList<String[]> importdata = new ArrayList<String[]>();
private class RemoteConnectivity extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
..................
..................
importdata.add(dataline); // POPULATE ARRAYLIST IMPORTDATA
//INSERT importdata INTO DATABASE. NOW DONE IN THE BACKGROUND THREAD (Alternate method)
mylibmandbhandler db = new mylibmandbhandler(ImportExport.this);
for (String[] s : importdata){
db.addRecord(new mylibman(s));
}
return null;
}
#Override
protected void onPostExecute(Void result1)
{
}
}
}
Update: The important this to highlight in my answer is that I used new mylibmandbhandler(ImportExport.this); instead of new mylibmandbhandler(this); as this refers to AsyncTask which is not what the constructor supports.
You need to use method onPostExecute to insert data to datatable. Like this:
private class RemoteConnectivity extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
..................
..................
importdata.add(dataline); // POPULATE ARRAYLIST IMPORTDATA
return null;
}
#Override
protected void onPostExecute(Void result1)
{
//INSERT importdata INTO DATABASE AFTER EXECUTE FINISH (POST EXECUTE)
mylibmandbhandler db = new mylibmandbhandler(ImportExport.this);
for (String[] s : importdata){
db.addRecord(new mylibman(s));
}
}
}
how do I return a List generated in an AsyncTask back to the Activity?
My LoadStringsAsync class:
public class LoadStringsAsync extends AsyncTask<Void, Void, List<String> > {
List<String> str;
#Override
protected void onPreExecute() {
super.onPreExecute();
...
}
#Override
protected List<String> doInBackground(Void... arg0) {
...
get content from the internet
and
fill the list
...
}
#Override
protected void onPostExecute(List<String> str) {
super.onPostExecute(events);
...
}
}
and I need the List back in my Activity to work with it. (No not only to show it in ListView :P)
Any suggestions how to do this? :-)
Thanks so far!
your Activity:
public class YourActivity extends Activity {
private List<String> list = new ArrayList<String>();
public void onCreate(Bundle state) {
//...
}
public void setList(List<String> list) {
this.list = list;
}
private void fireYourAsyncTask() {
new LoadStringsAsync(this).execute();
}
}
AsyncTask:
public class LoadStringsAsync extends AsyncTask<Void, Void, List<String>> {
List<String> str;
private YourAcitivity activity;
public LoadStringsAsync(YourAcitivity activity) {
this.activity = activity;
}
#Override
protected List<String> doInBackground(Void... arg0) {
}
#Override
protected void onPostExecute(List<String> str) {
super.onPostExecute(events);
activity.setList(str);
}
}
If you make your AsyncTask an inner class in your Activity, then onPostExecute will be in the same context as the Activity, and you can use the List as you would anywhere in the Activity.
If you don't make your AsyncTask an inner class in your Activity, then you need to set up a listener to call back to your Activity when the AsyncTask finishes. If you prefer to go that route look at this post.
There is also this post that is similar to your question.
According to the documentation from android link you can use the get method to return computational result. Since your AsyncTask shows that you are returning a List, then you can try the following code in the class you are calling the asynchronous class
List<String> returnedlist=new LoadStringAsync().execute().get();
Hoping this option helps.
Place code that uses the list, or sets it to a variable, inside onPostExecute().
Better run your task from parent Activity like:
public class MyActivity extends Activity{
private List<String> mData = new ArrayList<String>();
private void runTask(){
new LoadStringsAsync(){
#Override
protected void onPostExecute(List<String> str) {
super.onPostExecute(events);
mData.clear();
mData.addAll(str);
}
}.execute();
}
}
You can send your list to a handler inside a Message :
Message msg = Message.obtain();
msg.obj = myList;
handler.sendMessage(msg);
More infos : http://developer.android.com/reference/android/os/Message.html
I have doInBackground(). after function I want to change some TextView on MainActivity.
but When I trigger the function on main activity I got NullPointerException on TextView line.
protected String doInBackground(Object... arguments) {
some code..
return result;
}
#Override
protected void onPostExecute(String result) {
if(result!=null)
new MainActivity().setScoreListUpdate(result);
}
MainActivity:
public void setScoreListUpdate(String settings)
{
String[] yeniscore = settings.split("\\|");
if(yeniscore.length > 1)
{
birinci.setText(yeniscore[1]); << NULLPOINTEREXC.
}
}
The reason this gives a NullPointerException is that you create a new instance of MainActivity instead of working on your existing one.
What you need to do is pass a reference to your Activity to the AsyncTask and then call your method on that reference.
So in your AsyncTask-class you will have a variable:
private MainActivity myMainActivity;
Add a constructor to your AsyncTask-class:
public MyAsyncTaskClassName( MainActivity activity ) {
myMainActivity = activity;
}
Then in onPostExecute you do:
myMainActivity.setScoreListUpdate(result);
Use
MainActivity.this.setScoreListUpdate(result);
instead of
new MainActivity().setScoreListUpdate(result);
in yout postExecute method.
Also, TextView called birinci should be a field in your MainActivity class, not just a variable in the onCreate method for example.
EDIT: It works like this in my program. Check out the differences.
public class DeviceSettingsStatsActivity extends ListActivity {
AsyncTask<Void, Integer, ListAdapter> task = null;
ListAdapter listAdapter = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
task = new ComputeTask().execute();
}
protected void viewComputeResult(ListAdapter result) {
setListAdapter(result);
}
private class ComputeTask extends AsyncTask<Void, Integer, ListAdapter> {
#Override
protected ListAdapter doInBackground(Void... params) {
// some stuff
}
#Override
protected void onPostExecute(ListAdapter result) {
DeviceSettingsStatsActivity.this.viewComputeResult(result);
}
}
}