Android Parse JSON stuck on get task - java

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

Related

Incompatible types error: Manipulating return value of another class's method

I need to yield a JsonObject in a class MainActivity from a method doInBackground() in a class Post.
I instantiated the class Post, called the method in it which is being passed parameters into, and tried to assign it to a variable of type JSONObject.
This is the class Post:
class Post extends AsyncTask<String, Void, JSONObject> {
#Override
protected JSONObject doInBackground(String... args) {
JSONObject jsonObject = null;
try {
//Connect to the website
Connection.Response response =
Jsoup.connect(args[0])
.method(Connection.Method.POST)
.data("text", args[1])
.data("language", args[2])
.ignoreContentType(true)
.execute();
Document document = response.parse();
jsonObject = new JSONObject(document.text());
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException err) {
Log.d("Error", err.toString());
}
return jsonObject;
}
}
And this is how I tried to retrieve the object in the class MainActivity:
Post post = new Post();
JSONObject object = post.execute(stringurl, text, "en");
The Java error I get is incompatible types. Required is org.json.JSONObject and found is android.os.AsyncTask <java.lang.String, java.lang.Void, org.json.JSONObject>.
I should be able to capture the JSONObject... how?
You can declare a method in MainActivity which can be called from the AsyncTask once it has fetched the JSONObject:
private onObtainJSONObject(JSONObject jsonObject){
if(jsonObject != null){
// do something with the JSONObject
} else{
// something went wrong - maybe show an error message?
}
}
And you need to override onPostExecute() in the AsyncTask:
public void onPostExecute(JSONObject jsonObject){
// Note: this will be executed on the main thread
MainActivity.this.onObtainJSONObject(jsonObject);
}
If the AsyncTask is not an inner class of your Activity, you can use a callback (a simple interface) as follows
public interface PostCallback{
void onSuccess(JSONObject data);
void onError(Exception exception);
}
Then you let the AsyncTask have a field of type PostCallback and a setter setCallback(PostCallback).
In MainActivity:
Post post = new Post();
post.setPostCallback(new PostCallback(){
#Override
onSuccess((JSONObject data){
onObtainJSONObject(data);
}
#Override
onError(Exception exception){
// exception handling ...
}
});
JSONObject object = post.execute(stringurl, text, "en");
In Post:
private PostCallback callback;
private Exception exception;
public setPostCallback(PostCallback callback){
this.callback = callback;
}
#Override
protected JSONObject doInBackground(String... args){
// keep everything as before but when an Exception occurs,
// assign it to *exception* in the catch block
}
#Override
public void onPostExecute(JSONObject jsonObject){
// Note: this will be executed on the main thread
if(exception == null){
callback.onSuccess(jsonObject);
} else {
callback.onError(exception);
}
}

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 getting a result from an asynctask from within and asynctask

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

Android Async tasks reuse

I am developing an app where in a number of the activities I need to retrieve data via Http.
Once I have the data I process it in the onPostExecute() callback method.
This works fine if I define the async task as an inline class, but as I want to do the same processing in a number of activities I have defined it as an external class.
So the question is, using an external class how do I signal an "event" back to the calling class as a means of passing the data back. I know how to do this in C# but I am new to Java and can not see how to achieve this.
While it is true that a Listener technically correct, I would claim that it is either too complicated or not complicated enough.
Here's an easier solution:
class Foo {
class Bar extends AsyncTask<Void, Void, Result> {
public void onPostExecute(Result res) {
doSomething(res);
}
}
public void doSomething(Result res) {
/// process result
}
public void startTask() {
new Bar().execute();
}
}
Is equivalent to:
class Bar extends AsyncTask<Void, Void, Result> {
private final Foo foo;
public Bar(Foo foo) { this.foo = foo; }
public void onPostExecute(Result res) {
foo.doSomething(res);
}
}
class Foo {
public void doSomething(Result res) {
/// process result
}
public void startTask() {
new Bar(this).execute();
}
}
... which is what you asked: when you pull the inner class out, you lose the implicit pointer. Just make it explicit and pass it in.
The bad news is that there are all sorts of memory leak and lifecycle issues that arise from this solution. I would very much recommend that, before your program gets even bigger, you looking into using an IntentService instead of an AsyncTask and use a Handler, or Activity.runOnUiThread to get the results back onto the UI thread.
One approach:
Define a parent abstract class called ParentActivity (extend Activity of course). Have that contain an abstract method called onAsyncCallback();
Have each class that uses the task to extend that class and implement the method.
In your AsyncTask constructor, have it accept in a ParentActivity.
Eg
ParentActivity activity;
public MyTask (ParentActivity myActivity)
{
this.activity = myActivity;
}
When done in onPostExecute(), simply do
activity.onAsyncCallback(data);
This would also work with an interface, it does the same thing, except intead you have the Constructor accept in the Listener instance.
If you want to do it in a clean way try following approach
First create an enum which contains all your async call names
public enum TaskType {
USER_LOGIN(1), GET_PRODUCTS(2), GET_EMPLOYEE(3);
int value;
private TaskType(int value) {
this.value = value;
}
}
Then create an interface
public interface AsyncTaskListener {
public void onTaskCompleted(String result, TaskType taskType);
}
Now implement this interface in the activity which you are going to call the GetAsyncTask
eg:-
public class LoginActivity extends Activity implements AsyncTaskListener {
protected void onCreate(Bundle savedInstanceState) {
String url = ".....";
new GetAsyncTask(LoginActivity.this, LoginActivity.this, TaskType.USER_LOGIN).execute(url);
}
...
public void onTaskCompleted(String result, TaskType taskType) {
if(taskType == TaskType.USER_LOGIN){
//your login result handling here
}
}
Lastly, this is your AsyncTask
public class GetAsyncTask extends AsyncTask<String, Void, String> {
String outputStr;
ProgressDialog dialog;
Context context;
AsyncTaskListener taskListener;
TaskType taskType;
public GetAsyncTask(Context context, AsyncTaskListener taskListener, TaskType taskType){
this.context = context;
this.taskListener = taskListener;
this.taskType = taskType;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = ProgressDialog.show(context, "Loading", "Please wait...", true);
}
#Override
protected String doInBackground(String... params) {
String urlString = params[0];
try {
URL url = new URL(urlString);
HttpURLConnection conn
= (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
if (conn.getResponseCode() != 200) {
throw new IOException(conn.getResponseMessage());
}
// Buffer the result into a string
BufferedReader rd = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = rd.readLine()) != null) {
sb.append(line);
}
rd.close();
conn.disconnect();
String jsonStr = sb.toString();
outputStr = jsonStr;
} catch (SocketTimeoutException e) {
outputStr = "timeout";
}catch(Exception e){
e.printStackTrace();
outputStr = "error";
}
return outputStr;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
taskListener.onTaskCompleted(result, taskType);
dialog.dismiss();
}
}
Use Listener pattern. Take a look here TaskListener, Task that uses this listener and fragment that calls task
Try making your own http requesting class that extends AsyncTask and than put your code in "doInBackground" call. Thyt way you only have to instantiate your class with url and params and read response. That worked for me.
Here is example:
public class HttpRequest extends AsyncTask<String, Void, String> {
public String url;
public List<NameValuePair> nameValuePairs;
public String httpResponse =null;
public HttpRequest(String _url, List<NameValuePair> _nameValuePairs) {
url = _url;
nameValuePairs=_nameValuePairs;
}
#Override
protected String doInBackground(String... params) {
httpResponse = getWebPageWithFormData(url, nameValuePairs);
return "";
}
public static String getWebPageWithFormData( String url, List<NameValuePair> nameValuePairs ){
String html = "";
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
if (nameValuePairs!=null){
try {httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));}
catch (Exception e){}
}
HttpResponse response = null;
try {
response = httpclient.execute(httppost);
}
catch (ClientProtocolException e) { return ""; }
catch (IOException e) { return ""; }
int responseCode = response.getStatusLine().getStatusCode();
switch(responseCode) {
case 200:
HttpEntity entity = response.getEntity();
if(entity != null) {
try{ html = EntityUtils.toString(entity);}
catch (Exception e) {}
}
break;
}
return html;
}
}

