I'm trying to learn how to work with AsyncTask. I have code in the doInBackground that returns a String array, and a callback that invokes an interface to return it to the MainActivity. I am successfully executing the AsyncTask.
The problem is: trying to return the array via onPostExecute I'm getting an arguments error; it won't accept the array. How do I use the onPostExecute method to return the value feeds? I have tried to change the result of doInBackground but that wouldn't accept an array either.
Here is the interface called in MainActivity:
interface DownloadFinishedListener {
void notifyDataRefreshed(String[] feeds);}
Here is the callback:
try {
mCallback = (DownloadFinishedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement DownloadFinishedListener");
}
and here is the AsyncTask:
public class DownloaderTask extends AsyncTask<Integer, Void, String> {
#Override
protected String doInBackground(Integer... params) {
downloadTweets(params);
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
mCallback.notifyDataRefreshed(s); //trying to send back feeds
}
// Simulates downloading Twitter data from the network
private String[] downloadTweets(Integer resourceIDS[]) {
final int simulatedDelay = 2000;
String[] feeds = new String[resourceIDS.length];
try {
for (int idx = 0; idx < resourceIDS.length; idx++) {
InputStream inputStream;
BufferedReader in;
try {
// Pretend downloading takes a long time
Thread.sleep(simulatedDelay);
} catch (InterruptedException e) {
e.printStackTrace();
}
inputStream = mContext.getResources().openRawResource(
resourceIDS[idx]);
in = new BufferedReader(new InputStreamReader(inputStream));
String readLine;
StringBuffer buf = new StringBuffer();
while ((readLine = in.readLine()) != null) {
buf.append(readLine);
}
feeds[idx] = buf.toString();
if (null != in) {
in.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
return feeds;
}
}
The problem is: trying to return the array via onPostExecute I'm
getting an arguments error; it won't accept the array
You need to pass String Array as last generic argument to AsyncTask which is return type of doInBackground and argument type of onPostExecute.
Do following changes :
1. extend AsyncTask as:
public class DownloaderTask extends AsyncTask<Integer, Void, String[]>
2. Change doInBackground method return type from String to String[] :
#Override
protected String[] doInBackground(Integer... params) {
downloadTweets(params);
return downloadTweets(params);
}
3. Change onPostExecute paramter type from String to String[] :
protected void onPostExecute(String[] s) {
super.onPostExecute(s);
mCallback.notifyDataRefreshed(s); //trying to send back feeds
}
You should pass String[] as last argument in your AsyncTask not just String as you are doing and your AsyncTask should look like similar to this:
public class DownloaderTask extends AsyncTask<Integer, Void, String[]> {
#Override
protected String[] doInBackground(Integer... params) {
return downloadTweets(params);;
}
#Override
protected void onPostExecute(String[] s) {
super.onPostExecute(s);
mCallback.notifyDataRefreshed(s); //trying to send back feeds
}
}
Related
Im studying android, and i want to make an app that connects to a service and gets the values from there..
main activity:
public class teste extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
new api().execute();
}
}
AsyncTask
public class api extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
try {
URL url = new URL("https://randomuser.me/api/0.7");
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream));
String linha;
StringBuffer buffer = new StringBuffer();
while((linha = reader.readLine()) != null) {
buffer.append(linha);
buffer.append("\n");
}
return buffer.toString();
} catch (Exception e) {
e.printStackTrace();
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
return null;
}
#Override
protected void onPostExecute(String dados) {
}
}
how can i fill a EditText in the mainactivity with the values returned from the asynctask?
Ive searched in the web, but cand find a answer that works..
thankss!
Rafael
Since you don't provide code for your EditText view, consider the following piece of code and modify accordingly to suit your case. You need to write the following on the onPostExecute method of your AsyncTask
#Override
protected void onPostExecute(String dados) {
EditText simpleEditText = (EditText) findViewById(R.id.simpleEditText); //replace here with your editText's id
simpleEditText.setText(dados); //dados contains the result returned from the doInBackground() method
}
EDIT
I now realised that the api class is in different file from the teste class, so you need to pass a reference of the latter one (the activity) to the AyncTask, api. You can do this by declaring a constructor:
public class api extends AsyncTask<Void, Void, String> {
private Activity activity;
//constructor
public api(Activity activity) {
this.activity = activity;
}
//rest of your code
#Override
protected void onPostExecute(String dados) {
EditText simpleEditText = (EditText) activity.findViewById(R.id.simpleEditText); //replace here with your editText's id
simpleEditText.setText(dados); //dados contains the result returned from the doInBackground() method
}
}
and call your api in teste:
public class teste extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
new api(this).execute();
}
}
You don't. The point of an AsyncTask is its asynchronous. It doesn't return anything. You should never call .get() on one, if you do then there's no point in using an AsyncTask. Instead, all the code that needs the result should be placed in onPostExecute.
there is any way that I can get the return data from execute action?
for example I have the next line that calls to the execute function - googlePlacesReadTask.execute(toPass); and the googlePlacesReadTask return some parser data to me. So how can I get this data that the action return to me ?
AsyncTask -
public class PlacesDisplayTask extends AsyncTask<Object, Integer, List<HashMap<String, String>>> {
JSONObject googlePlacesJson;
GoogleMap googleMap;
#Override
protected List<HashMap<String, String>> doInBackground(Object... inputObj) {
List<HashMap<String, String>> googlePlacesList = null;
Places placeJsonParser = new Places();
try {
googlePlacesJson = new JSONObject((String) inputObj[1]);
googlePlacesList = placeJsonParser.parse(googlePlacesJson);
} catch (Exception e) {
Log.d("Exception", e.toString());
}
if(String.valueOf(googlePlacesList) != "[]"){
//Find the place
}
else{
//No place found
}
return googlePlacesList;
}
}
second AsyncTask -
public class GooglePlacesReadTask extends AsyncTask<Object, Integer, String> {
String googlePlacesData = null;
GoogleMap googleMap;
#Override
protected String doInBackground(Object... inputObj) {
try {
googleMap = (GoogleMap) inputObj[0];
String googlePlacesUrl = (String) inputObj[1];
Http http = new Http();
googlePlacesData = http.read(googlePlacesUrl);
} catch (Exception e) {
Log.d("Google Place Read Task", e.toString());
}
return googlePlacesData;
}
#Override
protected void onPostExecute(String result) {
PlacesDisplayTask placesDisplayTask = new PlacesDisplayTask();
Object[] toPass = new Object[2];
toPass[0] = googleMap;
toPass[1] = result;
placesDisplayTask.execute(toPass);
}
}
Thanks.
Based on Which type of data you want to get from that method. If that method returns String data then save it in String variable.
For example :
In your case if googlePlacesReadTask returns String type of data then store it in string variable like :
String data = googlePlacesReadTask.execute(toPass);
Hope it will help
Use the onPostExecute method of your AsyncTask, there you have the response from the service (sent by the background process), handle it as you need.
If you need the data back in your class, you can send the AsyncTask a reference to it and call one class method from your AsyncTask sending it the required data
Just one way of doing it, there are more.
Dummy example:
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
private MyClass myClass;
public MyAsyncTask(MyClass myClass) {
this.myClass = myClass;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(Void... params) {
return something;
}
#Override
protected void onPostExecute(String something) {
super.onPostExecute(something);
if(myClass != null){
myClass.thereYouGo(something);
}
}
}
From your class (MyClass):
new MyAsyncTask(this).execute();
Receiver method in MyClass:
public void thereYouGo(String something){
// do what you want
}
Hello so I have already an expirience with AsyncTask so I can manage to get some data with PHP scripts from an SQL Server and parsed them with JSON. Now what I would want is to know how can I use the AsyncTask in order to load images to some activities. Also is there anyway that I can call the AsyncTask before the app starts? because that would be really helpful too.
I don't have any adapters I am just using this for the AsyncTask:
// The definition of our task class
private class PostTask extends AsyncTask<String, Integer, String> {
private String postName;
private JSONObject jsonvar = new JSONObject();
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
this.postName = params[0];
String status = "";
List<NameValuePair> values = new ArrayList<NameValuePair>();
values.add( new BasicNameValuePair( "username", this.postName ) );
final AndroidHttpClient client = AndroidHttpClient.newInstance( "" );
HttpResponse response = HttpHelper.postResponse( client, Register.phpUrl, values );
String data = HttpHelper.getData( response );
try {
jsonvar = new JSONObject(data);
status=jsonvar.getString("status");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
client.close();
return status;
}
// #Override
// protected void onProgressUpdate(Integer... values) {
// super.onProgressUpdate(values);
// }
#Override
protected void onPostExecute(String status) {
String session = "", status_message = " ";
try {
status_message = jsonvar.getString("status_message");
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
super.onPostExecute(status);
}
}
}
As i can tell with information provided, supposing that what you read from your server is the image URL and obtain it in JSON format, what i would do is writing a listener to your AsyncTask, calling it in onPostExecute method, and loading it in your Activity using PicassoImagesLoader
Something like:
private class PostTask extends AsyncTask<String, Integer, String> {
public interface onLoadFinishedListener {
public void onLoadFinished(JSONObject response)
}
protected JSONObject onPostExecute(JSONObject response){
onLoadFinished(response);
}
}
And in your Activity:
public myActivity extends Activity implements PostTask.onLoadFinishedListener {
#Override
onLoadFinished(JSONObject response){
Picasso.with(this).load(response.getString("url")).into(imageView);
}
}
Something like this would help :)
This is my first async task, which gets called first, it gets data from server and then onPostExecute it executes other async task, which downloads and sets image.
private class GetData extends AsyncTask<String, Void, Void> {
private final HttpClient client = new DefaultHttpClient();
private String content;
private String error = null;
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... progress) {
}
#Override
protected Void doInBackground(String... params) {
try {
HttpGet httpget = new HttpGet(params[0]);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
content = client.execute(httpget, responseHandler);
} catch (ClientProtocolException e) {
error = e.getMessage();
cancel(true);
} catch (IOException e) {
error = e.getMessage();
cancel(true);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if (error == null) {
try {
JSONObject dataDishes = new JSONObject(content);
Log.d("DISHES", dataDishes.toString());
ArrayList<DishModel> dishData = new ArrayList<DishModel>();
for (int i = 0; i < 8; i++) {
DishModel model = new DishModel();
model.setName("Company " + i);
model.setDesc("desc" + i);
//TODO: set data img
new GetImage(model).execute("http://example.com/" + (i + 1) + ".png");
dishData.add(model);
}
ListView listAllDishes = (ListView) getView().findViewById(R.id.listView);
DishRowAdapter adapterAllDishes = new DishRowAdapter(getActivity(),
R.layout.dish_row, dishData);
listAllDishes.setAdapter(adapterAllDishes);
} catch (JSONException e) {
Log.d("DISHES", e.toString());
}
} else {
Log.e("DISHES", error);
}
}
}
This is another async task, it downloads image and onPostExecute it sets image to passed model.
private class GetImage extends AsyncTask<String, Void, Void> {
private DishModel model;
private Bitmap bmp;
public getImage(DishModel model) {
this.model = model;
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... progress) {
}
#Override
protected Void doInBackground(String... params) {
try {
URL url = new URL(params[0]);
Log.d("DISHES", params[0]);
try {
bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (IOException e) {
Log.d("DISHES", e.toString());
}
} catch (MalformedURLException e) {
Log.d("DISHES", e.toString());
}
return null;
}
#Override
protected void onPostExecute(Void result) {
model.setPhoto(bmp);
}
}
It works if I do both data/image download proccess in one AsyncTask doInBackground(String... params), but it doesnt when I split data and image downloading into seperate async tasks. Furthermore I dont get any exceptions or errors.
UPDATE: Images shows up when i switch views..
At first, getImage and getData are classes, and classes names in Java are capitalized.
Technically, you can run another AsyncTask from onProgressUpdate() or onPostExecute() - https://stackoverflow.com/a/5780190/1159507
So, try to put the breakpoint in second AsyncTask call and debug is it called.
Is it possible to make AsyncTask.doInBackground synchronized - or achieve the same result in another way?
class SynchronizedTask extends AsyncTask {
#Override
protected synchronized Integer doInBackground(Object... params) {
// do something that needs to be completed
// before another doInBackground can be called
}
}
In my case, any AsyncTask.execute() can be started before a previous one has completed, but I need to execute the code in doInBackground only after the previous task has finished.
EDIT: As correctly pointed out, the synchronization works only on the same object instance.
Unfortunately, it is not possible to create an AsyncTask and call execute() more than once on the same object instance, as specified in the "Threading rules" section of the AsyncTask documentation.
The solution is to use a custom Executor to serialize the tasks, or, if you use API 11 or above, AsyncTask.executeOnExecutor(), as suggested in the comments below.
I posted an answer showing an implementation of a SerialExecutor that can be used to queue tasks that will be executed sequentially.
Ideally, I'd like to be able to use AsyncTask.executeOnExecutor() with a SERIAL_EXECUTOR, but this is only available for API level 11 or above:
new AsyncTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params);
To target the Android APIs below level 11, I ended up implementing a custom class which encapsulates an ExecutorService with a thread pool size of 1. The full code is open-sourced here.
Executors.newFixedThreadPool(int nThreads) creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue. At any point, at most nThreads threads will be active processing tasks. In my case, nThreads is 1, which means tasks can be queued, but only one task will be executed at any given time.
Here is the code:
public abstract class SerialExecutor {
private final ExecutorService mExecutorService;
public SerialExecutor() {
mExecutorService = Executors.newFixedThreadPool(1);
}
public void queue(Context context, TaskParams params) {
mExecutorService.submit(new SerialTask(context, params));
}
public void stop() {
mExecutorService.shutdown();
}
public abstract void execute(TaskParams params);
public static abstract class TaskParams { }
private class SerialTask implements Runnable {
private final Context mContext;
private final TaskParams mParams;
public SerialTask(Context context, TaskParams params) {
mContext = context;
mParams = params;
}
public void run() {
execute(mParams);
Activity a = (Activity) mContext;
a.runOnUiThread(new OnPostExecute());
}
}
/**
* Used to notify the UI thread
*/
private class OnPostExecute implements Runnable {
public void run() {
}
}
}
This can be extended and used as a serial task executor in an Activity:
public class MyActivity extends Activity {
private MySerialExecutor mSerialExecutor;
#Override
public void onCreate(Bundle savedInstanceState) {
// ...
mSerialExecutor = new MySerialExecutor();
}
#Override
protected void onDestroy() {
if (mSerialExecutor != null) {
mSerialExecutor.stop();
}
super.onDestroy();
}
public void onTrigger(int param) {
mSerialExecutor.queue(this, new MySerialExecutor.MyParams(param));
}
private static class MySerialExecutor extends SerialExecutor {
public MySerialExecutor() {
super();
}
#Override
public void execute(TaskParams params) {
MyParams myParams = (MyParams) params;
// do something...
}
public static class MyParams extends TaskParams {
// ... params definition
public MyParams(int param) {
// ... params init
}
}
}
}
You may want to think about using IntentService instead. It seems like it may be a better fit for your process since it has built in features for queuing.
public class RestAsyncTask1 extends AsyncTask<String, Void, String> {
private AsyncTaskCompleteListener callback;
private Context context;
private String method;
private static final AtomicInteger PROGRESS_NUM = new AtomicInteger(0);
private static ProgressDialog PROGRESS_DIALOG;
public RestAsyncTask1(Context context, AsyncTaskCompleteListener callback, String method) {
this.callback = callback;
this.context = context;
this.method = method;
}
public static String format(String url, String... params) {
String[] encoded = new String[params.length];
for (int i = 0; i < params.length; i++) {
encoded[i] = Uri.encode(params[i]);
}
return String.format(url, (String[]) encoded);
}
#Override
protected void onPreExecute() {
int x = PROGRESS_NUM.getAndIncrement();
if (x == 0) {
String title = "M_yug";
PROGRESS_DIALOG = new ProgressDialog(context);
// PROGRESS_DIALOG.setTitle(title);
PROGRESS_DIALOG.setIndeterminate(true);
PROGRESS_DIALOG.setCancelable(false);
PROGRESS_DIALOG.setOnCancelListener(null);
PROGRESS_DIALOG.setMessage("Loading. Please wait...");
PROGRESS_DIALOG.show();
}
}
#Override
protected String doInBackground(String... params) {
String url = params[0];
String response = null;
HttpURLConnection connection = null;
if (params.length > 1) {
if (method.equals(Method.GET)) {
url = format(url, (String[]) Arrays.copyOfRange(params, 1, params.length));
} else if (params.length > 2) {
url = format(url, (String[]) Arrays.copyOfRange(params, 1, params.length - 1));
}
try {
URL call = new URL(url);
connection = (HttpURLConnection) call.openConnection();
connection.setRequestProperty("Content-Type", "application/json");
//connection.setRequestProperty("M-Yug", Utilities.VERSION);
connection.setRequestMethod(method);
connection.setDoOutput(true);
if (method.equals("POST")) {
BufferedOutputStream outputStream = new BufferedOutputStream(connection.getOutputStream());
outputStream.write(params[params.length - 1].getBytes());
outputStream.flush();
}
int status = connection.getResponseCode();
if (status == HttpURLConnection.HTTP_OK) {
InputStream is = connection.getInputStream();
response = readValue(is);
} else if (status == 400) {
InputStream is = connection.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
reader.close();
Toast.makeText(context, "" + builder.toString(), Toast.LENGTH_SHORT).show();
}
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
return response;
}
#Override
protected void onPostExecute(String s) {
int x = PROGRESS_NUM.decrementAndGet();
if (x == 0 && PROGRESS_DIALOG != null && PROGRESS_DIALOG.isShowing()) {
PROGRESS_DIALOG.dismiss();
}
if (s!=null) {
String resopnse=s.toString();
callback.onSuccess(resopnse);
} else {
Toast.makeText(context,"Server Not Responding",Toast.LENGTH_SHORT).show();
}
}
private String readValue(InputStream is) {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
String line;
try {
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (Exception e) {
}
return sb.toString();
}
enum Method {
GET, POST
}
}
AsyncTask is used to run a background thread so that you current process is not interupted .
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
where first of all your doInBackground function iscalled and the returned object will move to on post execute.
which line of code you want to run after some process you can put that in PostExecute function.
this will surely help you