AsyncTask onPostExecute listener [duplicate] - java

This question already has answers here:
how to return result from asyn call
(2 answers)
Closed 7 years ago.
Activity.java
//Activity stuff
MyClass mc = new MyClass();
mc.getText();
public void dosomething() {
textview.setText(mc.getText());
}
MyClass.java
class MyClass {
String text;
public void setText() {
class GetTextFromWEB extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String url = urls[0];
String output;
//Getting text from web
return output;
}
#Override
protected void onPostExecute(String _text) {
text = _text;
}
}
String url = "google.com";
//Doing with url something
new GetText().execute(url);
}
public String getText() {return text;}
}
Promblem is - in activity setText do faster, then AsyncTask do it's job.
So when setText run, it's run like setText(null)
I need to check in activity, is asynk ended, so i have my text to set.
I hope i explained it
And i don't even need exactly AsyncTask, i need jsoup working, so if there is solution with another thread-class, with which jsoup will work, i can use it
Edit
class GetLyrics extends AsyncTask<String, Void, String> { //Class for getting lyrics
private Context con;
public GetLyrics(Context con) {
this.con = con;
}
#Override
protected String doInBackground(String... urls) {
//do something
}
#Override
protected void onPostExecute(String _lyrics) {
lyrics = _lyrics;
con.runOnUiThread(new Runnable() {
#Override
public void run() {
((TextView) findViewById(R.id.lyricsOutput)).setText(lyrics);
}
});
}
}

Call the method setting your text in the postExecute inside your AsyncTask or set the text directly on your postExecute method.
And wrap the line with setText() inside runOnUIThread (otherwise you will get an exception saying that the view can be accessed only by the thread that created it, since you are setting the text from async task).
Setting the text would be something like this
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
((TextView) findViewById(R.id.txtFieldName)).setText("your text");
}
});
That way you can quit worrying about checking if the async task is finished. But avoid doing complex ui operations like this. Since this is just setting the text on TextView, it should be allright.

