Android getting a result from an asynctask from within and asynctask - java

I have two AsyncTasks running and the async task that is waiting for the result is just not getting the correct result.
I have a network class that runs like so:
public ArrayList<User> searchForFriends(String activeHash, TelephoneNumber telephone)
{
Object[] obj = {activeHash, telephone};
try
{
return new SearchForFriendsTelephone().execute(obj).get(Constants.TIMEOUT_TIME, Constants.TIMEOUT_UNIT);
}
catch (InterruptedException e)
{
return null;
}
catch (ExecutionException e)
{
return null;
}
catch (TimeoutException e)
{
return null;
}
}
private class SearchForFriendsTelephone extends AsyncTask<Object, Void, ArrayList<User>>
{
#Override
protected ArrayList<User> doInBackground(Object... searchTelephone)
{
if (config.getNetworkVersion() == config.NETWORK_PROTOCOL_VERSION_1)
{
TelephoneNumber tel = (TelephoneNumber) searchTelephone[1];
List<NameValuePair> params = new ArrayList<NameValuePair>(3);
params.add(new BasicNameValuePair(NetworkConfig.POST_ACTIVE_HASH, (String) searchTelephone[0]));
params.add(new BasicNameValuePair(NetworkConfig.POST_MOBILE_NUMBER_COUNTRY_CODE, tel.getCountryCode()));
params.add(new BasicNameValuePair(NetworkConfig.POST_MOBILE_NUMBER_RAW, tel.getNumberRaw()));
ServerCommunication csc = new ServerCommunication();
JSONObject jsonFoundFriends = csc.postToServer(config.getBaseUrl() + URL_FRIEND_SEARCH_MOBILE, params);
if (jsonFoundFriends == null || csc.networkError())
{
FriendNetworkCommunication.this.networkError = csc.getNetworkError();
return null;
}
return _processSearchFriends(jsonFoundFriends);
}
FriendNetworkCommunication.this.networkError = new NetworkError(NetworkLanguage.UNABLE_TO_PROCESS);
return null;
}
Anyway this works fine with no issues and pulls back the user/s. I know this as I tried the following code in the main ui thread and it populates a view just fine. When I call this code from another AsyncTask. I get a timeout error.
Code to all the searchForFriends code:
private class CompareNumbers extends AsyncTask<ArrayList<NameAndNumber>, Integer, Void>
{
#Override
protected Void doInBackground(ArrayList<NameAndNumber>... params)
{
for (NameAndNumber nameNumber : params[0])
{
try
{
FriendNetworkCommunication fnc = new FriendNetworkCommunication();
ArrayList<User> users = fnc.searchForFriends(CurrentUser.getInstance().getUserActiveHash(), new TelephoneNumber(String.valueOf(nameNumber.getNumber().getNationalNumber()), String.valueOf(nameNumber.getNumber().getCountryCode())));
if (users != null && users.size() == 1)
{
User u = users.get(0);
String[] s = nameNumber.getName().split(" ");
u.setFirstName(s[0]);
u.setLastName(s[1]);
((ArrayAdapter<User>) ((ListView) getView().findViewById(R.id.friend_add_fragment_search_cont_list)).getAdapter()).add(u);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
((ArrayAdapter<User>) ((ListView)getView().findViewById(R.id.friend_add_fragment_search_cont_list)).getAdapter()).notifyDataSetChanged();
return null;
}
}
Can I not run an asynctask that waits on another?
NOTE: This is all running in a fragment if this makes any difference?
NOTE2: The first Asynctask runs a network call and has to be run asynchronously and so I wanted it to be like this so if I wanted I could run it anywhere synchronously

try giving the .execute() of the second async task in the onpostexecute() of the first async task.

I have found the answer to my question and this is not possible.
A full answer can be found here:
Creating another AsyncTask inside of doInBackground

Related

Retrofit Task (Execute) Called from another function doesn't wait until Task finish

From my Login Activity (First Activity Opened) I always do a check if the token is still active on my server which is done through Async Task that does API call to server.
here's the code from LoginActivity :
private void checkIfAuthenticated(){
SharedPreferences reader_auth = getSharedPreferences(getString(R.string.auth_preferences), MODE_PRIVATE);
String auth_key = reader_auth.getString(getString(R.string.auth_access_key),null);
String mobile_token = reader_auth.getString(getString(R.string.auth_mobile_token),null);
if (auth_key != null) {
//THIS PART RUNS THE TOKEN CHECK TO SERVER
authGlobal = new AuthenticationGlobal(this);
// I WANT THIS FUNCTION TO FINISH FIRST BEFORE IT GOES TO THE NEXT PART OF THE CODE
authGlobal.runAuthenticationCheck(auth_key,mobile_token);
String Auth_Key = reader_auth.getString(getString(R.string.auth_access_key),null);
Log.d("Auth Key Check 0",Auth_Key);
if (Auth_Key != null) {
Log.d("Auth Key Check 1",Auth_Key);
MoveToDashboardActivity();
}
}
}
The runAuthenticationCheck(String,String) Code is located on another class (Because it was meant to be a global function which can be called from any function on any activity)
runAuthenticationCheck is located in AuthenticationGlobal Class, here's the code :
public void runAuthenticationCheck (String mobile_token, String Access_token) {
checkAuthTask = new checkAuthenticationTask(mobile_token, Access_token);
checkAuthTask.execute((Void) null);
}
public class checkAuthenticationTask extends AsyncTask<Void, Void, Boolean> {
private GetDataService service;
private String mobile_token;
private String access_token;
checkAuthenticationTask( String Access_token,String Mobile_token) {
/*Create handle for the RetrofitInstance interface*/
mobile_token = Mobile_token;
access_token = Access_token;
service = RetrofitClientInstance.getRetrofitInstance().create(GetDataService.class);
}
#Override
protected Boolean doInBackground(Void... params) {
// TODO: attempt authentication against a network service.
try {
Call<CheckAuthenticationResponse> call = service.checkAuthentication(access_token,mobile_token);
Response<CheckAuthenticationResponse> CheckAuthenticationResponse = call.execute();
if (CheckAuthenticationResponse.code() == 200){
} else{
//clear shared preferences
clearAuthentication();
Log.e("AuthKey Global","Expired0");
}
} catch (IOException ea) {
clearAuthentication();
Log.e("AuthKey Global","Expired1");
Log.e("AuthenticationResponseError Global","Network Went Wrong");
ea.printStackTrace();
}
return true;
}
#Override
protected void onPostExecute(final Boolean success) {
//mAuthTask = null;
//showProgress(false);
if (success) {
Log.e("AuthKey Global","Done");
} else {
// mPasswordView.setError(getString(R.string.error_incorrect_password));
clearAuthentication();
Log.e("AuthKey Global","Expired2");
}
}
#Override
protected void onCancelled() {
//mAuthTask = null;
//showProgress(false);
}
There are 2 Class / Activity : "LoginActivity" and "AuthenticationGlobal".
There are 3 Function :
checkIfAuthenticated => located in LoginActivity, Which in turn actually call another function from another class (Function number 2 : "runAuthenticationCheck")
runAuthenticationCheck => located in AuthenticationGlobal. which in calls a AsyncTask via .execute(...) command.
checkAuthenticationTask => located in AuthenticationGlobal. Which actually does the API Call to server.
From "LoginActivity" I run a function "checkIfAuthenticated" => which calls function "runAuthenticationCheck" located at "AuthenticationGlobal" => which runs a Task "checkAuthenticationTask" which does API Call to server and does stuff.
The problem is, when I called the first Function, the code doesn't wait until the function "checkIfAuthenticated" / "checkAuthenticationTask" is done. Is there a way for me to make the app wait until the task / function finish first??
Thank you
UPDATE :
I ONLY NEED TO ADD .get() at the end of .execute() and wrap it inside try catch.
public void runAuthenticationCheck (String mobile_token, String Access_token) {
checkAuthTask = new checkAuthenticationTask(mobile_token, Access_token);
try {
checkAuthTask.execute((Void) null).get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Well. I just need to add a .get() on the execute() and wrap it inside a try catch.
A dumb mistake.
here's the updated code :
public void runAuthenticationCheck (String mobile_token, String Access_token) {
checkAuthTask = new checkAuthenticationTask(mobile_token, Access_token);
try {
checkAuthTask.execute((Void) null).get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

Creating a JSoup class in android using AsyncTask

I know that I have to use ASyncTasks in order to make JSoup work for android, but all examples online illustrate that just by using random jsoup methods in the MainActivity.
I want to create a HTMLParser class which will contains a function for each element I want to parse but I can't seem to make it work.
My HTMLParser:
public class HTMLParser extends AsyncTask<Void, Void, Void> {
private Document doc;
#Override
protected Void doInBackground(Void... voids) {
try {
doc = Jsoup.connect("https://www.bodybuilding.com/exercises").get();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public ArrayList<String> findMuscleGroups(){
ArrayList<String> muscleGroups = new ArrayList<>();
Elements section = doc.select("a");
if (section != null) {
for (Element exercise : section) {
if (exercise.hasText() && !muscleGroups.contains(exercise.text()) &&
exercise.attr("href").contains("exercises/muscle")) {
muscleGroups.add(exercise.text());
}
}
}
return muscleGroups;
}
}
In my MainActivity I want to be able to create a HTMLParser object and be able to use something like ArrayList = htmlParser.findMuscleGroups()
My MainActivity:
HTMLParser parser = new HTMLParser();
new HTMLParser().execute();
for (String muscleGroup : parser.findMuscleGroups()){
textView.setText(muscleGroup + "\n");
}
Which won't work. I'm well aware that it isn't supposed to work and there is something I'm missing but I hope you guys can point me in the right direction.
Solution:
Probably not the best, but it works so there's that
I've added this toHTMLParser class
public Document initializeDoc(){
try {
Document doc = Jsoup.connect("https://www.bodybuilding.com/exercises").get();
return doc;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
In MainActivity I've created
private volatile Document doc = null;
private volatile HTMLParser htmlParser;
variables, and added the following in the onCreate method
htmlParser = new HTMLParser();
Thread t = new Thread(new Runnable() {
#Override
public void run() {
doc = htmlParser.initializeDoc();
}
});
try {
t.start();
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
And needless to say, calling htmlParser.findMuscleGroups(doc) works as expected

Retrieving more than one string with an AsyncTask

I am using AsyncTask in conjunction with StreamScraper to get shoucast metadata for an app I am developing. Right now, I am getting only the song title, but I would also like to get the stream title (which is achieved with stream.getTitle();.) Below is my AsyncTask.
public class HarvesterAsync extends AsyncTask <String, Void, String> {
#Override
protected String doInBackground(String... params) {
String songTitle = null;
Scraper scraper = new ShoutCastScraper();
List<Stream> streams = null;
try {
streams = scraper.scrape(new URI(params[0]));
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (ScrapeException e) {
e.printStackTrace();
}
for (Stream stream: streams) {
songTitle = stream.getCurrentSong();
}
return songTitle;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
MainActivity.songTitle.setText(s);
}
}
What do I need to change so that I can get more than one string?
The simplest way to return more than one value from a background task in this case is to return an array.
#Override
protected String[] doInBackground(String... params) {
String songTitle = null;
String streamTitle = null; // new
Scraper scraper = new ShoutCastScraper();
List<Stream> streams = null;
try {
streams = scraper.scrape(new URI(params[0]));
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (ScrapeException e) {
e.printStackTrace();
}
for (Stream stream: streams) {
songTitle = stream.getCurrentSong();
streamTitle = stream.getTitle(); // new. I don't know what method you call to get the stream title - this is an example.
}
return new String[] {songTitle, streamTitle}; // new
}
#Override
protected void onPostExecute(String[] s) {
super.onPostExecute(s); // this like is unnecessary, BTW
MainActivity.songTitle.setText(s[0]);
MainActivity.streamTitle.setText(s[1]); // new. Or whatever you want to do with the stream title.
}

Android Class with sub-class AsyncTask wait for the postExecute before returning the value

currently I'm doing something for my project wherein I created a separate Class that will only handle the Asynctask and get the value of the webservices I passed and that class should return the JSON response as a String. Now I already achieved it using taskName.execute().get(); wherein it will wait for the task to complete but the problem is it is also waiting for the task to complete before displaying the screen layout. Making my progressDialog useless and cause a delay on switching screens. Here's my code for now:
For the Class with AsyncTask:
public class UtilGetResponse {
Context context;
Map hash_values = new HashMap();
int DialogType;
String response;
/*
PLAN FOR DialogTypes:
* 0 - Standard Please wait dialog
* 1 - Progress dialog
* 2 - Camera upload dialog
* */
InputStream is = null;
StringBuilder string_builder = null;
public UtilGetResponse(Map values, Context baseContext, int type){
/*initialize class and pass the hash values for parameters*/
context = baseContext;
hash_values.putAll(values);
DialogType = type;
}
public String startTask(){
//TODO CASE WHEN BASED ON THE DIALOG TYPE SPECIFIED
Utilities util = new Utilities();
if(util.isOnline(context)){
try {
new UploaderTaskStandard().execute().get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
return response; //THE RESPONSE ONLY SHOW ONCE THE WHOLE TASK IS COMPLETED
}
public class UploaderTaskStandard extends AsyncTask<Map, Void, Void> {
ProgressDialog simpleDialog;
#Override
protected void onPreExecute() {
/*Do something before the async task starts*/
simpleDialog = new ProgressDialog(context);
simpleDialog.setMessage("Please wait");
simpleDialog.show();
}
#Override
protected Void doInBackground(Map... maps) {
uploadData();
return null;
}
protected void onPostExecute(Void v) {
/*Do something after the task is complete*/
simpleDialog.dismiss();
}
}
private void uploadData() {
response = "null";
String url = hash_values.get("url").toString().replace(" ", "%20"); //get the URL replacing the space with %20
//If the user is trying to upload a file use this part
try {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
MultipartEntity mpEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
/*This will convert the hashMap sent into individual part per key per value*/
Set set = hash_values.entrySet();
Iterator iterator = set.iterator();
/*do a loop passing all the data on a string*/
while(iterator.hasNext()) {
Map.Entry mapEntry = (Map.Entry)iterator.next();
String keyword = String.valueOf(mapEntry.getKey());
String value = String.valueOf(mapEntry.getValue());
/*this will check if the passed data is a URL, file or a simple value*/
if(!keyword.equals("url")){
if(value.matches("(.*)/(.*)")){
File file = new File(value);
Log.v("Does this exists?",String.valueOf(file.exists()));
if(file.exists()){
FileBody upload_file;
upload_file = new FileBody(file);
/*not url but file*/
mpEntity.addPart(keyword, upload_file);
}else{
/*not url and not file*/
mpEntity.addPart(keyword, new StringBody(value));
}
}else{
/*not URL and not file*/
mpEntity.addPart(keyword, new StringBody(value));
}
}
}
post.setEntity(mpEntity);
HttpResponse response = client.execute(post);
HttpEntity resEntity = response.getEntity();
is = resEntity.getContent();
} catch (Exception e) {
e.printStackTrace();
response = "null";
}
/*convert JSON to string*/
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(is,"iso-8859-1"),8);
string_builder = new StringBuilder();
String line = "0";
while ((line = reader.readLine()) != null) {
string_builder.append(line + "\n");
}
is.close();
response = string_builder.toString();
}catch(Exception e){
e.printStackTrace();
}
}
}
And to call this:
Map hash_values = new HashMap();
try{
HashMap params = new HashMap<String,String>();
params.put("param1", "YOUR_PARAM");
params.put("url", "YOUR_WEBSERVICE_URL");
//pass parameters
hash_values.putAll(params);
//start async task
UtilGetResponse util = new UtilGetResponse(hash_values, getActivity(), 0);
String result = util.startTask();
Log.v("The result string",result);
}catch (Exception e){
e.printStackTrace();
e.getCause();
Toast.makeText(getActivity(), "Oops problem", Toast.LENGTH_SHORT).show();
}
Is there's a way for me to do this properly without really waiting for the whole task to finish before moving to the next screen? I'm thinking of using a Handler but I'm not really familiar on how to use it anyway.
Your issue is with usage of this
new UploaderTaskStandard().execute().get();
Although you using AsynTask, but still making system wait until result which is against your requirement, what you need is a delivery mechanism, which will notify you back once results are ready. You can take either of two approaches.
change to this, and implement one of below mechanism.
new UploaderTaskStandard().execute();
Implementing handler, and posting result back once result available.
Implementing observer design pattern, where you create an interface with methods such as onResultReady, and passing an object of class implementing above interface to your method startTask, and posting result back from AsyncTask onPostExecute once it is available via interface mechanism.
Going via interface will be very easy and in this way your code will be independent of your network logic, sample code below
// Observer listener interface design
interface ResultListener{
// You can overload this method with data type you want to return
public void onResultReceived();
// Use them in a proper way for sending error message back to your program
public void onTaskCancelled();
public void onError();
}
// This will be your new method signature
public String startTask(ResultListener listener){
// Call it liske this, passing listener reference
new UploaderTaskStandard().execute(listener);
}
// This is your AsyncTask model
public class UploaderTaskStandard extends AsyncTask<ResultListener, Void, Void> {
ResultListener listener;
#Override
protected Void doInBackground(ResultListener... maps) {
this.listener = maps[0];
uploadData();
return null;
}
protected void onPostExecute(Void v) {
/*Do something after the task is complete*/
simpleDialog.dismiss();
// Notify back to calling program
listener.onResultReceived();
}
}

Android Parse JSON stuck on get task

I am trying to parse some JSON data. My code was working for awhile, and I am not sure what I changed to suddenly break the code. When I run my code I am not receiving any runtime errors or warnings. I create a new AsyncTask and execute this. When I call .get() on this new task, the debugger stalls on this line and takes more than 30 minutes. I have not been able to get the debugger or during run to complete this task.
JSON:
protected void setUp(Context context) {
_context = context;
getConfig();
}
// get config file
protected void getConfig() {
if (config != null)
return;
config = new Config();
String url = configURL;
AsyncTask<String, Integer, JSONObject> jsonTask = new DownloadJSONTask()
.execute(url);
JSONObject configItem = null;
try {
configItem = jsonTask.get(); //debugger pauses here
if (configItem == null)
return;
config.configVersion = configItem.getString("field_configversion");
config.currentAppVersion = configItem
.getString("field_currentappversion");
config.getSupportURL = configItem.getString("field_getsupporturl");
config.getCatalogURL = configItem.getString("field_getcatalogurl");
config.getDataVersion = configItem.getString("field_dataversion");
config.getDataUrl = configItem.getString("field_dataurl");
config.getDataApiKey = configItem.getString("field_dataapikey");
} catch (InterruptedException e) {
e.printStackTrace();
System.err.println("Download of config interrupted");
} catch (ExecutionException e) {
e.printStackTrace();
System.err.println("Download of config failed to execute");
} catch (JSONException e) {
e.printStackTrace();
}
cacheStaticData(_context);
}
DownloadJSONTask.java
package com.example.simplegraph;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.os.AsyncTask;
public class DownloadJSONTask extends AsyncTask<String, Integer, JSONObject> {
private HttpClient client = new DefaultHttpClient();
private HttpGet request;
private HttpResponse response;
DownloadJSONTask() {
super();
}
// tries to grab the data for a JSONObject
#Override
protected JSONObject doInBackground(String... urls) {
request = new HttpGet(urls[0]);
try {
response = client.execute(request);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
String result = convertStreamToString(instream);
JSONObject json = new JSONObject(result);
instream.close();
return json;
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
// converts the InputStream to a string and add nl
private String convertStreamToString(InputStream is) {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
is.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
return sb.toString();
}
}
And HomeActivity.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
new AddStringTask().execute();
}
class AddStringTask extends AsyncTask<Void, String, Void> {
#Override
protected Void doInBackground(Void... unused) {
app = (EconApplication) getApplication();
getApp().setUp(HomeActivity.this);
HomeActivity.this.setUpDrawer();
return (null);
}
#Override
protected void onPostExecute(Void unused) {
setUpDataDisplay();
setUpGraphRange();
createTable();
createGraph(-1);
}
}
QUESTION: Why is my code getting stuck on .get()?
AsyncTask.get() blocks the caller thread. Use AsyncTask.execute() instead.
public final Result get ()
Added in API level 3
Waits if necessary for the computation to complete, and then retrieves
its result.
Returns The computed result.
Drawing from
How do I return a boolean from AsyncTask?
Try the below
new DownloadJSONTask(ActivityName.this).execute(url);
In your DownloadJSONTask
In the construcotr
TheInterface listener;
public DownloadJSONTask(Context context)
{
listener = (TheInterface) context;
}
Interface
public interface TheInterface {
public void theMethod(ArrayList<String> result); // your result type
}
In your doInbackground return the result. I am assuming its ArrayList of type String. Change the arraylist to what suits your requirement.
In your onPostExecute
if (listener != null)
{
listener.theMethod(result); // result is the ArrayList<String>
// result returned in doInbackground
// result of doInbackground computation is a parameter to onPostExecute
}
In your activity class implement the interface
public class ActivityName implements DownloadJSONTask.TheInterface
Then
#Override
public void theMethod(ArrayList<String> result) { // change the type of result according yo your requirement
// use the arraylist here
}
Edit: Alternative
You can makes your asynctask an inner class of your activity class. The result on doInbackground computation is a parameter to onPostExecute. Return result in doInbackground. Update ui in onPostExecute.
You can greatly simplify everything using the droidQuery library:
$.getJSON("http://www.example.com", null, new Function() {//this will run using an AsyncTask, get the JSON, and return either a JSONObject or JSONArray on the UI Thread.
#Overrde
public void invoke($ droidQuery, Object... params) {
if (params[0] instanceof JSONObject) { //it's often ok just to assume a JSONObject, making your first line simply: JSONObject obj = (JSONObject) params[0];
//JSONObject is returned
JSONObject json = (JSONObject) params[0];
//to easily parse this Object, convert it to a map first:
Map<String, ?> map = $.map(json);
//then you can just make a call like this:
if (map.contains("field_currentappversion")) {
config.currentAppVersion = (String) map.get("field_currentappversion");
}
}
else {
//JSONArray is returned
JSONArray json = (JSONArray) params[0];
//if you got an array, you can easily convert it to an Object[] for parsing:
Object[] array = $.makeArray(json);
}
}
});

Categories