How to wrap these classes into a AsyncClass and then using them?

I'm trying to put together a simple RSS reader, and found code on http://www.ibm.com/developerworks/opensource/library/x-android/
Todo so, I noticed that you can not do network operations from the main thread since Honeycomb and have a hard time wrapping this class into a working AsyncTask:
package tlib.net.rss;
import java.util.ArrayList;
import java.util.List;
import android.sax.Element;
import android.sax.EndElementListener;
import android.sax.EndTextElementListener;
import android.sax.RootElement;
import android.util.Xml;
public class SaxFeedParser extends BaseFeedParser {
public SaxFeedParser(String feedUrl) {
super(feedUrl);
}
public List<Message> parse() {
final Message currentMessage = new Message();
RootElement root = new RootElement("rss");
final List<Message> messages = new ArrayList<Message>();
Element channel = root.getChild("channel");
Element item = channel.getChild(ITEM);
item.setEndElementListener(new EndElementListener(){
public void end() {
messages.add(currentMessage.copy());
}
});
item.getChild(TITLE).setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentMessage.setTitle(body);
}
});
item.getChild(LINK).setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentMessage.setLink(body);
}
});
item.getChild(DESCRIPTION).setEndTextElementListener(new
EndTextElementListener(){
public void end(String body) {
currentMessage.setDescription(body);
}
});
item.getChild(PUB_DATE).setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentMessage.setDate(body);
}
});
try {
Xml.parse(this.getInputStream(), Xml.Encoding.UTF_8, root.getContentHandler());
} catch (Exception e) {
throw new RuntimeException(e);
}
return messages;
}
}
this code also calls the base-class: BaseFeedParser which i guess also has to be wrapped into a AsyncTask. the code for BaseFeedParser looks like:
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
public abstract class BaseFeedParser implements FeedParser {
// names of the XML tags
static final String CHANNEL = "channel";
static final String PUB_DATE = "pubDate";
static final String DESCRIPTION = "description";
static final String LINK = "link";
static final String TITLE = "title";
static final String ITEM = "item";
private final URL feedUrl;
protected BaseFeedParser(String feedUrl){
try {
this.feedUrl = new URL(feedUrl);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
protected InputStream getInputStream() {
try {
return feedUrl.openConnection().getInputStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
I don't know if i'm simply dumb or having a bad day, but i don't get how this is supposted to happend. Could someone help me and my afternoon brain out to get this working?
Currently i use:
SaxFeedParser rss = new SaxFeedParser("http://www.androidster.com/android_news.rss");
messages = rss.parse();
for(Message message : messages)
{
tv.appendText(message);
}
to process the stream, how would i do if everything was done with AsyncTask?
Kind regards
Hiam
I have not tried this, but it should work.
Basically the AsyncTask will retrieve the url(s) contents, parse it and publish the parsed messages.The onProgressUpdate() is used to safely update the user interface as you please.
class ParserTask extends AsyncTask<String, List<Message>, Long> {
protected Long doInBackground(String... urls) {
if (urls == null || urls.length == 0)
return null;
for (String url : urls) {
SaxFeedParser rss = new SaxFeedParser(url);
List<Message> messages = rss.parse();
publishProgress(messages);
}
return null; //return somethingForPostExecute;
}
protected void onProgressUpdate(List<Message>... messages) {
if (messages == null || messages.length == 0)
return;
for (Message message : messages[0]) {
// tv.appendText(message);
// or call method from GUI thread (the activity)
}
}
protected void onPostExecute(Long nr) {
}
}
Then you use something like:
new ParserTask().execute("http://www.androidster.com/android_news.rss");
Or you could use multiple urls:
new ParserTask().execute(new String[]{"http://www.androidster.com/android_news.rss", "..."});

Categories