1: Make my first project from my previous post and add some new lines in it to get data from http: api's.
public class Example extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("parameter1", "xyz"));
params.add(new BasicNameValuePair("parameter2", "abc"));
params.add(new BasicNameValuePair("parameter3", "opqr"));
ServerConnection task = new ServerConnection(this, new ResultListener() {
#Override
public void result(String response) {
Toast.make(this, response, Toast.LENGTH_LONG).show();
}
#Override
public void loader(boolean visble) {
}
#Override
public void connectionLost(String error) {
Toast.make(this, error, Toast.LENGTH_LONG).show();
}
});
}
public class ServerConnection extends AsyncTask<String, String, String> implements Constant {
ResultListener listener;
private String Method = "GET";
private List<NameValuePair> params = new ArrayList<NameValuePair>();
private Context context;
private ConnectionDetector cd;
// public static Drawable drawable;
public ServerConnection(Context context, ResultListener r) {
this.context = context;
this.listener = r;
cd = new ConnectionDetector(context);
this.execute();
}
public boolean isConnection() {
return cd.isConnectingToInternet();
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... arg0) {
if (!isConnection()) {
cancel(true);
return "Sorry!connection lost,try again or later";
}
ApiResponse air = new ApiResponse();
System.out.println("working hre" + "hi");
String json;
try {
json = air.makeHttpRequest(URL, getMethod(), getParams());
} catch (Exception e) {
json = e.getMessage();
cancel(true);
return json;
}
return json;
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
protected void onCancelled(String result) {
listener.connectionLost(result);
rl.connectionLost("Sorry!connection lost,try again or later");
super.onCancelled(result);
}
#Override
protected void onPostExecute(String result) {
System.out.println("onpost" + result);
listener.result(result);
listener.loader(true);
super.onPostExecute(result);
}
public String getMethod() {
return Method;
}
public void setMethod(String method) {
Method = method;
}
public List<NameValuePair> getParams() {
return params;
}
public void setParams(List<NameValuePair> params) {
this.params = params;
}
}
Example

Related

Creating a callback function using AsyncTask

I've created an AsyncTask class to handle sending and receiving from my server. What I'm trying to do is fire an event or callback when the data is received so I can use said data to manipulate the UI.
AsyncTask class:
public class DataCollectClass extends AsyncTask<Object, Void, JSONObject> {
private JSONObject collected;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
//#Override -Commented out because it doesn't like the override
protected void onPostExecute() {
try {
Log.d("Net", this.collected.getString("message"));
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
protected JSONObject doInBackground(Object... params) {
OkHttpClient client = new OkHttpClient();
// Get Parameters //
String requestURI = (String) params[0];
RequestBody formParameters = (RequestBody) params[1];
Request request = new Request.Builder().url(requestURI).post(formParameters).build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// DO something on FAIL
}
#Override
public void onResponse(Call call, Response response) throws IOException {
String jsonResponse = response.body().string();
Log.d("Net", jsonResponse);
try {
DataCollectClass.this.collected = new JSONObject(jsonResponse);
Log.d("Net", DataCollectClass.this.collected.getString("message"));
} catch (JSONException e) {
e.printStackTrace();
}
}
});
return collected;
}
}
This is working, it prints an expected line of JSON into the log.
It's called from the Activity as:
new DataCollectClass().execute(requestURI, formVars);
I've looked all over, and I can't seem to find a definitive answer on how (and where) to add a callback. Preferably, the callback code itself should be with the DataCollectClass so all related code is reusable in the same place.
Is there a way to create a custom event firing (similar to Javascript libraries) that the program can listen for?
I've been pulling my hair out over this!
UPDATE:
Since AsyncTask is redundant, I've removed it and rewrote the code (in case someone else has this same issue):
public class DataCollectClass {
private JSONObject collected;
public interface OnDataCollectedCallback {
void onDataCollected(JSONObject data);
}
private OnDataCollectedCallback mCallback;
public DataCollectClass(OnDataCollectedCallback callback, String requestURI, RequestBody formParameters){
mCallback = callback;
this.collect(requestURI, formParameters);
}
public JSONObject collect(String requestURI, RequestBody formParameters) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(requestURI).post(formParameters).build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
//TODO Add what happens when shit fucks up...
}
#Override
public void onResponse(Call call, Response response) throws IOException {
String jsonResponse = response.body().string();
Log.d("Net", jsonResponse);
try {
DataCollectClass.this.collected = new JSONObject(jsonResponse);
if(mCallback != null)
mCallback.onDataCollected(DataCollectClass.this.collected);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
return collected;
}
}
Called from Activity:
new DataCollectClass(new DataCollectClass.OnDataCollectedCallback() {
#Override
public void onDataCollected(JSONObject data) {
if(data != null) {
try {
// Do Something //
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}, requestURI, formVars);
All working perfectly!
Thanks!
If you want to utilize a callback for an AsyncTask you can handle it via the following.
Do something like this (modifying your code to add what is below)
public class DataCollectClass extends AsyncTask<Object, Void, JSONObject> {
public interface OnDataCollectedCallback{
void onDataCollected(JSONObject data);
}
private OnDataCollectedCallback mCallback;
public DataCollectClass(OnDataCollectedCallback callback){
mCallback = callback;
}
// your code that is already there
...
#Override
public onPostExecute(JSONObject response){
if(mCallback != null)
mCallback.onDataCollected(response);
}
}
Then to make the magic happen
new DataCollectClass(new OnDataCollectedCallback() {
#Override
public void onDataCollected(JSONObject data) {
if(data != null)
// DO something with your data
}
}).execute(requestURI, formVars);
However, it is worth noting, most networking libraries, including OkHttp, handle background threads internally, and include callbacks to utilize with the requests.
This also implements a custom interface, so others may be able to see how you could use this for any AsyncTask.
There is a asynchronous get in OkHttp, so you don't need an AsyncTask, but as a learning exercise, you could define your callback as a parameter something like so.
new DataCollectClass(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// DO something on FAIL
}
#Override
public void onResponse(Call call, Response response) throws IOException {
JSONObject collected = null;
String jsonResponse = response.body().string();
Log.d("Callback - Net", jsonResponse);
try {
collected = new JSONObject(jsonResponse);
Log.d("Callback - Net", collected.getString("message"));
} catch (JSONException e) {
e.printStackTrace();
}
}
}).execute(requestURI, formVars);
The AsyncTask
public class DataCollectClass extends AsyncTask<Object, Void, Call> {
private Callback mCallback;
private OkHttpClient client;
public DataCollectClass(Callback callback) {
this.mCallback = callback;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
this.client = new OkHttpClient();
}
#Override
protected void onPostExecute(Call response) {
if (response != null && this.mCallback != null) {
response.enqueue(this.mCallback);
}
}
#Override
protected Call doInBackground(Object... params) {
// Get Parameters //
String requestURI = (String) params[0];
RequestBody formParameters = (RequestBody) params[1];
Request request = new Request.Builder().url(requestURI).post(formParameters).build();
return client.newCall(request); // returns to onPostExecute
}
}
Call Webservice using asynctask is an old fashioned. You can use Volley or retrofit.
But you can use this process to call Webservice . Here is steps:
Create an Interface and implements it in your Activity/Fragment
public interface IAsynchronousTask {
public void showProgressBar();
public void hideProgressBar();
public Object doInBackground();
public void processDataAfterDownload(Object data);
}
Create Class DownloadableAsyncTask . This class is:
import android.os.AsyncTask;
import android.util.Log;
public class DownloadableAsyncTask extends AsyncTask<Void, Void, Object> {
IAsynchronousTask asynchronousTask;
public DownloadableAsyncTask(IAsynchronousTask activity) {
this.asynchronousTask = activity;
}
#Override
protected void onPreExecute() {
if (asynchronousTask != null)
asynchronousTask.showProgressBar();
}
#Override
protected Object doInBackground(Void... params) {
try {
if (asynchronousTask != null) {
return asynchronousTask.doInBackground();
}
} catch (Exception ex) {
Log.d("BSS", ex.getMessage()==null?"":ex.getMessage());
}
return null;
}
#Override
protected void onPostExecute(Object result) {
if (asynchronousTask != null) {
asynchronousTask.hideProgressBar();
asynchronousTask.processDataAfterDownload(result);
}
}
}
Now in your Activity you will find this methods.
DownloadableAsyncTask downloadAsyncTask;
ProgressDialog dialog;
private void loadInformation() {
if (downloadAsyncTask != null)
downloadAsyncTask.cancel(true);
downloadAsyncTask = new DownloadableAsyncTask(this);
downloadAsyncTask.execute();
}
#Override
public void showProgressBar() {
dialog = new ProgressDialog(this, ProgressDialog.THEME_HOLO_LIGHT);
dialog.setMessage(" Plaese wait...");
dialog.setCancelable(false);
dialog.show();
}
#Override
public void hideProgressBar() {
dialog.dismiss();
}
#Override
public Object doInBackground() {
// Call your Web service and return value
}
#Override
public void processDataAfterDownload(Object data) {
if (data != null) {
// data is here
}else{
//"Internal Server Error!!!"
}
}
Now just call loadInformation() method then you will get your response on processDataAfterDownload().

Calling notifyOnDataSetChanged in AsyncTask (not within the class)

*************PROBLEM FIXED, CHECK BELOW FOR A SOLUTION*************
I have been struggling with that nearly half a day. Cannot get it work properly.
I have AsyncTask with private method, so I can pass boolean and String values in CustomLvAdapter
private void changeJobStatus(final boolean isAppliedforAJob, final String jobID){
class ChangeJobStatus extends AsyncTask<Void,Void,String> {
//private Delegates del = null;
ProgressDialog loading;
#Override
protected void onPreExecute() {
super.onPreExecute();
if(isAppliedforAJob) {
loading = ProgressDialog.show(context, "","Canceling application", false);
}
else {
loading = ProgressDialog.show(context, "","Applying for position", false);
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//del.asyncCompleteOnCustomJob(true);
loading.dismiss();
}
#Override
protected String doInBackground(Void... v) {
String res;
HashMap<String,String> params = new HashMap<>();
params.put(Config.KEY_USER_ID, studentID);
params.put(Config.KEY_JOB_ID, jobID);
RequestHandler rh = new RequestHandler();
if(isAppliedforAJob)
res = rh.sendPostRequest(Config.URL_CANCEL_APPLICATION, params);
else
res = rh.sendPostRequest(Config.URL_APPLY_FOR_A_JOB, params);
Log.d("Stringas", "CustomListViewBackground " + res);
return res;
}
}
ChangeJobStatus cjs = new ChangeJobStatus();
cjs.execute();
}
and in onPostExcecute() I want to call notifyOnDataSetChanged() to my another activity lvAdapters.
As far as I read I have to implement delegate interface, but I didnt succeed doing that. I fail at initializing delegate in my main class, because changeJobStatus method is private and it is called in customLvAdapter class.
If I make a constructor in ChangeJobStatus class
public ChangeJobStatus(Delegates delegate)
{
this.del = delegate;
}
I have to pass something in the parameters, when excecuting it. If I pass new Delegate, my delegate implementation, which is in my another activity is not triggered.
ChangeJobStatus cjs = new ChangeJobStatus(new Delegates() {
#Override
public void asyncCompleteOnCustomJob(boolean success) {
//whatever
}
});
cjs.execute();
I hope you can help me figure out right implementation for that,
Cheers
***********SOLUTION***********
Sadly, I couldn't implement what fellow user gave to me, but I am very glad that I heard from one of you I can use broadcast receiver. And it worked.
This is what I did
Create a Broadcast Receiver in your main class
private final BroadcastReceiver broadcastJobList = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//what will happen, when event triggers
}
};
Register custom intent and register it to Broadcast receiver in your main class onCreate method or wherever you feel comfortable :)
IntentFilter filter = new IntentFilter();
filter.addAction("jobListChanged");
registerReceiver(broadcastJobList, filter);
All we left to do is send intent which will trigger Broadcast receiver. Following code in my scenario went to onPostExcecute method in custom adapter (context was initialized for Context at the beggining of custom adapter)
Intent intent = new Intent();
intent.setAction("jobListChanged");
context.sendBroadcast(intent);
Hope I will help anyone that has this problem. Cheers!
// your asynctask class
public class ChangeJobStatus extends AsyncTask<String, Void, String> {
private ProgressDialog loading;
private OnResponseListener responseListener;
private boolean isAppliedforAJob;
private Context con;
public ChangeJobStatus(Context con,boolean state) {
super();
// TODO Auto-generated constructor stub
this.con=con;
isAppliedforAJob = state;
}
public void setOnResponseListener(OnResponseListener onLoadMoreListener) {
this.responseListener = onLoadMoreListener;
}
public interface OnResponseListener {
public void onResponse(String responsecode);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
if (isAppliedforAJob) {
loading = ProgressDialog.show(con, "", "Canceling application", false);
} else {
loading = ProgressDialog.show(con, "", "Applying for position", false);
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// del.asyncCompleteOnCustomJob(true);
loading.dismiss();
responseListener.onResponse(s);
}
#Override
protected String doInBackground(String... param) {
String res="";
HashMap<String, String> params = new HashMap<>();
params.put(Config.KEY_JOB_ID, param[0]);// job id
params.put(Config.KEY_USER_ID, param[1]);// student id
RequestHandler rh = new RequestHandler();
if (isAppliedforAJob)
res = rh.sendPostRequest(Config.URL_CANCEL_APPLICATION, params);
else
res = rh.sendPostRequest(Config.URL_APPLY_FOR_A_JOB, params);
return res;
}
}
in your activity class
public class MainActivity extends Activity implements OnResponseListener {
String jobId="1",studId="1";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ChangeJobStatus cbs=new ChangeJobStatus(this, true);
cbs.setOnResponseListener(this);
cbs.execute(jobId,studId);
}
#Override
public void onResponse(String responsecode) {
// TODO Auto-generated method stub
//here u can do ur stuff with the string
}
}

