i've got something blowing my mind all day long.
The question is, I have an AsyncTask that returns me an User Object, with all its attributes. I know that I have to return from the doInBackground method and receive in the OnPostExecute to work with my data. The fact is that i want to extract that user out of the AsyncTask method because i have to work with it in my main thread.
My AsyncTask class is placed in the MainActivity.class.
i've heard about using interfaces to get my value back but i can't understand the way to do it.
public class FetchUserDataAsyncTask extends AsyncTask<Void, Void, User> {
RequestHandler rh = new RequestHandler(); //this is the class i use to do de server conection
User user;
User ret_user;
public FetchUserDataAsyncTask(User user){
this.user = user;
}
#Override
protected void onPostExecute(User user) {
super.onPostExecute(user);
//I WANT THIS USER IN MY MAIN THREAD, TO WORK WITH ITS ATTRIBUTES
}
#Override
protected User doInBackground(Void... params) {
try {
HashMap<String, String> dataToSend = new HashMap<>();
dataToSend.put("username", user.username);
dataToSend.put("password", user.password);
ret_user = rh.sendGetRequest("myadresstophp.php", dataToSend);
} catch (Exception e) {
e.printStackTrace();
}
return ret_user;
}
and the call (when user press the log in button), a few lines above.
new FetchUserDataAsyncTask(userk).execute();
I was hoping to do something like that: (i know its not the way to do it)
User user = new FetchUserDataAsyncTask(userk).execute();
Thank you all, have a nice day!
At first declare an Interface in your project somewhere having the required functions, then implement that interface in the (AsyncTask)calling class ,then declare one Interface object in the AsyncTask. Create the constructor of AsyncTask as follows:
public FetchUserDataAsyncTask(User user,InterfaceClass object){
this.user = user;
this.interfaceObject=object;
}
And then do the following in onPostExecute:
#Override
protected void onPostExecute(User user) {
super.onPostExecute(user);
interfaceObject.function(user); //call the function of the calling class
}
You can create an interface, pass it toAsyncTask (in constructor), and then call method in onPostExecute()
For example:
Your interface:
public interface OnTaskCompleted{
void onTaskCompleted();
}
Your Activity:
public class YourActivity implements OnTaskCompleted{
// your Activity
}
And your AsyncTask:
public class YourTask extends AsyncTask<Object,Object,Object>{
//change Object to required type
private OnTaskCompleted listener;
public YourTask(OnTaskCompleted
listener){
this.listener=listener;
} // required methods
protected void onPostExecute(Object
o){
// your stuff
listener.onTaskCompleted();
}
}
Here you go, this is in general how it would work. This is based on this answer and modified to be specific to your existing code. Basically assign your member variable based on what the user entered, and compare that value to the one you get from the server:
public class MyClass extends Activity {
//member variable for the username the user enters:
User userEnteredUser;
public class FetchUserDataAsyncTask extends AsyncTask<Void, Void, User> {
RequestHandler rh = new RequestHandler(); //this is the class i use to do de server conection
User user;
User ret_user;
public FetchUserDataAsyncTask(User user){
this.user = user;
}
#Override
protected void onPostExecute(User user) {
super.onPostExecute(user);
//I WANT THIS USER IN MY MAIN THREAD, TO WORK WITH ITS ATTRIBUTES
processValue(user); //added
}
#Override
protected User doInBackground(Void... params) {
try {
HashMap<String, String> dataToSend = new HashMap<>();
dataToSend.put("username", user.username);
dataToSend.put("password", user.password);
ret_user = rh.sendGetRequest("myadresstophp.php", dataToSend);
} catch (Exception e) {
e.printStackTrace();
}
return ret_user;
}
}
private void getValue()
{
EditText et = (EditText) findViewById(R.id.username);
userEnteredUser.username = et.getText().toString(); //something like this.... replace with your syntax
new FetchUserDataAsyncTask(userEnteredUser).execute();
}
private void processValue(User userFromServer)
{
if (userEnteredUser.equals(userFromServer)) {
//Users match! Yay!
}
}
}
onPostExecute runs on the UI thread by default (main thread). Do what ever you need to be do on the main thread in onPostExecute
I suggest you read up more from the link provided below for a better understanding on AsyncTask
http://developer.android.com/reference/android/os/AsyncTask.html
I'm uncertain what you mean by "main thread". If you mean "UI Thread", which is the primary thread used to execute in your app, then Shashank's reply is correct.
However, I suspect from the context of the question that you actually mean that you want the results returned to the code that initiated the AsyncTask. Let's call that the "invoking object" In that case, what I would do is define a callback in your invoking object whose only purpose is to receive the result of this AsyncTank. You could call it onUserDataFetched(User user).
So, to do this using Interfaces, you could define an Interface that contains a single method:
public interface FetchUserDataListener {
public void onUserDataFetched(User user);
}
Then make sure that your InvokingObject implements that interface, and pass your InvokingObject (which implements FetchUserData, and thus can be considered that object type) to your AsyncTask when you instantiate it.
So, you invoking object code would look like this:
public class InvokingObject implements FetchUserData {
public void someMethodToInvokeFetchUserData() {
//....
new FetchUserDataAsyncTask(userk, this).execute();
//....
}
#Override
public void onUserDataFetched(User user) {
//Compare the result to the data in your invoking object
}
}
Then pass that callback to your AsyncTask when you construct it:
And your AsyncTask Code would look like this:
public class FetchUserDataAsyncTask extends AsyncTask<Void, Void, User> {
FetchUserDataListener mFetchUserDataListener;
public FetchUserDataAsyncTask(User user, FetchUserDataListener listner){
this.user = user;
mFetchUserDataListener = listener
}
//...
#Override
protected void onPostExecute(User user) {
super.onPostExecute(user);
listener.onUserDataFetched(user)
}
//...
}
Related
I'm making an AsyncTask extension that communicates with a service using different actions and returns different types of results depending on the action used. Each action has a listener, made of interfaces extending one interface called OnCommunicationFailedListener. The thing is, I want to have only one variable to save the listener, OnCommunicationFailedListener type, and make the user be able to save all "sub-interfaces" in that variable. They can save them just as is, but I cannot call the methods that the "sub-interface" introduces.
class CommunicationTask extends AsyncTask<Void, Void, String> {
private Action action;
private OnCommunicationFailedListener listener;
enum Action {
LOGIN,
LOGOUT,
SEARCH
}
interface OnCommunicationFailedListener {
void onCommunicationFailed();
}
interface OnLoginAchievedListener extends OnCommunicationFailedListener {
void onLoggedIn(String result);
void onLoginError(String error);
}
interface OnLogoutAchievedListener extends OnCommunicationFailedListener {
void onLoggedOut(String result);
void onLogoutError(String error);
}
interface OnSearchAchievedListener extends OnCommunicationFailedListener {
void onSearchAchieved(String[] results);
}
#Override protected String doInBackground(Void... voids){
try {
// Try to communicate with a query, resulting in some result.
return result;
} catch(IOException e) {
e.printStackTrace();
}
return null;
}
#Override protected void onPostExecute(String result){
super.onPostExecute(result);
if(result == null) {
listener.onCommunicationFailed();
return;
}
// ALL OF THESE GIVE ERRORS, SINCE THE METHODS DO NOT EXIST ANYMORE
switch(action){
case LOGIN:
if(<check if result is ok>){
listener.onLoggedIn(result);
} else listener.onLoginError(<some error>);
break;
case LOGOUT:
if(<check if result is ok>){
listener.onLoggedOut(result);
} else listener.onLogoutError(<some error>);
break;
case SEARCH:
String[] results = <process result>;
listener.onSearchAchieved(results);
break;
}
}
void login(String user, String password, OnLoginAchievedListener listener){
this.listener = listener;
action = Action.LOGIN;
//Build the query...
execute();
}
void logout(OnLogoutAchievedListener listener){
this.listener = listener;
action = Action.LOGOUT;
//Build the query...
execute();
}
void search(String query, OnSearchAchievedListener listener){
this.listener = listener;
action = Action.SEARCH;
//Build the query...
execute();
}
}
The idea is that another class calls the methods login(), logout() or search() and gives them a listener of the action's type. When the communication is finalized and the result is acquired, the action's listener methods are called (in my code, this happens in the switch statement).
The thing is, these methods cannot be called since the passed listener has been casted to OnCommunicationFailedListener.
Is there any way to save a subclass in a variable of its superclass type without being casted to it? I don't want to have actual variables for every type of listener.
I would like to send and email on the background of my app.
I followed this example and implemented it
http://javapapers.com/android/android-email-app-with-gmail-smtp-using-javamail/
public class SendMailTask extends AsyncTask {
private ProgressDialog statusDialog;
private Activity sendMailActivity;
public SendMailTask(Activity activity) {
sendMailActivity = activity;
}
protected void onPreExecute() {
statusDialog = new ProgressDialog(sendMailActivity);
statusDialog.setMessage("Getting ready...");
statusDialog.setIndeterminate(false);
statusDialog.setCancelable(false);
statusDialog.show();
}
#Override
protected Object doInBackground(Object... args) {
try {
Log.i("SendMailTask", "About to instantiate GMail...");
publishProgress("Processing input....");
GMail androidEmail = new GMail(args[0].toString(),
args[1].toString(), (List) args[2], args[3].toString(),
args[4].toString());
publishProgress("Preparing mail message....");
androidEmail.createEmailMessage();
publishProgress("Sending email....");
androidEmail.sendEmail();
publishProgress("Email Sent.");
Log.i("SendMailTask", "Mail Sent.");
} catch (Exception e) {
publishProgress(e.getMessage());
Log.e("SendMailTask", e.getMessage(), e);
}
return null;
}
#Override
public void onProgressUpdate(Object... values) {
statusDialog.setMessage(values[0].toString());
}
#Override
public void onPostExecute(Object result) {
statusDialog.dismiss();
}
}
The code is working fine
However, i have a presentation and i need to explain the code.
In the code, SendMailTask extends AsyncTask without any extra parameters not even Void
I m stuck in this point because i searched and no one is using this way.
Can anyone explain it to me?
without the parameters, AsyncTask will assume the default class (which is Object)
public class SendMailTask extends AsyncTask <Object1, Object2, Object3> {
#Override
protected Object doInBackground(Object1... args) {
...
//publishProgress calls "onPublishProgress" method
//e.g. publishProgress("email sent.");
publishProgress(object2);
//last line returns to "onPostExecute" method
//e.g. return null;
return object3;
}
#Override
public void onProgressUpdate(Object2... values) {
...
}
#Override
public void onPostExecute(Object3 result) {
...
}
}
Object1 is the array of parameters you pass in when initializing the asyncTask
new SendMailTask(SendMailActivity.this).execute(fromEmail,
fromPassword, toEmailList, emailSubject, emailBody);
so fromEmail, fromPassword, etc, etc all goes into the array of Object1.
you access them in doInBackground method using arg[ index ].
If you not specify any Generic parameter , You will see it will take Object as a type (Base Class for all Classes)
So in case of using only AsyncTask
You are actually dealing with Object
eg- See the parameter of doInBackground() in the given link
Honestly, the way they've extended AsyncTask isn't terribly smart. It causes a number of annoying warnings in Android Studio, and it would have been just as easy to extend AsyncTask<Object, Object, Object>, it's the same effect, but it removes the warnings.
All of that said, in order to use the class, you can simply call the following:
Object[] args = new Object[]{
arg1,
arg2,
etc
};
new SendMailTask(activity).execute(args);
You just need to check the GMail constructor to see how you should order your args.
I have a list of objects with certain states
private ArrayList<MyObjectMap> MyList;
MyList = new ArrayList<>();
Every object in that list contains a certain value, that can be updated via the internet (say active, inactive). To update each element I use an AsyncTask, so something like this
for(int i=0;i<MyList.size();i++) {
new myAsyncTask(MyList.get(i)).execute();
}
Later, to update the List in my GUI, I use notifyDataSetChanged for the BaseAdapter of my list.
Is this somehow possible? How do I need to change my AsyncTask?
public class myAsyncTask extends AsyncTask<Void, Void, Void> {
private MyObjectMap myObject;
protected void onPreExecute() {
}
public myAsyncTask(MyObjectMap mom) {
myObject = mom;
}
#Override
protected Void doInBackground(Void... voids) {
myObject.updateThisItem();
return null;
}
}
Pass the full arrayList and baseAdapter object to the asyncTask. and update the current element of arrayList and then make notifyDatasetchanged()
public class MyAsyncTask extends AsyncTask<Void, Void, Void>
{
private ArrayList<MyObjectMap> myList;
private BaseAdapter baseAdapter;
private int position;
public MyAsyncTask(ArrayList myList, int position, BaseAdapter baseAdapter) {
this.myList = myList;
this.position = position;
this.baseAdapter = baseAdapter;
}
protected void onPreExecute()
{
}
#Override
protected Void doInBackground(Void... voids)
{
myList.get(position).updateThisItem(); //or
/*
MyObjectMap mop = myList.get(position);
mop.updateThisItem();
myList.remove(position);
myList.add(position, mop);
*/
return null;
}
protected void onPostExecute()
{
baseAdapter.notifyDataSetChanged();
}
}
you can update ui components in asyncTask in both onPreExecute and onPostExcute...
#Prassana has already shown you how to pass objects to AsyncTask by using a constructor, but there is another elegant way to do it, by altering the AsyncTask class type paramers. If I wanted to pass an ArrayList< String> to AsyncTask, and receive an ArrayList< Integer> back, the class layout would look something like this.
// notice the return type and parameter type
public class myAsyncTask extends AsyncTask <ArrayList<String>, Void, ArrayList<Integer> {
...
// Make sure this method receives and returns the correct types.
// the params are specified when you make the call to execute the asynctask and
// are accessed in a usual varargs way (like an array).
#Override
public ArrayList<Integer> doInBackground(ArrayList<String>... params) {
...
// onPostExecute takes the ArrayList returned by doInBackground
#Override
public void onPostExecute(ArrayList<Integer> result) {
// do something with your newly acquired ArrayList<Integer>
Note that this is the main structure, just to give you an idea. I cannot garauntee that this is typo-less code. Good luck!
public class myAsyncTaskextends AsyncTask<Object, Void, Void> {
private MyObjectMap myObject;
protected void onPreExecute() {
}
#Override
protected Void doInBackground(Object... voids) {
myObject = (MyObjectMap)param[0];
myObject.updateThisItem();
return null;
}
}
when we execute asyn task use this code to send object
Asyntask.execute(loginRequestBean);
inside background method you can get object like this
#Override
protected Object doInBackground(Object... params) {
Object responseObject = null;
try {
Object object = params[0];
if (object instanceof LoginRequestBean) {
//login webservice
} else if (object instanceof RegisterBean) {
//registration webservice
}
}
I'm new in Android. It's been a few weeks since I started working in this project. Reading the code already made I see a lot of private async tasks doing basically the same (call an API) So I wonder if there is a better solution, my idea would be create a public async task called ApiCaller which will return a JSONObject and the responsible for parsing the JSON would be the class calling the ApiCaller:
public class ApiCaller extends AsyncTask<String, String, JSONObject> {
private static final String TAG = "ApiCall";
private final String apiVersion = "v1";
private final String baseURL = "http://my.api.com/";
private String URL = null;
/**
* Generates the URL to call the API.
*
* #param params List with the params to call the API.
*/
public ApiCaller(ArrayList<NameValuePair> params){
String apiURL = this.baseURL + this.apiVersion + "/?";
String paramsList = URLEncodedUtils.format(params, "utf-8");
this.URL = apiURL + paramsList;
}
#Override
protected JSONObject doInBackground(String ... params) {
Log.i(TAG, "API:");
Log.i(TAG, this.URL);
JSONManager jParser = new JSONManager();
JSONObject jsonObject = jParser.getJSONFromUrl(this.URL);
return jsonObject;
}
Is there a way to return that JSONObject outside of the class so I can do something like:
JSONObject js = apiCaller.execute();
Or any other solution to avoid creating new asynctasks every time I need to call the API? With my current code I can't get it but I don't know what is missing? maybe returning it in onPostExecute?
Some time ago I've asked a similar question
One AsyncTask for multiple Activities
and the solution I found was answered in another question:
Common class for AsyncTask in Android?
Basically, what you need is an interface.
I've going to explain the basics, although you should check the original answer by #SirDarius.
You could create an interface like this:
interface AsyncTaskCompleteListener<T> {
public void onTaskComplete(T result);
}
And implements that interface in all classes you need to use the AsynTask, then, in your generic Asynstask you need to have a callback AsyncTaskCompleteListener and call it from your onPostExecute
class B implements AsyncTaskCompleteListener<JSONObject> {
public void onTaskComplete(JSONObject result) {
// do whatever you need
}
public void launchTask(String url) {
ApiCaller a = new ApiCaller(context, ArrayList<NameValuePair> params, this);
ApiCaller.execute(url);
}
}
class ApiCaller extends AsyncTask<String, Void, String> {
private AsyncTaskCompleteListener<String> callback;
public ApiCaller(Context context, ArrayList<NameValuePair> params, AsyncTaskCompleteListener<String> cb) {
this.context = context;
this.callback = cb;
}
protected void onPostExecute(String result) {
finalResult = result;
progressDialog.dismiss();
System.out.println("on Post execute called");
callback.onTaskComplete(result);
}
}
because the asynchronous AsyncTask you can not call a method and obtain the return value;
you could use a AsyncTask on your inline code and get on postExecute your JSON object:
new AsyncTask<String, String, JSONObject>(){
#Override
protected Void doInBackground(String... params) {
//...
}
#Override
protected void onPostExecute(JSONObject result) {
// ...
}
}.execute(...);
You should implement a listener that you will pass to the async task. When the asynctask finishes, it will call the listener's method:
First, make a listener in a new java file:
public interface onTaskDoneListener{
void onTaskDone(JSONObject result);
}
Pass it to your AsyncTask:
private onTaskDoneListner donelistner;
public ApiCaller(ArrayList<NameValuePair> params,onTaskDoneListener donelistener){
String apiURL = this.baseURL + this.apiVersion + "/?";
String paramsList = URLEncodedUtils.format(params, "utf-8");
this.URL = apiURL + paramsList;
this.donelistener = donelistener;
}
Then, inside the onPostExecute method of your AsyncTask
this.donelistener.onTaskDone(result)
Usage:
new ApiCaller(params,new onTaskDoneListener() {
#Override
public void onTaskDone(JSONObject result) {
//This will be called when the asynctask finishes
//Do something with the result
});
Step 1 : Define an Interface.
public interface WebServiceListener {
public void onLoginActionComplete (ArrayList<String> arrayList);
}
Step 2: Implement the WebServiceListener in your activity class.
public class LoginActivity extends Activity implements WebServiceListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
/* Calling the AsyncTask here,you could call in Login Button Click... */
WebServiceClient httpclient = new WebServiceClient(this);
httpclient.execute(ssoURLStr);
}
#Override
public void onLoginActionComplete (ArrayList<String> arrayList) {
// TODO Auto-generated method stub
/* Read the response */
String Response = arrayList.get(0);
}
}
Step 3 : Your AsynTask class code here.
public class WebServiceClient extends
AsyncTask<String, Integer, ArrayList<String>> {
WebServiceListener listener = null;
/* Constructor added WebServiceListener here */
public WebServiceClient ( WebServiceListener listener)
{
this.listener = listener;
}
#Override
protected ArrayList<String> doInBackground(String... params) {
// TODO Auto-generated method stub
ArrayList<String> arrayList = null;
" write your http code here and get the response and update the
arrayList <String> here"
return arrayList;
}
#Override
protected void onPostExecute(ArrayList<String> arrayList) {
// Returns the contents of the HTML page
listener.onLoginActionComplete (arrayList);
}
}
I have also asked this question. Maybe this link will help
First off - I'm rather novice at Java so if the question makes no sense do let me know.
Basically I'm making an Android app which communicates with my web service and so I've made a separate class to deal with the communication, which also includes the AsyncTask (I've removed a lot from the code here just for preview):
public class api {
private String caller = null;
Context that = null;
api(Context that) {
this.that = that;
this.caller = that.getClass().getSimpleName();
}
void call(String action) {
/* .... */
}
new back().execute(param1, param2);
}
void callback(String action, String result){
that.callback(action, result);
}
public class back extends AsyncTask<String, Void, String> {
public String response = null;
protected String doInBackground(String... params) {
response = connection.executeRequest(params[1]);
return response;
}
protected void onPostExecute(String result) {
callback("a", "b");
}
}
}
And when I use the class from some part of the app (let's say SomeClass.class), I do:
api WS = new api(this);
WS.call("....");
And it's supposed to execute the function 'callback' which is in SomeClass.
But the key problem here is this line:
that.callback(action, result);
Eclipse makes me add the name of the "caller" class in the cast:
(SomeClass) that.callback(action, result);
But that doesn't work for me, because I use the 'api' class from many different classes, so ideally I need to put a variable in the cast. I do get the name of the "caller" class here:
this.caller = that.getClass().getSimpleName();
//obviously this won't work:
(this.caller) that.callback(action, result);
Is there anyway to do that, or am I doing something fundamentally wrong?
Thank you.
Currently your api class accepts a Context object in its default constructor. It would make more sense to extend Context with a new class which contains a callback method which you can then override in subclasses such as SomeClass, that would negate the need for casting in your api class. e.g:
public class APIContext extends Context
{
public void callback( String action, String result )
{
/* ... */
}
}
public class SomeClass extends APIContext
{
#Override
public void callback( String action, String result )
{
/* ... */
}
}
public class api
{
private APIContext callerContext = null;
public api( APIContext context )
{
this.callerContext = context;
}
public void callback( String action, String result )
{
callerContext.callback( action, result );
}
}