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
Related
This is what i have so far:
I have 3 activities
In every activity is a connection to a Database to send and
recieve data
Every input (String) and Output (JSONObject) works the same
At first i implemented an asynctask in every activity to send and recieve the data
The result is handeld in the activity that started the task
To reduce the code i transfered the asynctask to an extra class
Every activity implements an interface "AsyncResponse"
My Problem is:
With the implementation i use delegate to set a reference to the calling activity. I cant find a way to change the delegation. If i want to create a new asynctask in my second activity and try to delegate it, it shows an incompatible types error.
So is there a way that i can send the asyncresults back to a specific calling activity?
Example for the implementation
public class MainActivity extends AppCompatActivity implements AsyncResponse
public void startAsync(String[] stringArray)
{
AsyncTaskRequest objMyTask = new AsyncTaskRequest(this);
// objMyTask.delegate = this; // *.delegate in another Task in not possible
objMyTask.execute(stringArray);
}
AsyncResponse Interface
public interface AsyncResponse
{
void taskDone(JSONObject x);
}
Example for the AsyncTask
public class AsyncTaskRequest extends android.os.AsyncTask<String,
Void, JSONObject>
{
//MainActivity delegate = null;
private AsyncResponse delegate;
public AsyncTaskRequest(AsyncResponse delegation)
{
delegate=delegation;
}
protected JSONObject doInBackground(String... postData)
{.......}
#Override
protected void onPostExecute(JSONObject x)
{
delegate.taskDone(x);
}
}
You can use a listener inside you ASyncTask
In your ASyncTask:
public class AsyncTaskRequest extends android.os.AsyncTask<String,
Void, JSONObject>
{
private OnTaskCompleted listener;
public interface OnTaskCompleted{
void onTaskCompleted(Boolean output);
}
private AsyncResponse delegate;
public AsyncTaskRequest(AsyncResponse delegation)
{
delegate=delegation;
}
protected JSONObject doInBackground(String... postData)
{.......}
#Override
protected void onPostExecute(JSONObject x)
{
delegate.taskDone(x);
if (listener != null)
listener.onTaskCompleted(result);
}
}
and in your java file call this function:
public OnTaskCompleted listener =new OnTaskCompleted() {
public void onTaskCompleted(Boolean output) {
//your code here
}
};
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.
I am new in Android development. Is there any way to get result from an AsyncTask in a non-activity class? I know about the standard procedure of using an interface and getting the parsed result from the onPostExecute. But this is not working, using context instead of activityname.this in the non activity class(where I sent the context as a parameter). I am building a library and it is required for that. Any help would be greatly appreciated.
in MainActivity.java --->
Library l1 = new Library();
l1.init(portalHitter, "security certificate file name");
if(l1.getLoginStatus(MainActivity.this)){
start intent to go to another activity
}
in Library.java --->
CommonMethods commonMethods;
public void init(String portalHitter, String certName){
.....
}
public boolean getLoginStatus(Context context){
if(clint is initialized){
commonMethods = new CommonMethods(context, CommonValues.LOGIN_REQUEST);
}else{
/* error */
}
if(CommonValues.LOGIN_STATUS)
return true;
else
return false;
}
in CommonMethods.java --->
public CommonMethods(Context context, int reqest_code){
this.context = context;
this.request_for_which_service = reqest_code;
executeService();
}
public void executeService(){
switch(request_for_which_service){
case CommonValues.LOGIN_REQUEST:
loginAsyncTask = new LoginAsyncTask(context, params ...);
loginAsyncTask.execute();
loginAsyncTask.delegate = context;
break;
}
}
in LoginAsyncTask.java --->
public class LoginAsyncTask extends AsyncTask<String, String, String>{
...
public LoginCompleteInterface delegate = null;
public LoginAsyncTask(Context context, params...){
...
}
doInBacground(){
..do work..
return response;
}
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(exception_identifier == 0 || exception_identifier == 1 || exception_identifier == 2){
/* display dialog for exception on timeout, socket exceptions etc */
}else{
String tempLoginStatus = loginStatus(result);
delegate.loginCompleted(tempLoginStatus);
loginProgress.dismiss();
}
}
loginStatus(String result){
// parse and return success and failure //
}
...
}
and in the LoginCompleteInterface.java --->
public interface LoginCompleteInterface {
void loginCompleted(String output);
}
Now, if commonmethods was an activity, then it did not create a problem, but now it is creating problem, even after passing the context from MainActivity.java
loginAsyncTask.delegate = context; line.
You can use Event Bus for same .
You can set a bus and subscribe to a class where you want to have the callback.
Some common Event Bus are
TinyBus
Otto
You can get with the help of Interface.
Create an Interface which has method getResponse(String data).
implements Interface to your Activity.
when you call AsyncTask from Activity pass then reference of Interface.
In AsyncTask onPostExecute() call then Interface method and pass the data as parameter.
you will get the data in override method of interface in Activity.
Code
Interface
public interface MyInterface {
public void getResponse(String data);
}
Activity Class:
public class MainActivity extends AppCompatActivity implements MyInterface {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// CAll Async Task
new AsyncTaskClass(this).execute();
}
#Override
public void getResponse(String data) {
Toast.makeText(this, data, Toast.LENGTH_SHORT).show();
}
AsyncTask Class
public class AsyncTaskClass extends AsyncTask<String, String, String> {
private MyInterface mInterface;
public AsyncTaskClass(MyInterface reference) {
mInterface = reference;
}
#Override
protected String doInBackground(String... params) {
return "this data";
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// call getResponse(_) of interface.
mInterface.getResponse(s);
}
}
----------------------For non-Activity Class--------------
public class SimpleClass implements MyInterface
{
public void someMethod()
{
// CAll Async Task
new AsyncTaskClass(this).execute();
}
}
Interface and AsyncTask class will be the same.
I tried to call the "AsyncTask" class from another class called "MainActivity" but "AsyncTask" Class is inside the class called "SiteAdapter". I tried to pass a reference but it not working. How could do that?
Main Activity:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("StackSites", "OnCreate()");
setContentView(R.layout.activity_main);
//Call the class AsyncTask
new GetAddressTask(this).execute(); // <----ERROR - GetAddressTask cannot be resolved to a type
}
}
AsyncTask inside SitesAdapter class:
public class SitesAdapter extends ArrayAdapter<StackSite> {
...//PROCESS
public class GetAddressTask extends AsyncTask<String, Void, String> {
Context mContext;
public GetAddressTask(Context context) {
super();
mContext = context;
}
//Pass a reference to MainActivity
private MainActivity mainActivity; // <--- WARNING - The value of the field SitesAdapter.GetAddressTask.mainActivity is not used
public GetAddressTask(MainActivity mainActivity)
{
this.mainActivity = mainActivity;
}
#Override
protected String doInBackground(String... arg0) {
...
}
#Override
protected void onPostExecute(String result) {
...
}
}
}
First of all, MainActivity is not a class that you can not define an object from. It extends Activity.
Change your AsyncTask class with it;
public static class GetAddressTask extends AsyncTask<String, Void, String> {
Context mContext;
public GetAddressTask(Context context) {
super();
mContext = context;
}
#Override
protected String doInBackground(String... values) {
// If you want to use 'values' string in here
String values = values[0];
}
#Override
protected void onPostExecute(String result) {
...
}
}
Then call this with it;
String values = ""; //You can pass any string value to GetAddressTask with that parameter
//Call the class AsyncTask
new SitesAdapter.GetAddressTask(this).execute(values);
make GetAddressTask static:
public static class GetAddressTask
Try this, this is working for me.
Just create a method in your SitesAdapter class and call it from your MainActivity like this :
new SitesAdapter().start(MainActivity.this);
now in your SitesAdapter class do this :
private Context mContext;
public void start(){
mContext = context;
new GetAddressTask().execute();
}
May this help you
You could make it static then call it with
SitesAdapter.GetAddressTask myClass = new SitesAdapter.GetAddressTask();
myClass.execute();
But, if you are going to be needing this in multiple activities, then it is probably worth it to take it out of that class and put it in its own file.
If you will need to update your UI from the task, you can see this answer on using an interface with a callback to your calling Activity.
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