Return Callback response from AsyncTask postExecute: Nullpointerexception

I've created a component which downloads an Image (in the Android side) and I want to send back size details about that image (to the JS side) of my app.
Now, I can safely say that I can call my component from JS and it will respond back with data but as soon as I add in the Async element to download the image from an URL, read it and respond I get a NullpointerException as soon as I call my callback.invoke("response text");
My problematic code is:
public void loadImage(final String url, final Callback onLoadCallback) {
...
new AsyncTask<String, Void, Void>() {
#Override
protected Void doInBackground(String... url) {
try {
theImage = Glide.with(getReactApplicationContext()).load(url[0]).asBitmap().into(-1, -1).get();
}
catch ...
return null;
}
#Override
protected void onPostExecute(Void dummy) {
if (null != theImage) {
onLoadCallback.invoke("Success"); //<== THIS LINE HERE
}
}
}.execute(url);
...
}
Now, I get that it's because I'm trying to return on a sep thread back to the main thread via the callback but I'm not sure how in the heck I'm supposed to get the info I want back to the JS side?! This is my first attempt at a component in RN so be kind! :)
Extra Info - My React module:
var MY_Image = require('NativeModules').MYImage;
var myimage = {
loadImage(url, onLoad) {
MY_Image.loadImage(url, onLoad)
},
};
module.exports = myimage;
Then in my React app view:
...
componentDidMount: function() {
myImage.loadImage('[URL to Image]',onLoad=> {
console.log('Success: '+onLoad);
});
}
Thanks for the input everyone. I've managed to sort this. I needed a class-wide variable to hold the callback in and a callback handler. Here's my code:
public class MyClass extends ReactContextBaseJavaModule {
private Bitmap mTheImage;
private Callback mCallback;
private WritableMap mResults;
public MyClass(ReactApplicationContext reactContext) {
super(reactContext);
this.mContext = reactContext;
}
private void consumeCallback(String type, WritableMap obj) {
if(mCallback!=null) {
obj.putString("type", type);
mCallback.invoke(obj);
mCallback = null;
}
}
#ReactMethod
public void doMyStuff(final String input, final Callback callback) {
if(mCallback==null) {
mResults = Arguments.createMap();
}
mCallback = callback;
new AsyncTask<String, Void, Void>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(String... params) {
try {
String myValue = params[0];
mResults.putString("myValue", myValue);
mTheImage = [method to get the image]
}
catch(Exception e) {
}
return null;
}
protected void onPostExecute(Void dummy) {
if(null!=mTheImage && null!=mCallback) {
mResults.putInt("width", mImage.getWidth());
mResults.putInt("height",mImage.getHeight());
consumeCallback("success", mResults);
}
else {
consumeCallback("error", mResults);
}
}
}.execute(url);
}
}

