I have developed a class that manages all my API calls to my server (via AsyncTask)
problem is, that I want after the doInBackground(), in the onPostExecute() to pass externally a callback function that will be executed in the onPostExecute().
In that way, I can keep my communication class generic, and the Activity will send it a callback to activate and update the UI.
Any idea how do I do that?
thanks!
although answer is accepted, just adding another, real anonymous implementation. hope this help others.
your interface : you can implement this inside AsyncTask class.
public interface ImageLoaderListener{
void imageDownloaderCallBack(Bitmap bmp);
}
AsyncTask class Constructor :
// declare interface variable
private ImageLoaderListener listener;
private String link;
public ImageDownloader(String link, ImageLoaderListener listener){
this.link = link;
this.listener = listener;
}
onPostExecution :
#Override
protected void onPostExecute(Void result){
listener.imageDownloaderCallBack(bitmap);
// your code, i was returning bitmap
}
implementation in Activity class :
ImageDownloader imageDownloader = new ImageDownloader(url, new ImageLoaderListener(){
#Override
public void imageDownloaderCallBack(Bitmap bmp) {
// update Ui elements
}
});
imageDownloader.execute();
Also, you should remember that if any Ui elements need to be updated based on imageDownloaderCallBack return values, you should write that code inside function itself.
Here you go mate:
public class ApiMethods {
public interface OnCommandFinished {
public void onApiSuccess(String result);
public void onApiError(String error);
}
public void like(PARAMS .... , OnCommandFinished respondTo){
new runRequestTask(respondTo).execute(uri, params);
}
private class runRequestTask extends AsyncTask<Object, Void, String>{
private final OnAtomicCommandFinished mRespondTo;
public runRequestTask(OnCommandFinished respondTo){
mRespondTo = respondTo;
}
#Override
protected void onPostExecute(String result) {
// IF SUCCESS
mRespondTo.onAtomicSuccess(result);
// IF ERROR
mRespondTo.onApiError("404....");
}
}
}
To run the code, you simply call like(...) with a class that implements the OnCommandFinished
Related
I am currently working on project. It involves reading data from cloud server continuously. I am using ubidots server. Currently i have created class that extends to asynctask class like this
public class ApiUbidots extends AsyncTask<Integer, Void, Void> {
private final String API_KEY = "1XXXXXXXXX";
private static final String tempID = "56XXXXXXXX";
#Override
protected Void doInBackground(Integer... params) {
final ApiClient apiClient = new ApiClient(API_KEY);
Variable tempVariable = apiClient.getVariable(tempID);
Value[] tempValues = tempVariable.getValues();
Double vlStr = tempValues[0].getValue();
String tempValue = String.valueOf(vlStr);
Log.i(TAG, "TEMPERATURE VALUE IS ====" + tempValue);
tempTextView.setText(tempValue);
return null;
}
}
now i am trying to set the values i got from server to display on textview but i cannot set in this class.
I need to find a way where the textview have to be changed whenever the data variable changes
Can anyone please help me how to proceed to get it working.
Thank you!
If you have this class defined as a subclass, all you need to do is update your TextView in the onPostExecute() method of your AsyncTask. If this task is a class in a separate file, you would define a callback to send data back to the calling Activity, then update your TextView with the data you receive in the callback. Here's some example code:
Your AsyncTask would look something like this. Notice it defines a public interface that acts as a callback for the results of the task.
import android.os.AsyncTask;
public class TestTask extends AsyncTask<String, Void, String> {
TestTaskCallback listener;
public TestTask(TestTaskCallback listener) {
this.listener = listener;
}
protected String doInBackground(String... args) {
String input = args[0];
String output = "simulated return value";
return output;
}
protected void onPostExecute(String result) {
listener.onResultReceived(result);
}
public interface TestTaskCallback {
void onResultReceived(String result);
}
}
Then your calling Activity would implement the callback, fire the Task, then wait for the result, like this:
public class TestActivity extends AppCompatActivity implements TestTask.TestTaskCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
new TestTask(this).execute("Some input");
}
public void onResultReceived(String result) {
Log.d("TEST TASK RESULT", result);
}
}
Once the result comes in, you can use it in your Activity to update your TextView. And as I mentioned above, this is all way easier if you just subclass the Task right in the Activity itself. That way, you'll just have access to your TextViews right from the Task. No need to mess with callbacks at that point.
I am new to Android. I am using Sockets in an asynchronous task and I wish to pass data back to the activity that called it. But I do not want the asynchronous task to handle the UI. I just wish to pass data.
The class that e![enter image description here][1]xtends async task is not a part of the class that extends activity
My activity has 2 buttons. When the button is clicked, async task is called and corresponding changes should be made to rest of the activity.
From How do I send data back from OnPostExecute in an AsyncTask:
class YourActivity extends Activity {
private static final int DIALOG_LOADING = 1;
public void onCreate(Bundle savedState) {
setContentView(R.layout.yourlayout);
new LongRunningTask1().execute(1,2,3);
}
private void onBackgroundTaskDataObtained(List<String> results) {
//do stuff with the results here..
}
private class LongRunningTask extends AsyncTask<Long, Integer, List<String>> {
#Override
protected void onPreExecute() {
//do pre execute stuff
}
#Override
protected List<String> doInBackground(Long... params) {
List<String> myData = new ArrayList<String>();
for (int i = 0; i < params.length; i++) {
try {
Thread.sleep(params[i] * 1000);
myData.add("Some Data" + i);
} catch(InterruptedException ex) { }
}
return myData;
}
#Override
protected void onPostExecute(List<String> result) {
YourActivity.this.onBackgroundTaskDataObtained(result);
}
}
}
Yes you can use handler to communicate between AsyncTask and Activity, see following example, it will help,
#Override
protected void onPostExecute(Object result) {
super.onPostExecute(result);
Message message = new Message();
Bundle bundle = new Bundle();
bundle.putString("file", pdfPath);
message.setData(bundle);
handler.sendMessage(message); // pass handler object from activity
}
put following code into Activity class
Handler handler = new android.os.Handler() {
#Override
public void handleMessage(Message msg) {
String filePath = msg.getData().getString("file"); // You can change this according to your requirement.
}
};
If you dont't aware of Handler class then first read following link, it will help you
https://developer.android.com/training/multiple-threads/communicate-ui.html
There are different way to pass data back to activity. As explained below
Suppose u have one class
public class Socket {
private Activity activity;
//create interface
public interface OnAyscronusCallCompleteListener{
public void onComplete(/*your data as parameter*/);
}
private void setAsyncListener(Activity activity){
this.activity = activity;
}
//rest of your code
// send back data to activity
activity.onComplete(/* your data */)
}
//Now your activity
class YourActivity extends Activity implements Socket.OnAyscronusCallCompleteListener {
// rest of your activity life cycle methods
onCreate(Bundle onSaved)
{Socket socket = new Socket();
socket.setAsyncListener(this);
}
public void onComplete(/*your data*/){
// perform action on data
}
}
In your Activity Class
new YourAsyncTask().execute("String1","String2","12");
Your AsyncTask
AsyncTask<Params, Progress, Result>
private class YourAsyncTask extends AsyncTask<String, Void, Void > {
protected Long doInBackground(String... s) {
String s1 = s[0]; //="String1";
String s2 = s[1]; //="String2";
int s1 = Integer.parseInt(s[2]); //=3;
}
protected void onProgressUpdate(Void... values) {
}
protected void onPostExecute() {
}
}
A great explanation is here
Example to implement callback method using interface.
Define the interface, NewInterface.java.
package javaapplication1;
public interface NewInterface {
void callback();
}
Create a new class, NewClass.java. It will call the callback method in main class.
package javaapplication1;
public class NewClass {
private NewInterface mainClass;
public NewClass(NewInterface mClass){
mainClass = mClass;
}
public void calledFromMain(){
//Do somthing...
//call back main
mainClass.callback();
}
}
The main class, JavaApplication1.java, to implement the interface NewInterface - callback() method. It will create and call NewClass object. Then, the NewClass object will callback it's callback() method in turn.
package javaapplication1;
public class JavaApplication1 implements NewInterface{
NewClass newClass;
public static void main(String[] args) {
System.out.println("test...");
JavaApplication1 myApplication = new JavaApplication1();
myApplication.doSomething();
}
private void doSomething(){
newClass = new NewClass(this);
newClass.calledFromMain();
}
#Override
public void callback() {
System.out.println("callback");
}
}
Then regarding your answer, in actually you have a 2 possibilities... The first one is the answer from #Rodolfoo Perottoni and the other possibility are correctly, read this post please!
I prefer the second way because I can update when I need it.
I would create a inner class in the MainActivity that extends the AsyncTask and voila all data is there already by getters.
During my implantation I need to throw several exceptions from a class, and handle them outside.
Inside the class I made, I also implemented AsyncTask private class, and from this class , as well, I need to throw the exceptions.
I realized that I cannot throw any exception from AsyncTask class, but only to handle it. This is not what I need.
Is there some kind of solution, so I'll be able to throw any exception I want from inside the AsyncTask?
I do something like below.
- Write your own implementation of MyListener class.Pass it in the constructor of MyAsyncTask class.
- Check the return value of doInBackground method,and call relevant method.
public interface MyListener {
public void onSuccess();
public abstract void onFail();
}
public class MyAsyncTask extends AsyncTask<String, Void, String>{
private MyListener listener;
public MyAsyncTask(MyListener listener){
this.listener = listener;
}
protected String doInBackground(String... params) {
return aValue;
}
protected void onPostExecute(String aValue) {
//Check aValue,if OK
listener.onSuccess();
//else
listener.onFail();
}
}
I use an AsyncTask to perform a long process.
I don't want to place my long process code directly inside doInBackground. Instead my long process code is located in another class, that I call in doInBackground.
I would like to be able to call publishProgress from inside the longProcess function.
In C++ I would pass a callback pointer to publishProgress to my longProcess function.
How do I do that in java ?
EDIT:
My long process code:
public class MyLongProcessClass
{
public static void mylongProcess(File filetoRead)
{
// some code...
// here I would like to call publishProgress
// some code...
}
}
My AsyncTask code:
private class ReadFileTask extends AsyncTask<File, Void, Boolean>
{
ProgressDialog taskProgress;
#Override
protected Boolean doInBackground(File... configFile)
{
MyLongProcessClass.mylongProcess(configFile[0]);
return true;
}
}
EDIT #2
The long process method could also be non-static and called like this:
MyLongProcessClass fileReader = new MyLongProcessClass();
fileReader.mylongProcess(configFile[0]);
But that does not change my problem.
The difficulty is that publishProgress is protected final so even if you pass this into your static method call you still can't call publishProgress directly.
I've not tried this myself, but how about:
public class LongOperation extends AsyncTask<String, Integer, String> {
...
#Override
protected String doInBackground(String... params) {
SomeClass.doStuff(this);
return null;
}
...
public void doProgress(int value){
publishProgress(value);
}
}
...
public class SomeClass {
public static void doStuff(LongOperation task){
// do stuff
task.doProgress(1);
// more stuff etc
}
}
If this works please let me know! Note that calling doProgress from anywhere other than a method that has been invoked from doInBackground will almost certainly cause an error.
Feels pretty dirty to me, anyone else have a better way?
A solution could be placing a simple public class inside the AsyncTask (make sure the task you define is also public) which has a public method that calls publishProgress(val). Passing that class should be available from any other package or class.
public abstract class MyClass {
public MyClass() {
// code...
}
// more code from your class...
public class Task extends AsyncTask<String, Integer, Integer> {
private Progress progress;
protected Task() {
this.progress = new Progress(this);
}
// ...
#Override
protected Integer doInBackground(String... params) {
// ...
SomeClass.doStuff(progress);
// ...
}
// ...
#Override
protected void onProgressUpdate(Integer... progress) {
// your code to update progress
}
public class Progress {
private Task task;
public Progress(Task task) {
this.task = task;
}
public void publish(int val) {
task.publishProgress(val);
}
}
}
}
and then in the other class:
public class SomeClass {
public static void doStuff(Progress progress){
// do stuff
progress.publish(20);
// more stuff etc
}
}
This worked for me.
Split up the longProcess() function into smaller functions.
Sample code:
#Override
protected Boolean doInBackground(Void... params) {
YourClass.yourStaticMethodOne();
publishProgress(1);
YourClass.yourStaticMethodTwo();
publishProgress(2);
YourClass.yourStaticMethodThree();
publishProgress(3);
// And so on...
return true;
}
If this works please let me know! Note that calling doProgress from anywhere other than a method that has been invoked from doInBackground will almost certainly cause an error.
Yes, it works. I extended it so that you don't need to pass the AsyncTask as a parameter to your method. This is particularly useful if (like me) you've already written all your methods before deciding that actually you do need to publish some progress, or in my case, update the UI from an AsyncTask:
public abstract class ModifiedAsyncTask<A,B,C> extends AsyncTask<A,B,C>{
private static final HashMap<Thread,ModifiedAsyncTask<?,?,?>> threads
= new HashMap<Thread,ModifiedAsyncTask<?,?,?>>();
#Override
protected C doInBackground(A... params) {
threads.put(Thread.currentThread(), this);
return null;
}
public static <T> void publishProgressCustom(T... t) throws ClassCastException{
ModifiedAsyncTask<?, T, ?> task = null;
try{
task = (ModifiedAsyncTask<?, T, ?>) threads.get(Thread.currentThread());
}catch(ClassCastException e){
throw e;
}
if(task!=null)
task.publishProgress(t);
}
}
public class testThreadsActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void Button1Clicked(View v){
MyThread mthread = new MyThread();
mthread.execute((Void[])null);
}
private class MyThread extends ModifiedAsyncTask<Void, Long, Void>{
#Override
protected Void doInBackground(Void... params) {
super.doInBackground(params);
while(true){
myMethod(System.currentTimeMillis());
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
return null;
}
}
}
protected void onProgressUpdate(Long... progress) {
//Update UI
((TextView) findViewById(R.id.textView2)).setText("The Time is:" + progress[0]);
}
}
private void myMethod(long l){
// do something
// request UI update
ModifiedAsyncTask.publishProgressCustom(new Long[]{l});
}
}
Feels pretty dirty to me, anyone else have a better way?
My way is probably worse. I'm calling a static method for doProgress (which I called publishProgressCustom). It can be called from anywhere without producing an error (as if the thread has no corresponding AsyncTask in the hashMap, it won't call publishProgress). The down side is that you have to add the Thread-AsyncTask mapping yourself after the thread has started. (You can't override AsyncTask.execute() sadly as this is final). I've done it here by overriding doInBackground() in the super class, so that anyone extending it just has to put super.doInBackground() as the first line in their own doInBackground().
I don't know enough about Threads and AsyncTask to know what happens to the HashMap references once the Thread and/or AsyncTask comes to an end. I suspect bad things happen, so I wouldn't suggest anyone try my solution as part of their own unless they know better
When you say "my long process code is located in another class that I call in doInBackground", do you mean "located in another method that I call in doInBackground"?
If so, you could make that method a private method of your AsynTask class. Then you could call publishProgress inside the method whenever needed.
setAccountAuthenticatorResult can be called from the Activity, which extends AccountAuthenticatorActivity. My activity extends that, but launches ASyncTask and hence this setAccountAuthenticatorResult should be called from ASyncTask (or, the result of ASyncTask should be passed back to the main thread).
How to do it?
What is wrong in the code below?
AsyncTask<Uri, Void, Bundle> task = new RetrieveAccessTokenTask(this, consumer, provider, prefs).execute(uri);
public class RetrieveAccessTokenTask extends AsyncTask<Uri, Void, Bundle> {
private Context context;
public RetrieveAccessTokenTask(Context context, OAuthConsumer consumer,
OAuthProvider provider, SharedPreferences prefs) {
this.context = context;
}
#Override
protected void onPostExecute(Bundle result) {
context.setAccountAuthenticatorResult(); // doesn't work
}
When you create the AsyncTask, you can add a new constructor to it, and pass in a reference to the Activity:
AsyncTask myTask = new MyTask(this);
And then from the onPostExecute() method in the AsyncTask you can call the method on the Activity.
public class MyTask extends AsyncTask<String, String, String>
{
public MyActivity activity;
public MyTask(MyActivity a)
{
this.activity = a;
}
// ......
protected void onPostExecute(String result)
{
activity.myMethod();
}
}
Use Interface
Follow these steps:
1) Create an interface
public interface AsyncTaskListener{
public void updateResult(String result);
}
2) Use the listener in your AsyncTask
DownloadSongTask extends AsyncTask<String,Integer,String>{
private AsyncTaskListener listener;
public DownloadSongTask(Context context)
{
listener= (AsyncTaskListener)context; // Typecast
}
#Override
public void doInbackGround(String... params)
{
// Download code
int downloadPerc = // calculate that
publish(downloadPerc);
}
#Override
public void onPostExecute(String result)
{
listener.updateResult(String result); // Use it
}
}
3) Implement the interface in your Activity and Override the interface method
public class YourActivity extends AppcompatActivity implements AsyncTaskListener{
// Activity code //
new DownloadSongTask(this).execute("Paradise.mp3"); // this is how you start Task
public void yourMethod(String arg)
{
// Your method related Stuff
}
#Override
public void updateResult(String result){
yourMethod(result);
}
}
Advantege of using interface?
This seems a lengthy approach at first but if you use this approach
You can make a loosely coupled AsyncTask. Which means you can use same AsyncTask with any Activity in Future without even changing code in your AsyncTask.
Relevant Links:
For better understanding you can read this ANSWER