AsyncTask Android - Design Pattern and Return Values - android

I'm writing an application that validates login credentials on an external webserver - so I have the basic issue of creating a login screen that when submitted will send an HTTP request to a server in the background and not cause the UI to hang - whilst providing a ProgressDialog to the user.
My problem lies in, I want to write a generic HTTP Request class that extends AsyncTask, so when I call .execute() I will then pass String parameters which may contain something like 'post', and when doInBackground is called this will see the 'post' string and then forward those parameters onto the respective call in my class. Pseudo code would be something like
public class HTTPOperations extends AsyncTask<String, Void, String>
{
doInBackground(String... string1,additionalParams)
{
if string1.equals "post"
response = httpPost(additionalParams)
return response;
}
httpPost(params)
{
// do http post request
}
}
This is all I could think of, other than creating a class for every HTTP Post/GET etc request I wish to make and extending ASyncTask...
Which leads me to my next problem, if the HTTP POST is successful and it returns an authentication token, how do I access this token?
Because new httpOperations.execute(), does not return the string from doInBackground, but a value of type
Sorry if this doesn't make sense, I can't figure this out at all. Please ask for elaboration if you need it. AsyncTask design patterns and ideas are hugely welcomed.

If you are designing a reusable task for something like this, you need to identify a reusable return type. Its a design decision on your part. Ask yourself, "Are my HTTP operations similar in both the mechanisms with which they are called and in which their data is processed?" If so, you can design a single class to do both. If not, you probably need different classes for your different remote operations.
In my personal use, I have an object i attach key value pairs to and the common return type is the HttpEntity. This is the return type for both HTTP Get and Post, and this seems to work ok in my scenarios because i throw exceptions in exceptional HTTP result situations, like 404. Another nice aspect of this setup is that the code to attach parameters to a get or post are fairly similar, so this logic is pretty easy to construct.
An example would be something like this (psuedo):
public interface DownloadCallback {
void onSuccess(String downloadedString);
void onFailure(Exception exception);
}
Then in your code, where you go to do the download:
DownloadCallback dc = new DownloadCallback(){
public void onSuccess(String downloadedString){
Log.d("TEST", "Downloaded the string: "+ downloadedString);
}
public void onFailure(Exception e){
Log.d("TEST", "Download had a serious failure: "+ e.getMessage());
}
}
DownloadAsyncTask dlTask = new DownloadAsyncTask(dc);
Then inside the constructor of DownloadAsyncTask, store the DownloadCallback and, when the download is complete or fails, call the method on the download callback that corresponds to the event. So...
public class DownloadAsyncTask extends AsyncTask <X, Y, Z>(){
DownloadCallback dc = null;
DownloadAsyncTask(DownloadCallback dc){
this.dc = dc;
}
... other stuff ...
protected void onPostExecute(String string){
dc.onSuccess(string);
}
}
I'm going to reiterate that I think for the good of yourself, you should pass back HttpEntities. String may seem like a good idea now, but it really leads to trouble later when you want to do more sophisticated logic behind your http calls. Of course, thats up to you. Hopefully this helps.

