public AsyncTask to be called from several classes - java

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

Related

How to fetch data out of AsyncTask class in android?

I want to know how to access the data and bind it to a component in out of the AsyncTask class body?
I have a class like:
class DownloadData extends AsyncTask<String, Void, String> {....}
and it has a method :
#Override
protected String doInBackground(String... params) {
return ....;//return some data
}
I don't understand doInBackground return data to where?
Because when i want to use my class, i use it like:
DownloadData dd = new DownloadData();
dd.execute(...);
can i use it like this? because i want to fetch returned data out of my main class to bind it to some components
DownloadData dd = new DownloadData();
string temp=dd.doInBackground(...);
After doInBackground() your return will be forwarded to onPostExecute().
To use it in your activity refer this link : How to use Async result in UIThread
I can not catch
#Override
protected String doInBackground(String... params) {
return ....;//return some data
}
result from main UI.
You have to use callbacks. For example, you can use interface to obtain the result.
For example create an interface:
public interface IProgress {
public void onResult(int result);
}
create class:
private class DownloadData extends AsyncTask<String, Void, String> {
private IProgress cb;
DownloadData(IProgress progress) {
this.cb = cb;
}
#Override
protected String doInBackground(String... params) {
for (int i = 0; i < 10; i ++) {
if (cb!=nil)
cb.onResult(i);//calls 10 times
}
....
}
...
}
somewhere in code:
DownloadData dd = new DownloadData( new IProgress() {
public void onResult(int result) {
/// this is your callback
//to update mainUI thread use this:
final res = result;
runOnUiThread(new Runnable() {
#Override
public void run() {
//update UI here
textview.setText("" + res);
}
});
}
});
dd.execute(...);
And, as usual, you can update UI after doInBackground via onPostExecute()
If you just want to return a result from your AsyncTask class so that you can update the UI in your activity according to the result you can do something like this:
In your AsyncTask class declare an interface like this:
private AsyncResponse asyncResponse = null;
public DownloadData(AsyncResponse as) {
this.asyncResponse = as;
}
public interface AsyncResponse {
void onAsyncResponse(String result); // might be any argument length of any type
}
and in onPostExecute() :
asyncResponse.onAsyncResponse(result); // result calculated from doInBackground()
and in the activity class:
DownloadData dd = new DownloadData(new AsyncResponse() {...}); // implement onAsyncResponse here
dd.execute();

assign external variable to the result of a callback inside AsynckTask