doInBackground of asyncTask not getting called?

In my app, when I call new RetrieveFirstThreeArtUrl().execute() doInBackground isn't getting called.. does anyone know why? This code was working a few days ago, so I have no idea what's going on..
public class RetrieveFirstThreeArtUrl extends AsyncTask<String, Void, Void> {
static final String APIURL = "http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=2ead17554acf667f27cf7dfd4c368f15&artist=%s&album=%s";
static final String APIURL_ARTIST = "http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&api_key=2ead17554acf667f27cf7dfd4c368f15&artist=%s";
#Override
public void onPreExecute() {
super.onPreExecute();
Log.v("", "Pre");
}
#Override
public Void doInBackground(String... args) {
Log.v("", "Background");
return null;
}
#Override
public void onPostExecute(Void args) {
list = (ListView) rootView.findViewById(R.id.list);
adapter = new LiveAdapter(LiveStreamFragment.this.getActivity(), oslist, LiveStreamFragment.this, list);
list.setAdapter(adapter);
}
}
Replace your code with this
before calling RetrieveFirstThreeArtUrl method, write these two lines
static final String APIURL = "http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=2ead17554acf667f27cf7dfd4c368f15&artist=%s&album=%s";
static final String APIURL_ARTIST = "http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&api_key=2ead17554acf667f27cf7dfd4c368f15&artist=%s";
And than call method RetrieveFirstThreeArtUrl, one more thing, use protected instead of public
public class RetrieveFirstThreeArtUrl extends AsyncTask<String, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.v("", "Pre");
}
#Override
protected void onPostExecute(Void result) {
list = (ListView) rootView.findViewById(R.id.list);
adapter = new LiveAdapter(LiveStreamFragment.this.getActivity(), oslist, LiveStreamFragment.this, list);
list.setAdapter(adapter);
}
#Override
protected Void doInBackground(String... params) {
Log.v("", "Background");
return null;
}
}

Start function inside overriden Asynctask method of the same class

I have AsyncTask class and I call it in my main class. I need to override the onPostExecute function and call inside ftpDisconnect(). But it does not work properly.
TempClass dj = new TempClass(serialnum) {
#Override
protected void onProgressUpdate(Integer... values) {
pr_bar.setProgress(values[0]);
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
//dj.ftpDisconnect(); //need to make this happen
super.onPostExecute(result);
}
};
dj.execute();
My TempClass:
public class TempClass extends AsyncTask<String, Integer, String> {
public TempClass(String serialnum) {
this.serialnum = serialnum;
}
#Override
protected String doInBackground(String... params) {
//do stuff
return null;
}
public boolean ftpDisconnect() {
try {
mFTPClient.disconnect();
return true;
} catch (Exception e) {
}
return false;
}
}
You can't access that instance of dj without making it final. You should be able to call ftpDisconnect from inside the class:
#Override
protected void onPostExecute(String result) {
ftpDisconnect();
super.onPostExecute(result);
}

Categories

Resources