I have an AsyncTask class which parse json data and inserts into an object, when I call it in normal activity classes it shows that data have been parsed but when I execute this on a class which extends Application then it gives zero result. Here is my class
public class AppGlobalData extends Application {
public ArrayList<YoutubeItem> gotItem= new ArrayList<YoutubeItem>();
private YouTubeParser parser;
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
new ParserLoader().execute();
}
public class ParserLoader extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
Log.i("Succeed?", "Yes");
parser = new YouTubeParser(
"http://powergroupbd.com/youtube/getyoutubejson.php");
try {
gotItem = parser.parseInitiator();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
public ArrayList<YoutubeItem> getGotItem() {
return gotItem;
}
public void setGotItem(ArrayList<YoutubeItem> gotItem) {
this.gotItem = gotItem;
}
}
I cant figure out the problem, can anyone help?
please be noted that this class runs and logs my String but doesnt parse data.
I think what might happen is that when new ParserLoader().execute(); it doing the work asynchronously. When your Activity load and call the getGotItem() the Asynctask might not have finished
Related
I'm trying to learn Android and when I was trying to parse HTML by using Jsoup, I get an error and my app stops. I have a button in my layout and when I click it I want the app to update the TextView and write HTML Page's title. Here is the code (necessary parts):
public void onClick(View arg0) {
// TODO Auto-generated method stub
new Title().execute(new String[] {url}); // I have url of an html address as a string above
}
}
class Title extends AsyncTask <String, Void, String> {
String pageTitle;
protected String doInBackground(String... params) {
try {
Document doc = Jsoup.connect(params[0]).get();
pageTitle = doc.title();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return pageTitle;
}
protected void onPostExecute (String... params) {
MainActivity.title.setText(params[0]);
}
}
When I click the button, it says "Unfortunately, App has stopped."
Can anybody tell me what I am doing wrong?
try this in doInBackground() :
{
String pageTitle;
Element ele;
protected String doInBackground(String... params) {
try {
Document doc = Jsoup.connect(params[0]).get();
t =doc.select("title");
pageTitle = t.text();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return pageTitle;
}
I am new to JSON and I was wondering how I would pull some info and put it into a JSON Object and then read some of the values. The json info looks like this,
{
"photos":{
"page":1,
"pages":1802,
"perpage":100,
"total":"180134",
"photo": [
{
"id":"8711964781",
"owner":"21156896#N07",
"secret":"3e24e45977",
"server":"8553",
"farm":9,
"title":"Old Harbor",
"ispublic":1,
"isfriend":0,
"isfamily":0
},
{
"id":"8712680696",
"owner":"21156896#N07",
"secret":"fe82f8387b",
"server":"8122",
"farm":9,
"title":"Rockefeller Plaza",
"ispublic":1,
"isfriend":0,
"isfamily":0
},
....
It photo array goes on for quite a while. How would I get the values of "isPublic"? "Secret" is a String because of the "" and isPublic is an integer or boolean? I basically have to put them into a URL link and download the image.
public class ReadString extends AsyncTask<String, Integer, String>{
#Override
protected String doInBackground(String... FlickrString) {
try {
json = getValue();
return json.getString(FlickrString[0]);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
tvTest.setText(result);
}
This works for all the strings. How would I get the farm, isfriend, isfamily, and ispublic converted to a string? I tried something else now to get the Int values, I made a whole new class for reading the ints. But it isnt getting the correct int value. I have it download the int and I convert it to a string and then I change a textview to the string of the int using String.valueOf(x); What am i doing wrong?
public class ReadInt extends AsyncTask<String, Integer, String>{
#Override
protected String doInBackground(String... FlickrString) {
try {
json = getValue();
int x = json.getInt(FlickrString[0]);
String y = String.valueOf(x);
return y;
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
tvTest.setText(result);
}
}
Thanks!
JSONObject jobj = result.getJSONObject("photo");
jobj.getBoolean("ispublic");
jobj.getInt("isfriend");
The variable result is of typeJsonObject that should contain the entire object have pasted above in your code
Java is not like C++.In C++ 0 is false and other integers are true
I think you should create a function like this
private void boolean convertIntToBool(int value) {
if(value==0) {
return false;
} else {
return true;
}
}
and use it in the JSON parsing like this for example
boolean isfamily = convertIntToBool(jsonPhotoObject.getInt("isfamily"));
I guess you already know about the JSON parsing so I won't give so much example, but if you have another question about my answer feel free to ask in the comment :)
we assume the jsonString is your json result. You can get the your values like this:
protected String doInBackground(String... FlickrString) {
try {
JSONObject result = new JSONBOject(jsonString);
JSONObject photots = (JSONObject)result.get("photos");
JSONArray photosArray = (JSONArray) result.get("photo");
for(int i = 0; i < photosArray.length(); i++) {
JSONObject item = potosArray.get(i);
//ispublic
int ispublic = item.getInt("ispublic");
//isfriend
int isfriend = item.getInt("isfriend");
//isfamily
int isfamily = item.getInt("isfamily");
}
json = getValue();
return json.getString(FlickrString[0]);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
I would recommend that you try either Jackson or Gson and convert the JSON into some POJOs. I find that it's easier and less error prone to work with java objects instead of JSONObject, JSONArray and such. Here's an example of how it would work using Jackson. First we create the Objects that map to the JSON data:
public class Photos {
#JsonProperty
private int page;
#JsonProperty
private int pages;
...
#JsonProperty("photo")
public List<Photo> photoList;
}
public class Photo {
#JsonProperty
private String id;
#JsonProperty
private String owner;
...
#JsonProperty("ispublic")
public boolean isPublic;
#JsonProperty("isfriend")
public boolean isFriend;
#JsonProperty("isfamily")
public boolean isFamily;
}
Once we've created our pojos we can convert the JSON data into objects using the ObjectMapper. AT least when it comes to Jackson it automatically tries to convert integers to boolean (0 = false, anything else = true) and Strings to booleans ("true" and "false").
ObjectMapper mapper = new ObjectMapper();
Photos photos = mapper.readValue(json, Photos.class);
for(Photo photo : photos.photoList) {
if(photo.isPublic) {
// do something
}
}
PS I've made some of the properties of the pojos public to make the example shorter. You may wish to add getters and keep the properties private.
I am using a New Runnable httprequest data loading in one of my classes. I use that class to populate a ListView in one of my Activities, but the thing is that the views are loading before the data has been loaded.. I tried moving my initialize method, which initializes all views, but nothing happened. Every time I load the app, I have to reload the main view because there are no entries in the ListView. LoadReportList() is the method that makes an instance of the class holding the http request method.
public class HomeActivity extends Activity {
private ArrayList<Report> reportList = null;
ListView listview;
private final boolean DEBUG = true;
private MyCustomArrayAdapter adapter = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
}
#Override
protected void onResume()
{
super.onResume();
loadReportList();
initialize();
}
/**
* This method initializes all the components needed for the activity
*/
private void initialize()
{
/* Get a reference of the listview in our xml view */
listview = (ListView) findViewById(R.id.reportsList);
adapter = new MyCustomArrayAdapter(this, R.layout.single_listview_row);
try{
// Populate the list, through the adapter
for(final List_Item entry : getListEntries()) {
adapter.add(entry);
if(DEBUG)Log.i("HomeActivity","in adding List_Item entries to the adapter");
}
}catch(Exception e){
Log.i("In initialize() HomeActivity","Could not load the list with entries");
loadReportList();
}
listview.setAdapter(adapter);
listview.setOnItemClickListener(new OnItemClickListener(){
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long id) {
/* Class to assist us in loading the activity */
Class editClass = null;
try {
editClass = Class.forName(".DetailsActivity");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/* create bundle to pass the ID of the deck that was clicked */
Bundle reportPassed = new Bundle();
//reportPassed.putInt("Report", reportList.get(4).getId());
reportPassed.putSerializable("report", reportList.get(position));
/* Start the new intent and also pass a bundle that will contain the name of the card that was clicked */
Intent ourIntent = new Intent(HomeActivity.this, editClass);
ourIntent.putExtras(reportPassed);//passing the bundle to the activity
//start the activity
startActivity(ourIntent);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.home, menu);
return true;
}
/* Create the list of objects of type List_Item, in our case it will be Decks */
private List<List_Item> getListEntries(){
/* Create an ArrayList of List_Items */
final ArrayList<List_Item> entries = new ArrayList<List_Item>();
if(reportList == null || reportList.isEmpty())
loadReportList();
/* Create the rows for the ListView by adding them into the ArrayList "entries".
* reportList is a global ArrayList<Report> that we populate by a method call to the class JsonParser.
* Look above.
* */
for(int i = 0; i < reportList.size(); i++) {
if(DEBUG)Log.i("getListEntries HomeActivity","Passing through reportlistEntries");
entries.add(
new List_Item(((Report)reportList.get(i)).getType(), Integer.toString(((Report)reportList.get(i)).getId()), ((Report)reportList.get(i)).getId())
);
}
return entries;
}
//This method loads the reportList arraylist with all Report objects
void loadReportList(){
try {
reportList = new JsonParser().getArrayList();
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalStateException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
Here is my HTTP request:
//The constructor simply calls the getHttpResponse()
public JsonParser() throws UnsupportedEncodingException, IllegalStateException, IOException, JSONException
{
getHttpResponse();
}
/*
* This method returns an HttpResponse
*/
public void getHttpResponse(){
Log.i("getHttpResponse", "Right after declaring HttpResponse response");
new Thread(new Runnable() {
public void run() {
runRequest();
}
}).start();
}
void runRequest()
{
HttpResponse response = null;
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet();
try {
request.setURI(new URI("http://....../report_data.json"));
response = client.execute(request);
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(response!= null)
Log.i(response.toString(), "testing response.toString()");
//call to populate the list
try {
populateList(response);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Instead of using a java thread you can take advantage of the AsyncTask class of the Android SDK. You can show a progress dialog onPreExecute method, do all the heavy work(in your case the http stuff) in the doInBackground method and populate your list and dismiss the progress dialog in the onPostExecute method. You can create an inner class e.g Task which extends the AsyncTask method and call it from onCreate or onResume ,whatever suits you, like this.
new Task().execute();
AsyncTask has given the name"Painless threading" because it is there to make our life easier. It is consider good practice to reuse already implemented code which is intended for such tasks.
You can find many threads regarding AsyncTasks use in StackOverflow e.g progressDialog in AsyncTask
So what you need to do is call initialize() after your runRequest code completes.
I agree with the above poster that an AsyncTask will make this easy. Get rid of the threading code in your JsonParser class. AsyncTask will take care of that for you.
Here's a snippet.
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... voids) {
myparser = new JSONParser();
myparser.runRequest()
}
#Override
protected void onPostExecute(Void aVoid) {
initialize();
}
}.execute();
I can't explain why onPostExecute is not being called in my code. I have successfully used almost this exact code with a different app before. It prints 'onPreExecute' and the successful result of the JSON fetch from doInBackground just before return result; but then onPostExecute doesn't print anything - with the super call or not - and moreover doesn't return my string to the UI thread. Any ideas?
public class PrivateLoadFromServer extends AsyncTask<String, Integer, String> {
InputStream is = null;
String result = null;
String error_text="";
JSONObject j = null;
String url;
SQLiteOpenHelper helper;
CustomActivity activity;
private Context context;
private ProgressDialog dialog;
private int count;
String employee;
String text;
public PrivateLoadFromServer(CustomActivity activity,String employee,String url){
this.url=url;
this.employee=employee;
this.activity=activity;
}
#Override
protected void onPreExecute() {
system.out.println("onPreExecute");
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
System.out.println("onPostExecute");
activity.setJSONResult(result);
/*
if(result!=null){
System.out.println("Task reported successful");
taskHandler.taskSuccessful(this.result);
activity.setJSONResult(this.result);
} else {
taskHandler.taskFailed();
}
*/
//return;
}
#Override
protected String doInBackground(String... params) {
System.out.println("Running aSyncTask");
// Successful code to get JSON result string from server omitted.
System.out.println("Raw at doInBackground: " + result);
return result;
EDIT: Should've posted this originally, I call it as an inner class in CustomActivity like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
helper=new DBHelper(this);
loadBasicData();
}
private void loadBasicData() {
// If you can encode all of these into one JSON Object, cool.
String url="*****" //Omitted URL.
String employee=null;
PrivateLoadFromServer syncTask = new PrivateLoadFromServer(this,employee,url);
syncTask.execute();
try {
syncTask.get(15000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("JSONResult at Activity:"+jsonResult); // jsonResult is null
}
}
public void setJSONResult(String result){
System.out.println("setJSONResult"+result);
this.jsonResult=result; // jsonResult is a field in the Activity.
}
Because you are calling get, the JSON result is also returned from this method (see the source code of AsyncTask.java. So you can call your method directly on the output.
try {
setJSONResult(syncTask.get(15000, TimeUnit.MILLISECONDS));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
Check if your are explicitly cancelling AsyncTask somewhere in the code before it could postExecute.
onPostExecute() is called on the main UI thread. If its not getting called, it means your UI thread is blocked doing something else.
This class causing me android.os.NetworkOnMainThreadException,i know that i have to use asyncTask to make it but i can't figure out how because i am using 1 fragments and this make my application very slow especially when i laod bitmaps, can any one help me please.
public class ContainerData {
static public Context context;
public ContainerData() {
}
public static ArrayList<Feed> getFeeds(String feedurl){
SAXParserFactory fabrique = SAXParserFactory.newInstance();
SAXParser parseur = null;
ArrayList<Feed> feeds = null;
try {
parseur = fabrique.newSAXParser();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
URL url = null;
try {
url = new URL(feedurl);
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
DefaultHandler handler = new ParserXMLHandler();
try {
parseur.parse(url.openConnection().getInputStream(), handler);
feeds = ((ParserXMLHandler) handler).getData();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return feeds;
}
}
If you use AsyncTask make sure getFeeds is called inside the doInBackground(...) callback
Regardless of whether you use a fragment or not, you're still trying to perform Network activity on the main thread.
Create a generic class that extends AsyncTask which can perform all your parsing.
public class MyTaskHandler extends AsyncTask<String, Integer, Boolean>
{
#Override
protected void onPreExecute()
{
//Could display progress dialog here
}
#Override
protected Boolean doInBackground(String... params)
{
//Implement your parser here
}
#Override
protected void onPostExecute(Boolean result)
{
//Check result, dismiss dialog etc
}
}
Then create a new instance of MyTaskHandler and run it...
MyTaskHandler myTask = new MyTaskHandler();
myTask.execute("http://www.myxmlsite.com/lists.xml");
The execute method can take (String... params) so you can pass for example a URL,and retrieve it in doInBackground(String... params)
#Override
protected Boolean doInBackground(String... params)
{
//Implement your parser here
String urlToParse = params[0];
}
Best of luck.