private class exampleTask extends AsyncTask<String, Void, SomeResult>{
#Override
protected SomeResult doInBackground(String... urls) {
SomeResult res ;
someMethod(new CallBack<T>(){
#Override
public void onResponse(SomeResult something) {
res = something ;
}
#Override
public void onFailure() {
//
}
});
return res ;
}
#Override
protected void onPostExecute() {
//
}
}
Please I want to assign "res" to "something" witch is inside the callback in the onResponse method. In this code it's impossible to assign res inside the onResponse method.
Please any help is welcome.
Thank you :)
my original code : I'd like to assign "url" ;
private class GetBeaconInfosTask extends AsyncTask<String, Void, Call<Url>> {
Url url ;
#Override
protected Call<Url> doInBackground(String... urls) {
ProxService service = ProxService.Factory.makeProxService(ProxService.ENDPOINT);
return service.getUrlDetails(urls[0]);
}
// onPostExecute return the results of the AsyncTask.
#Override
protected void onPostExecute(Call<Url> call) {
call.enqueue(new Callback<Url>() {
#Override
public void onResponse(Call<Url> call, Response<Url> response) {
url = response.body();
}
#Override
public void onFailure(Call<Url> call, Throwable t) {
//
}
});
if(url == null){
Log.i("url is null", "url is null !!!!! ....");
}
else {
setShopLogo(url.icon) ;
setShopName(url.title);
setDescription(url.description);
setlongUrl(url.longUrl); }
}
}
Assuming the problem is due to the variable having to be declared as final to be accessible from the callback, you could move it out of the doInBackground method and declare it as a member of the exampleTask class.
private class exampleTask extends AsyncTask<String, Void, SomeResult>{
SomeResult res;
#Override
protected SomeResult doInBackground(String... urls) {
someMethod(new CallBack<T>(){
#Override
public void onResponse(SomeResult something) {
res = something ;
}
#Override
public void onFailure() {
//
}
});
return res ;
}
#Override
protected void onPostExecute() {
//
}
}
While this should answer your question, it's hard to tell what you're trying to achieve. Further to #Gabe Sechan's answer - your variable may never get assigned, or it would be assigned after a certain length of time. Ordinarily you would carry out work in the doInBackground and when that has been carried out onPostExecute is called, but in your case you'll likely have onPostExecute called before hitting the onRespons of your callback. I don't think it's good practice to use a Callback in doInBackground the way you're trying to use it.
If you have other work that needs to be carried out asynchronously in doInBackground, do that, but move the someMethod call to onPostExecute and do whatever you need to do with res in there.
private class exampleTask extends AsyncTask<String, Void, SomeResult>{
SomeResult res;
#Override
protected SomeResult doInBackground(String... urls) {
// background work
}
#Override
protected void onPostExecute() {
someMethod(new CallBack<T>(){
#Override
public void onResponse(SomeResult something) {
res = something ;
// DO STUFF WITH RES HERE AFTER IT'S BEEN ASSIGNED OR YOU WON'T HAVE ACCESS TO IT
}
#Override
public void onFailure() {
//
}
});
}
}
EDIT: Now that the question contains real code, I can provide a flow that should work for you. Note in the code I pasted above the comment in onResponse stating this is where you should have the code that uses the variable. Look at onResponse below for example using your code. The value doesn't exist until you get to the onResponse callback method, so you have to wait until it gets there. Your code below is being carried out before onResponse so the variable is inevitably null. The code isn't executed sequentially. I'd suggest studying callbacks to fully understand them :)
private class GetBeaconInfosTask extends AsyncTask<String, Void, Call<Url>> {
Url url ;
#Override
protected Call<Url> doInBackground(String... urls) {
ProxService service = ProxService.Factory.makeProxService(ProxService.ENDPOINT);
return service.getUrlDetails(urls[0]);
}
// onPostExecute return the results of the AsyncTask.
#Override
protected void onPostExecute(Call<Url> call) {
call.enqueue(new Callback<Url>() {
#Override
public void onResponse(Call<Url> call, Response<Url> response) {
url = response.body();
setShopLogo(url.icon) ;
setShopName(url.title);
setDescription(url.description);
setlongUrl(url.longUrl); }
}
#Override
public void onFailure(Call<Url> call, Throwable t) {
//
}
});
}
You seem to not understand the purpose of a callback. A callback is called at some point in the future. Not now. So the function that sets up the callback won't be assured its called by the end of its execution. What you want will never work. Instead, you should execute whatever you wanted to do in onPostExecute with that value in the body of the callback.

Can't return value from method containing class which extends AsyncTask

I am trying to return a boolean from my method checkInvited(). This method contains a class which extends AsyncTask<Void,Void,String>. This is the full method
public boolean checkInvited(String player_id){
final String g_id = game_id;
final String fr_id = player_id;
class CheckInvited extends AsyncTask<Void, Void, String>{
boolean invited;
ProgressDialog loading;
#Override
protected void onPreExecute(){
super.onPreExecute();
loading = ProgressDialog.show(InviteFriends.this,"Checking Invite Status","Please Wait...",false,false);
}
#Override
protected void onPostExecute(String s){
super.onPostExecute(s);
loading.dismiss();
JSON_STRING = s;
if (s.trim().equals("0")){
invited = false;
} else {
invited = true;
}
}
#Override
protected String doInBackground(Void... params){
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put(Config.KEY_INVITES_GAME_ID, g_id);
hashMap.put(Config.KEY_INVITES_PLAYER_ID, fr_id);
RequestHandler rh = new RequestHandler();
String s = rh.sendPostRequest(Config.URL_CHECK_INVITED, hashMap);
return s;
}
}
CheckInvited ci = new CheckInvited();
ci.execute();
return ci.invited;
}
This method calls a predefined method of sendPostRequest() which contacts the mySql database through php. My problem is getting the checkInvited() method to return true or false. Currently it will only return false when I know at least one of the results should be true.
Thanks in advance for any help.
It only returns false because async task runs in a seperate thread and might take long to execute depending on carious factors. You are returning value even before async task completes.
I would suggest calling a method which requires the true or false from onPostexecute, as onPostExecute runs after doInBackground completes.

Pass an object to AsyncTask

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
}
}

Java (Android): calling a function from Context without cast

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 );
}
}

Categories

Resources