suppose the data format with web api is json, my design pattern :
common classes
1.MyAsyncTask : extends AsyncTask
2.BackgroundBase : parameters to server
3.API_Base : parameters from server
4.MyTaskCompleted : callback interface
public class MyAsyncTask<BackgroundClass extends BackgroundBase,APIClass extends API_Base> extends AsyncTask<BackgroundClass, Void, APIClass> {
private ProgressDialog pd ;
private MyTaskCompleted listener;
private Context cxt;
private Class<APIClass> resultType;
private String url;
private int requestCode;
public MyAsyncTask(MyTaskCompleted listener, Class<APIClass> resultType, int requestCode, String url){
this.listener = listener;
this.cxt = (Context)listener;
this.requestCode = requestCode;
this.resultType = resultType;
this.url = url;
}
public MyAsyncTask(MyTaskCompleted listener, Class<APIClass> resultType, int requestCode, String url, ProgressDialog pd){
this(listener, resultType, requestCode, url);
this.pd = pd;
this.pd.show();
}
#Override
protected APIClass doInBackground(BackgroundClass... params) {
APIClass result = null;
try {
//do something with url and params, and get data from WebServer api
BackgroundClass oParams = params[0];
String sUrl = url + "?d=" + URLEncoder.encode(oParams.getJSON(), "UTF-8");
String source = "{\"RtnCode\":1, \"ResultA\":\"result aaa\", \"ResultB\":\"result bbb\"}";
//to see progressdialog
Thread.sleep(2000);
result = new com.google.gson.Gson().fromJson(source, resultType);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
#Override
protected void onPostExecute(APIClass result) {
super.onPostExecute(result);
try {
if(pd != null && pd.isShowing())
pd.dismiss();
API_Base oApi_Base = (API_Base)result;
listener.onMyTaskCompleted(result , this.requestCode);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class API_Base {
public int RtnCode;
public String getJSON(Context context) throws Exception
{
return new com.google.gson.Gson().toJson(this);
}
public String toString(){
StringBuilder sb = new StringBuilder();
for (Field field : this.getClass().getFields()) {
try {
field.setAccessible(true);
Object value = field.get(this);
if (value != null) {
sb.append(String.format("%s = %s\n", field.getName(), value));
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
return sb.toString();
}
}
public class BackgroundBase {
public String getJSON() throws Exception
{
return new com.google.gson.Gson().toJson(this);
}
}
public interface MyTaskCompleted {
void onMyTaskCompleted(API_Base oApi_Base, int requestCode) ;
}
example, let's call two api in one activity
assume :
API 1.http://www.google.com/action/a
input params : ActionA
output params : RtnCode, ResultA
API 2.http://www.google.com/action/b
input params : ActionB
output params : RtnCode, ResultB
classes with example :
1.MyActivity : extends Activity and implements MyTaskCompleted
2.MyConfig : utility class, i set requestCode here
3.BackgroundActionA, BackgroundActionB : model classes for api's input params
4.API_ActionA, API_ActionB : model classes for api's output params
public class MyActivity extends Activity implements MyTaskCompleted {
ProgressDialog pd;
Button btnActionA, btnActionB;
TextView txtResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
btnActionA = (Button)findViewById(R.id.btn_actionA);
btnActionB = (Button)findViewById(R.id.btn_actionB);
txtResult = (TextView)findViewById(R.id.txt_result);
btnActionA.setOnClickListener(listener_ActionA);
btnActionB.setOnClickListener(listener_ActionB);
pd = new ProgressDialog(MyActivity.this);
pd.setTitle("Title");
pd.setMessage("Loading");
}
Button.OnClickListener listener_ActionA = new Button.OnClickListener(){
#Override
public void onClick(View v) {
//without ProgressDialog
BackgroundActionA oBackgroundActionA = new BackgroundActionA("AAA");
new MyAsyncTask<BackgroundActionA, API_ActionA>(MyActivity.this,
API_ActionA.class,
MyConfig.RequestCode_actionA,
"http://www.google.com/action/a").execute(oBackgroundActionA);
}
};
Button.OnClickListener listener_ActionB = new Button.OnClickListener(){
#Override
public void onClick(View v) {
//has ProgressDialog
BackgroundActionB oBackgroundActionB = new BackgroundActionB("BBB");
new MyAsyncTask<BackgroundActionB, API_ActionB>(MyActivity.this,
API_ActionB.class,
MyConfig.RequestCode_actionB,
"http://www.google.com/action/b",
MyActivity.this.pd).execute(oBackgroundActionB);
}
};
#Override
public void onMyTaskCompleted(API_Base oApi_Base, int requestCode) {
// TODO Auto-generated method stub
if(requestCode == MyConfig.RequestCode_actionA){
API_ActionA oAPI_ActionA = (API_ActionA)oApi_Base;
txtResult.setText(oAPI_ActionA.toString());
}else if(requestCode == MyConfig.RequestCode_actionB){
API_ActionB oAPI_ActionB = (API_ActionB)oApi_Base;
txtResult.setText(oAPI_ActionB.toString());
}
}
}
public class MyConfig {
public static String LogTag = "henrytest";
public static int RequestCode_actionA = 1001;
public static int RequestCode_actionB = 1002;
}
public class BackgroundActionA extends BackgroundBase {
public String ActionA ;
public BackgroundActionA(String actionA){
this.ActionA = actionA;
}
}
public class BackgroundActionB extends BackgroundBase {
public String ActionB;
public BackgroundActionB(String actionB){
this.ActionB = actionB;
}
}
public class API_ActionA extends API_Base {
public String ResultA;
}
public class API_ActionB extends API_Base {
public String ResultB;
}
Advantage with this design pattern :
1.one Advantage for multi api
2.just add model classes for new api, ex: BackgroundActionA and API_ActionA
3.determine which API by different requestCode in callback function : onMyTaskCompleted

Related

SQL query with listview

I am busy with an application where i am getting data from my azure database with sql and storing it in an array. I created a separate class where i get my data and my main activity connects to this class and then displays it.
Here is my getData class:
public class GetData {
Connection connect;
String ConnectionResult = "";
Boolean isSuccess = false;
public List<Map<String,String>> doInBackground() {
List<Map<String, String>> data = null;
data = new ArrayList<Map<String, String>>();
try {
ConnectionHelper conStr=new ConnectionHelper();
connect =conStr.connectionclass(); // Connect to database
if (connect == null) {
ConnectionResult = "Check Your Internet Access!";
} else {
// Change below query according to your own database.
String query = "select * from cc_rail";
Statement stmt = connect.createStatement();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
Map<String,String> datanum=new HashMap<String,String>();
datanum.put("NAME",rs.getString("RAIL_NAME"));
datanum.put("PRICE",rs.getString("RAIL_UNIT_PRICE"));
datanum.put("RANGE",rs.getString("RAIL_RANGE"));
datanum.put("SUPPLIER",rs.getString("RAIL_SUPPLIER"));
datanum.put("SIZE",rs.getString("RAIL_SIZE"));
data.add(datanum);
}
ConnectionResult = " successful";
isSuccess=true;
connect.close();
}
} catch (Exception ex) {
isSuccess = false;
ConnectionResult = ex.getMessage();
}
return data;
}
}
And in my Fragmentactivity.java I simply just call the class as shown here:
List<Map<String,String>> MyData = null;
GetValence mydata =new GetValence();
MyData= mydata.doInBackground();
String[] fromwhere = { "NAME","PRICE","RANGE","SUPPLIER","SIZE" };
int[] viewswhere = {R.id.Name_txtView , R.id.price_txtView,R.id.Range_txtView,R.id.size_txtView,R.id.supplier_txtView};
ADAhere = new SimpleAdapter(getActivity(), MyData,R.layout.list_valence, fromwhere, viewswhere);
list.setAdapter(ADAhere);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
HashMap<String,Object> obj=(HashMap<String,Object>)ADAhere.getItem(position);
String ID=(String)obj.get("A");
Toast.makeText(getActivity(), ID, Toast.LENGTH_SHORT).show();
}
});
My problem comes when I want to include the onPreExecute and onPostExecute because I am relatively new to android studio and I do not know where to put the following lines of code:
#Override
protected void onPreExecute() {
ProgressDialog progress;
progress = ProgressDialog.show(MainActivity.this, "Synchronising", "Listview Loading! Please Wait...", true);
}
#Override
protected void onPostExecute(String msg) {
progress.dismiss();
}
You need to get the data from your azure database using a background service or AsyncTask. However, you are defining a class GetData which does not extend AsyncTask and hence the whole operation is not asynchronous. And I saw you have implemented doInBackground method which is not applicable here as you are not extending AsyncTask. I would suggest an implementation like the following.
You want to get some data from your azure database and want to show them in your application. In these kind of situations, you need to do this using an AsyncTask to call the server api to get the data and pass the data to the calling activity using an interface. Let us have an interface like the following.
public interface HttpResponseListener {
void httpResponseReceiver(String result);
}
Now from your Activity while you want to get the data through an web service call, i.e. AsyncTask, just the pass the interface from the activity class to the AsyncTask. Remember that your AsyncTask should have an instance variable of that listener as well. So the overall implementation should look like the following.
public abstract class HttpRequestAsyncTask extends AsyncTask<Void, Void, String> {
public HttpResponseListener mHttpResponseListener;
private final Context mContext;
HttpRequestAsyncTask(Context mContext, HttpResponseListener listener) {
this.mContext = mContext;
this.mHttpResponseListener = listener;
}
#Override
protected String doInBackground(Void... params) {
String result = null;
try {
// Your implementation of getting data from your server
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
#Override
protected void onPostExecute(final String result) {
mHttpResponseListener.httpResponseReceiver(result);
}
#Override
protected void onCancelled() {
mHttpResponseListener.httpResponseReceiver(null);
}
}
Now you need to have the httpResponseReceiver function implemented in the calling Activity. So the sample activity should look like.
public class YourActivity extends AppCompatActivity implements HttpResponseListener {
// ... Other code and overriden functions
public void callAsyncTaskForGettingData() {
// Pass the listener here
HttpRequestAsyncTask getDataTask = new HttpRequestGetAsyncTask(
YourActivity.this, this);
getDataTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
#Override
public void httpResponseReceiver(String result) {
// Get the response callback here
// Do your changes in UI elements here.
}
}
To read more about how to use AsyncTask, you might consider having a look at here.

Async task does not let me override onPostExecute (method does not override method from it's superclass)

i'm creating an app that grabs list of playlists on YouTube. It used to be a list of videos, but i've changed the code and now it did not let me override that method.
My understanding is that i should change the "extends AsyncTask" with the new Playlist value instead of Video as it was before, but it still did not work.
it was:
public abstract class GetPlaylistAsyncTask extends AsyncTask<String, Void, Pair<String, List<Video>>> {
and now is:
public abstract class GetPlaylistAsyncTask extends AsyncTask<String, Void, Pair<String, List<Playlist>>> {
This is where is the error:
mPlaylist = new Playlist(mPlaylistId);
initAdapter(mPlaylist);
new GetPlaylistAsyncTask(mYouTubeDataApi, mTitle, mSearchQuery) {
#Override
public void onPostExecute(Pair<String, List<Playlist>> result) {
handleGetPlaylistResult(mPlaylist, result);
}
}.execute(mPlaylist.playlistId, mPlaylist.getNextPageToken());
And this is the AsyncTask:
public abstract class GetPlaylistAsyncTask extends AsyncTask<String, Void, Pair<String, List<Playlist>>> {
private static final String TAG = "GetPlaylistAsyncTask";
private static final Long YOUTUBE_PLAYLIST_MAX_RESULTS = 50L;
private static final String YOUTUBE_VIDEOS_PART = "snippet,contentDetails,statistics"; // video resource properties that the response will include.
private static final String YOUTUBE_VIDEOS_FIELDS = "items(id,snippet(title,description,thumbnails/high),contentDetails/duration,statistics)"; // selector specifying which fields to include in a partial response.
private YouTube mYouTubeDataApi;
private String mTitle;
private String mSearchQuery;
public GetPlaylistAsyncTask(YouTube api, String title, String searchQuery) {
mYouTubeDataApi = api;
mTitle = title;
mSearchQuery = searchQuery;
}
#Override
protected Pair<String, List<Playlist>> doInBackground(String... params) {
SearchListResponse searchResponse;
try {
YouTube.Search.List search = mYouTubeDataApi.search().list("id,snippet");
search.setKey(ApiKey.YOUTUBE_API_KEY);
search.setQ(mTitle + " " + mSearchQuery);
search.setType("video");
search.setFields("items(id/kind,id/videoId,snippet/title,snippet/thumbnails/default/url)");
search.setMaxResults(YOUTUBE_PLAYLIST_MAX_RESULTS);
searchResponse = search.execute();
} catch (IOException e) {
e.printStackTrace();
return null;
}
if (searchResponse == null) {
Log.e(TAG, "Failed to get playlist");
return null;
}
ArrayList videoIds = new ArrayList();
for (SearchResult item : searchResponse.getItems()) {
videoIds.add(item.getId().getVideoId());
}
VideoListResponse videoListResponse = null;
try {
videoListResponse = mYouTubeDataApi.videos()
.list(YOUTUBE_VIDEOS_PART)
.setFields(YOUTUBE_VIDEOS_FIELDS)
.setKey(ApiKey.YOUTUBE_API_KEY)
.setId(TextUtils.join(",", videoIds)).execute();
} catch (IOException e) {
e.printStackTrace();
}
return new Pair(searchResponse.getNextPageToken(), videoListResponse.getItems());
}
}
i don't get what is wrong on my code, i'll appreciate if you can point me on the right direction. Thanks in advance!
I've figured it out. The "onPostExecute" takes the object that doInBackground returns, as this post says:
stackoverflow post
Thanks to all for your answers, especially to #Enzokie
Just change public to protected since onPostExecute is not public by design.
#Override
protected void onPostExecute(Pair<String, List<Playlist>> result) {
handleGetPlaylistResult(mPlaylist, result);
}

AsyncTask return a boolean while retrieving information from a Json

I want to check if a user is registered or not in a database, and if it is get the information of the user.
Normally, when I retrieve the information from the server, I put in the Json a variable saying if the user exists or not. Then in onPostExecute(Void result) i treat the Json, so i don't need the AsyncTask to return any value.
Before I was calling the AsyncTask as follows:
task=new isCollectorRegistered();
task.execute();
But now i'm trying a different approach. I want my asynktask to just return a boolean where i called the AsyncTask.
the AsyncTask looks as follows:
public class isCollectorRegistered extends AsyncTask<Void, Void, Void> {
private static final String TAG_SUCCESS = "success";
int TAG_SUCCESS1;
private static final String TAG_COLLECTOR = "collector";
public String collector;
JSONArray USER = null;
JSONObject jObj = null;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
// Checks on the server if collector is registered
try {
jObj = ServerUtilities.UserRegistered(context, collector);
return null;
} finally {
return null;
}
}
#Override
protected void onPostExecute(Void result) {
try {
String success = jObj.getString(TAG_SUCCESS);
Log.d(TAG_COLLECTOR, "Final Info: " + success);
//This if sees if user correct
if (Objects.equals(success, "1")){
//GOOD! THE COLLECTOR EXISTS!!
}
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG_COLLECTOR, "JSON parsing didn't work");
}
}
}
I have checked several posts, but I still havent found out the way to retrieve the boolean where I call the Asynktask, something like this :
task=new isCollectorRegistered();
task.execute();
boolean UserRegistered = task.result();
What would be the right approach? Any help would be appreciated
To use AsyncTask you must subclass it. AsyncTask uses generics and varargs. The parameters are the following AsyncTask <TypeOfVarArgParams , ProgressValue , ResultValue> .
An AsyncTask is started via the execute() method.
The execute() method calls the doInBackground() and the onPostExecute() method.
TypeOfVarArgParams is passed into the doInBackground() method as input, ProgressValue is used for progress information and ResultValue must be returned from doInBackground() method and is passed to onPostExecute() as a parameter.
In your case you are passing Void to your AsyncTask : isCollectorRegistered extends AsyncTask<Void, Void, Void> so you can't get your result from the thread.
please read this tutorial to a deep understand of the AsyncTask in Android
I think the following is exactly what you were looking for, Alvaro...NOTE: I tweaked your code to make it more sensible, but I tried to stick to as much of your original code as possible...
public class RegisterCollector extends AsyncTask<String, Void, Boolean> {
private static final String TAG_SUCCESS = "success";
private static final String TAG_COLLECTOR = "collector";
int TAG_SUCCESS1;
String[] strArray;
JSONArray USER = null;
JSONObject jObj = null;
public String collector;
private AppCompatActivity mAct; // Just incase you need an Activity Context inside your AsyncTask...
private ProgressDialog progDial;
// Pass data to the AsyncTask class via constructor -> HACK!!
// This is a HACK because you are apparently only suppose to pass data to AsyncTask via the 'execute()' method.
public RegisterCollector (AppCompatActivity mAct, String[] strArray) {
this.mAct = mAct;
this.strArray = strArray;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
// AHAH!! - So we do need that Activity Context after all...*TISK* *TISK* # Google **sigh**.
progDial = ProgressDialog.show(mAct, "Please wait...", "Fetching the strawberries & cream", true, false);
}
#Override
protected Boolean doInBackground(String... params) {
// Checks on the server if collector is registered
try {
jObj = ServerUtilities.UserRegistered(context, collector);
return true; // return whatever Boolean you require here.
} finally {
return false; // return whatever Boolean you require here.
}
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
progDial.dismiss();
try {
String success = jObj.getString(TAG_SUCCESS);
Log.d(TAG_COLLECTOR, "Final Info: " + success);
// This 'if' block checks if the user is correct...
if (Objects.equals(success, "1")){
//GOOD! THE COLLECTOR EXISTS!!
}
// You can then also use the Boolean result here if you need to...
if (result) {
// GOOD! THE COLLECTOR EXISTS!!
} else {
// Oh my --> We need to try again!! :(
}
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG_COLLECTOR, "JSON parsing didn't work");
Toast.makeText(mAct, "JSON parsing FAILED - Please try again.", Toast.LENGTH_LONG).show();
}
}
}
...then if you want to use the generated Boolean data outside the AsyncTask class try the following:.
RegisterCollector regisColctr = new RegisterCollector((AppCompatActivity) this, String[] myStrArry);
AsyncTask<String, Void, Boolean> exeRegisColctr = regisColctr.execute("");
Boolean isColctrRegistered = false;
try {
isColctrRegistered = exeRegisColctr.get(); // This is how you FINALLY 'get' the Boolean data outside the AsyncTask...-> VERY IMPORTANT!!
} catch (InterruptedException in) {
in.printStackTrace();
} catch (ExecutionException ex) {
ex.printStackTrace();
}
if (isColctrRegistered) {
// Do whatever tasks you need to do here based on the positive (i.e. 'true') AsyncTask Bool result...
} else {
// Do whatever tasks you need to do here based on the negative (i.e. 'false') AsyncTask Bool result...
}
There you go - I think this is what you were looking for (originally). I always use this approach whenever I need Async data externally, and it has yet to fail me....

Same AsyncTask for Parallel execution

I have an AsyncTask as public class like below,
public class FetchFromTCWebTask extends AsyncTask<String, Void, String> {
MainActivity mainActivity;
int requestId;
private final static String DEBUG_TAG = "FetchFromTCWebTask";
FetchFromTCWebTask(MainActivity activity, int id) {
mainActivity = activity;
requestId = id;
}
#Override
protected String doInBackground(String[] urls) {
// params comes from the execute() call: params[0] is the url.
try {
return downloadUrl(urls[0]);
} catch (IOException e) {
return "Unable to retrieve web page. URL may be invalid.";
}
}
#Override
protected void onPostExecute(String result) {
mainActivity.loadFinished(result);
}
// Reads an InputStream and converts it to a String.
public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
Reader reader = null;
reader = new InputStreamReader(stream, "UTF-8");
char[] buffer = new char[len];
reader.read(buffer);
return new String(buffer);
}
public interface UIListner {
public void loadFinished(String result);
public void loading(int progress);
}
}
Now i want to call it as
(new FetchFromTCWebTask(actviity,1)).execute(url);
(new FetchFromTCWebTask(actviity,2)).execute(url);
(new FetchFromTCWebTask(actviity,3)).execute(url);
Now My Question is , there any way to do like it in parallel and get back the results separately for 1,2 and 3 ? if yes then how ?
Use a thread pool to achieve this.
(new FetchFromTCWebTask(actviity, 1)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url)
(new FetchFromTCWebTask(actviity, 2)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url)
(new FetchFromTCWebTask(actviity, 3)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url)
ExecuteOnExecutor
Since I figure you're about to ask me how to write this (for the twentieth time), here's a small example. I omitted some parts since they're not relevant. This is how you would send the id back to the activity to distinguish between them. If you needed to do different tasks inside of onPostExecute then just use a switch/case statement.
public class FetchFromTCWebTask extends AsyncTask<String, Void, String>
{
MainActivity mainActivity;
int requestId;
FetchFromTCWebTask(MainActivity activity, int id)
{
mainActivity = activity;
requestId = id;
}
...
#Override
protected void onPostExecute(String result)
{
mainActivity.loadFinished(result, requestId);
}
public interface UIListner
{
public void loadFinished(String result, int id);
public void loading(int progress);
}
}
Use custom thread pool.
Why not use build in thread pool(AsyncTask.THREAD_POOL_EXECUTOR)? Its got quite small limit of tasks it can handle. How can you tell that build in pool aint working? Its simple, AsyncTask wont start :)

Android UI, Networking and async code

I have a serious problem which I can't a solution to.
I need to authenticate a token in order to let the user login into my app, the problem is that even though I'm using the AsyncTask, and probably because of it, I can't authenticate it in time. Other problem that sometimes accurs is that I get the NetworkOnMainThreadException error... I'm really hopeless.
Here's the flow -
Check for existsing token -> Validate -> Move to next activity
And here's my code -
public boolean validateToken(TokenAccess token) {
new IsValid().execute(token);
return isValid;
}
private class IsValid extends AsyncTask<TokenAccess, Void, Boolean> {
#Override
protected Boolean doInBackground(TokenAccess... params) {
TokenAccess token = params[0];
switch (token.getSource().getSource()) {
case 'M':
new UrlDownloader(new UrlDownloader.DownloadListener() {
#Override
public void setRequest(HttpRequest request) {}
#Override
public void onRecive(String content) {
if (content.contains("stats")) {
isValid = true;
} else {
isValid = false;
}
}
#Override
public void onError(Exception e) {}
}, UrlDownloader.RequestType.GET)
.execute("https://api.meetup.com/dashboard?access_token="
+ token.getToken());
}
return isValid;
}
}
That's is the URLDownloader class -
public class UrlDownloader extends AsyncTask<String, Void, HttpResponse> {
public static final String TAG = "net.ytsweb.socigo.assests.UrlDownloader";
public enum RequestType {
GET, POST;
}
private RequestType type;
private DownloadListener listener;
public UrlDownloader(DownloadListener listener, RequestType type) {
this.type = type;
this.listener = listener;
}
#Override
protected HttpResponse doInBackground(String... params) {
HttpClient httpClient = new DefaultHttpClient();
HttpUriRequest request;
HttpResponse response;
if (type == RequestType.GET) {
request = new HttpGet(params[0]);
} else {
request = new HttpPost(params[1]);
}
listener.setRequest(request);
try {
response = httpClient.execute(request);
} catch (Exception e) {
listener.onError(e);
return null;
}
return response;
}
#Override
protected void onPostExecute(HttpResponse response) {
try {
Log.d(TAG, response.getAllHeaders()[0].getValue() + "");
listener.onRecive(EntityUtils.toString(response.getEntity()));
} catch (Exception e) {
listener.onError(e);
}
}
public interface DownloadListener {
public void onRecive(String content);
public void onError(Exception e);
public void setRequest(HttpRequest request);
}
}
You need to use onPostExecute for handling the result of the IsValid AsyncTask. What I don't understand: why two AsyncTasks? One would be enough, do everything in there, and handle the result in the one and only onPostExecute.
Whatever happens in doInBackground is in a separate thread, onPostExecute happens on the UI-thread again. One AsyncTask is enough, but don't fetch a result in your validateToken method. In there, just execute your AsyncTask and whatever you need to do with the result you have to initiate in the onPostExecute.
As a basic example of what I mean:
public boolean validateToken(TokenAccess token) {
new YourAsyncTask().execute(token);
// DON'T rely on a result here
}
public class YourAsyncTask extends AsyncTask<?, ?, ?> {
#Override
protected ? doInBackground(?) {
// do networking in background-task
return result;
}
#Override
protected void onPostExecute(? response) {
// handle result here.. call a method in your main class, a listener with the result, or start an Activity directly
}
}

Categories

Resources