My app is a game that is a simple words puzzle, so the levels on it is fetched from a Json web service, using AsyncTask class I can fetch the data in doInBackground and onPostExecute methods, I use local variables in FetchData class to hold the fetched data in, the data is simply 6 strings that are an image URL and level id, and 4 words that is for the buttons, here is the game interface, as you can see there are 4 buttons each one has a word and the player must find it by looking at the picture.
So when the player finds for example 1 word and leaves the app and closes it, the word the player found must be saved and when he return back to LevelActivity he is supposed to continue the level by finding more 3 words.
THE PROBLEM: is that when I find a word and the word shows (so it must be saved) when I close the app and return this happens, depending on my testing I found out that those lines of code that effects the data lag
NOTE: That whenever I reload the activity (manually) everything gets good and instead of having an empty button after recreating the activity the word shows.
data fetching method used: in onCreate & onResume
//This is in LevelActivity.java:
//These methods checks if the button is answered previously or not (button1/button2... variables are true when a word is answered)
public void checkButton1() {
if (button1) {
wordButton1.setText(button1Word); //<--- Here if I changed it to .setText("Test")
//the lag will disappear and the button will show "Test" (without the quotation) and everything's good
//So the problem is when I use .setText(button1Word); that is the word fetched from Json web service.
//it doesn't throw NullPointerException and it doesn't show the word
//but what? it set the text to " "? Why?
//Note other buttons are the same thing too
}
}
public void checkButton2() {
if (button2) {
wordButton2.setText(button2Word);
}
}
public void checkButton3() {
if (button3) {
wordButton3.setText(button3Word);
}
}
public void checkButton4() {
if (button4) {
wordButton4.setText(button4Word);
}
}
//This is FetchData class that fetches the data from Json web service (full code)
package com.example.wordspuzzlejsontest;
import android.content.Context;
import android.os.AsyncTask;
import com.squareup.picasso.Picasso;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class FetchData extends AsyncTask<Void, Void, Void> {
//Local variable that are used to hold fetched data to transfer them to LevelActivity with static variables
static int currentLevel = 0;
String w1;
String w2;
String w3;
String w4;
String data = "";
String id;
String img;
Context context;
#Override
protected Void doInBackground(Void... voids) {
try {
URL url = new URL("https://api.jsonbin.io/b/5e42776dd18e4016617690ce/7");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = "";
while (line != null) {
line = bufferedReader.readLine();
data = data + line;
}
JSONArray JA = new JSONArray(data);
JSONObject JO = (JSONObject) JA.get(currentLevel);
id = (String) JO.get("id");
img = (String) JO.get("img");
w1 = (String) JO.get("w1");
w2 = (String) JO.get("w2");
w3 = (String) JO.get("w3");
w4 = (String) JO.get("w4");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
int levelId = Integer.parseInt(id);
levelId++;
//Loading the words data to buttons
LevelActivity.levelID = String.valueOf(levelId);
LevelActivity.imageURL = img;
LevelActivity.button1Word = w1;
LevelActivity.button2Word = w2;
LevelActivity.button3Word = w3;
LevelActivity.button4Word = w4;
//Loading level image and level number on the screen
LevelActivity.levelIdTextView.setText(LevelActivity.levelID);
loadLevelImage();
}
public void loadLevelImage() {
Picasso.with(context).load(LevelActivity.imageURL).placeholder(R.drawable.loading)
.error(R.drawable.loading)
.into(LevelActivity.imageView, new com.squareup.picasso.Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
}
});
}
}
Thanks for viewing my answer :D tell me if you need any other code.
At the end of onPostExecute() calls to
checkButton1()
checkButton2()
checkButton3()
checkButton4()
are missing. Because of that, buttons cannot know about the new values and therefore remain empty.
Related
I got a method that fetch data from a web service, so Im looking for a way to call it as a method.
How can I turn this code into a method? or can I call a class in a method? because it has a protected method and extended from a class, but if I implemented the extended class AsyncTask to the class I need to use the Json fetching protected method doInBackground it says "Interface expexted here".
Here's my code that I need to convert it to a method or a way to add it to the class I want to use it in:
Notice: I already extended AppCompatActivity to the class I want to call doInBackground in so I cannot extend FetchData class.
Thanks a lot :D
package com.example.wordspuzzlejsontest;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class FetchData extends AsyncTask<Void, Void, Void> {
final String update = "4";
String data = "";
int currentLevel;
Context context;
FetchData(Context context) {
this.context = context;
}
#Override
protected Void doInBackground(Void... voids) {
try {
URL url = new URL("https://api.jsonbin.io/b/5e42776dd18e4016617690ce/" + update);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = "";
while (line != null) {
line = bufferedReader.readLine();
data = data + line;
}
JSONArray JA = new JSONArray(data);
SharedPreferences sharedPreferences = context.getSharedPreferences("SHARED_PREFS", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
currentLevel = sharedPreferences.getInt("currentLevel", 0);
for (int i = 0; i < JA.length();) {
i = currentLevel;
JSONObject JO = (JSONObject) JA.get(i);
String id = (String) JO.get("id");
String img = (String) JO.get("img");
String w1 = (String) JO.get("w1");
String w2 = (String) JO.get("w2");
String w3 = (String) JO.get("w3");
String w4 = (String) JO.get("w4");
editor.putString("id" + i, id);
editor.putString("img" + i, img);
editor.putString("w1" + i, w1);
editor.putString("w2" + i, w2);
editor.putString("w3" + i, w3);
editor.putString("w4" + i, w4);
editor.apply();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
```
Summing up my comments:
Create a new class called NewClass.java
class NewClass extends FetchData{
public Void fetchData(Void... voids){ return this.doInBackground(voids);}
}
Since doInBackground in a protected method, you will have private access inside NewClass.java
New to using REST API and JSON files, but I have retrieved data from a weather API about my current locations weather conditions. The JSON file has data, such as my location, weather speed etc. I wish to sort all these individual parts of data into textViews so they can be clearly seen.
My Asynch Class:
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.AsyncTask;
import java.util.ArrayList;
import android.widget.*;
import java.util.Date;
import android.util.Log;
public class RESTAPI extends Activity {
ArrayList<String> items = new ArrayList<String>();
// json test string
String jsonTest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_restapi);
// start the AsyncTask for calling the REST service using httpConnect class
new AsyncTaskParseJson().execute();
}
// added asynctask class methods below - you can make this class as a separate class file
public class AsyncTaskParseJson extends AsyncTask<String, String, String> {
// set the url of the web service to call
String yourServiceUrl = "http://api.apixu.com/v1/current.json?key=e87e62510df946cc84c02652162112&q=LN11RX";
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(String... arg0) {
try {
// create new instance of the httpConnect class
httpConnect jParser = new httpConnect();
// get json string from service url
String json = jParser.getJSONFromUrl(yourServiceUrl);
// save returned json to your test string
jsonTest = json.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String strFromDoInBg) {
TextView tv1 = (TextView) findViewById(R.id.jsontext);
tv1.setText(jsonTest);
}
}
}
My httpConnect Class to handle the URL:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.util.Log;
public class httpConnect {
final String TAG = "JsonParser.java";
static String json = "";
public String getJSONFromUrl(String url) {
try {
URL u = new URL(url);
HttpURLConnection restConnection = (HttpURLConnection) u.openConnection();
restConnection.setRequestMethod("GET");
restConnection.setRequestProperty("Content-length", "0");
restConnection.setUseCaches(false);
restConnection.setAllowUserInteraction(false);
restConnection.setConnectTimeout(10000);
restConnection.setReadTimeout(10000);
restConnection.connect();
int status = restConnection.getResponseCode();
// switch statement to catch HTTP 200 and 201 errors
switch (status) {
case 200:
case 201:
BufferedReader br = new BufferedReader(new InputStreamReader(restConnection.getInputStream()));
// create a new string builder to store json data returned from the REST service
StringBuilder sb = new StringBuilder();
String line;
// loop through returned data line by line and append to stringbuilder 'sb' variable
while ((line = br.readLine()) != null) {
sb.append(line+"\n");
}
br.close();
try {
json = sb.toString();
} catch (Exception e) {
Log.e(TAG, "Error parsing data " + e.toString());
}
return json;
}
// HTTP 200 and 201 error handling from switch statement
} catch (MalformedURLException ex) {
Log.e(TAG, "Malformed URL ");
} catch (IOException ex) {
Log.e(TAG, "IO Exception ");
}
return null;
}
So is there anyway to sort the returned data and put each bit of data into its own textbox?
Screenshot of JSON:
If I am understanding your question correctly, try giving this link a go. Let me know if I have misunderstood and I will try and help you with an alternative.
Edit:
Roughly another way to dynamically create new a new TextView and set data:
TextView view;
LinearLayout currLayout = (LinearLayout) findViewById(R.id.LinearLayout);
for(String value : items) {
view = new TextView();
view.setText(value);
currLayout.addView(view);
}
Make pojo classes for the response you get:
Open any converting site like this:-
http://www.jsonschema2pojo.org/
here paste the json reponse, and click zip, all pojo class will be automatically created for you.
Now in your code do this
protected String doInBackground(String... arg0) {
try {
// create new instance of the httpConnect class
httpConnect jParser = new httpConnect();
// get json string from service url
String json = jParser.getJSONFromUrl(yourServiceUrl);
// save returned json to your test string
jsonTest = json.toString();
Gson gson = new Gson();
/*here Example class is the main pojo class, you can use this class which will be there in the zip, which is created from jsontoPojo converting site */
Example response = gson.fromJson(json, Example.class);
/*
*Now to get data
* just do this */
String name = getLocation().getName();
.
.
.
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
For details view this example,example of data parsing using gson
And you need to add this dependency as well in build.gradle file
compile 'com.google.code.gson:gson:2.4'
This is a mobile app composed in Java with Codename One's CODAPPS plugin for NetBeans IDE.
The code is from a Coursera course where a Twitter-clone app was developed. In the course the coding of the app was show, but the end result -- a wall of "Roars" (Tweets) which appears when you click Refresh -- was not shown, and does not appear to work.
There are no errors, but I simply cannot get it to display any Roars (Tweets). These are downloaded as JSON data. I confirmed that the data uploads and downloads as it should; it's just not displaying.
All of the user-written code is stored in a file called StateMachine.java. I will paste this code below. The entire project is also available here on GitHub.
/**
* Your application code goes here
*/
package userclasses;
import com.codename1.analytics.AnalyticsService;
import com.codename1.io.ConnectionRequest;
import com.codename1.io.NetworkManager;
import com.codename1.io.Preferences;
import com.codename1.io.Util;
import com.codename1.processing.Result;
import generated.StateMachineBase;
import com.codename1.ui.*;
import com.codename1.ui.events.*;
import com.codename1.ui.layouts.BoxLayout;
import com.codename1.ui.layouts.Layout;
import com.codename1.ui.util.Resources;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Hashtable;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
*
* #author Your name here
*/
public class StateMachine extends StateMachineBase {
String roar;
public StateMachine(String resFile) {
super(resFile);
// do not modify, write code in initVars and initialize class members there,
// the constructor might be invoked too late due to race conditions that might occur
}
/**
* this method should be used to initialize variables instead of the
* constructor/class scope to avoid race conditions
*/
protected void initVars(Resources res) {
AnalyticsService.init("UA-67803686-1", "irrelevant");
AnalyticsService.setAppsMode(true);
}
#Override
protected void onMain_ButtonAction(Component c, ActionEvent event) {
Hashtable infoToBeSent = new Hashtable();
infoToBeSent.put("roar", roar);
infoToBeSent.put("author", "seinecle");
final String infoInString = Result.fromContent(infoToBeSent).toString();
String firebase = "https://roar.firebaseIO.com/listofroars.json";
ConnectionRequest request = new ConnectionRequest() {
#Override
protected void buildRequestBody(OutputStream os) throws IOException {
os.write(infoInString.getBytes("UTF-8"));
}
};
request.setUrl(firebase);
request.setPost(true);
request.setHttpMethod("POST");
request.setContentType("application/json");
NetworkManager.getInstance().addToQueueAndWait(request);
}
#Override
protected void onMain_TextAreaAction(Component c, ActionEvent event) {
roar = findTextArea().getText();
if (roar == null) {
roar = "we did not get a roar from you";
}
}
#Override
protected void onWall_ButtonAction(Component c, ActionEvent event) {
try {
String roars = "https://roar.firebaseIO.com/listofroars.json";
//if we want to retrieve only the latest 10 roars posted
//String roars = "https://roar.firebaseIO.com/listofroars.json" + "?" + "orderBy=\"$key\"" + "&" + "limitToLast=10";
ConnectionRequest request = new ConnectionRequest();
request.setUrl(roars);
request.setPost(false);
request.setHttpMethod("GET");
request.setContentType("application/json");
NetworkManager.getInstance().addToQueueAndWait(request);
ByteArrayInputStream allRoarsInBytes = new ByteArrayInputStream(request.getResponseData());
String responseInString = Util.readToString(allRoarsInBytes, "UTF-8");
JSONObject allRoarsInJsonFormat = new JSONObject(responseInString);
JSONArray listOfRoarIds = allRoarsInJsonFormat.names();
Form wallScreen = c.getComponentForm();
Container myContainerForAllRoars = new Container();
Layout myLayout = new BoxLayout(BoxLayout.Y_AXIS);
myContainerForAllRoars.setLayout(myLayout);
Integer counterOfRoars = 0;
while (counterOfRoars < allRoarsInJsonFormat.length()) {
String idOfOneRoar = listOfRoarIds.getString(counterOfRoars);
JSONObject oneRoarInJsonFormat = (JSONObject) allRoarsInJsonFormat.get(idOfOneRoar);
Container myRoarContainer = new Container();
String author = oneRoarInJsonFormat.getString("author");
String roarText = oneRoarInJsonFormat.getString("roar");
Label myLabelForAuthor = new Label(author);
Label myLabelForRoar = new Label(roarText);
myRoarContainer.addComponent(myLabelForAuthor);
myRoarContainer.addComponent(myLabelForRoar);
myContainerForAllRoars.addComponent(myRoarContainer);
counterOfRoars = counterOfRoars + 1;
}
wallScreen.addComponent(wallScreen.getComponentCount(), myContainerForAllRoars);
wallScreen.revalidate();
} catch (IOException ex) {
} catch (JSONException ex) {
}
}
#Override
protected void onCreateUserName() {
String userName;
userName = Preferences.get("username", "");
if (userName != null) {
showForm("Main", null);
AnalyticsService.visit("Main", "UserName");
}
}
#Override
protected void onUserName_ButtonAction(Component c, ActionEvent event) {
String userName = findTextField().getText();
if (userName == null || userName.length() == 0) {
} else {
Preferences.set("username", userName);
showForm("Main", null);
AnalyticsService.visit("Main", "UserName");
}
}
}
I tried adding wallScreen.show() and Wall.show() but it didn't fix the problem.
Just add the following code and it works well on both connections
request.setDuplicateSupported(true);
Please bear with me, I'm a beginner to Android development.
I'm trying to put URLs in an ArrayList and return the ArrayList to MainActivity.
I can update it in the Connection class but when I try to check if it's working in the getValidURL() method, it doesn't display anything.
In MainActivity, I also use Log.d to log whether the ArrayList returned is empty or not, and it is.
What am I doing wrong? I feel like I'm making a very silly mistake and I have no idea what it is.
MainActivity.urlEnteredButton():
public void urlEnteredButton(View view) throws IOException {
Button ok = (Button) findViewById(R.id.urlButtonOK);
Intent displayArticleScreen = new Intent(this, SecondActivity.class);
GetURLS work = new GetURLS();
ArrayList<String> URLS = work.getValidURL();
if(URLS.isEmpty()){
Log.d("URL IN MAIN IS: " , "EMPTY!!!!!");
}
for(String s : URLS){
Log.d("URL Main: " , s);
}
if(!URLS.isEmpty()) {
String[] workingURLS = URLS.toArray(new String[URLS.size()]);
final int result = 1;
displayArticleScreen.putExtra("url", workingURLS);
startActivity(displayArticleScreen);
}
}
GetURLS.java
import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.ArrayList;
public class GetURLS {
ArrayList<String> workingURLS = new ArrayList<String>();
Connection myConnection = new Connection();
public GetURLS() throws IOException {
myConnection.execute();
}
public void update(ArrayList<String> temp){
for(String s : temp){
workingURLS.add(s);
}
for(String s : workingURLS){
Log.d("URL in workingURLS", s);
}
}
public ArrayList<String> getValidURL(){
for(String s : workingURLS){
Log.d("URL in getValidURL()", s);
}
return workingURLS;
}
private boolean isValidURL(String temp){
if(temp.contains("thestar.com") && temp.length() > 75 && (temp.contains("/news/") || temp.contains("/business/") || temp.contains("/sports/") || temp.contains("/entertainment/") || temp.contains("/life/"))){
return true;
}
return false;
}
private class Connection extends AsyncTask<Void , Void, ArrayList<String>> {
ArrayList<String> tempAL = new ArrayList<String>();
#Override
protected ArrayList<String> doInBackground(Void... params){
Document doc = null;
Elements links = null;
try {
doc = Jsoup.connect("http://www.thestar.com/").get();
links = doc.select("a");
} catch (IOException e) {
e.printStackTrace();
}
if (links != null) {
for(Element link : links){
String temp = link.attr("href");
if(isValidURL(temp)){
tempAL.add(temp);
}
}
}
return tempAL;
}
#Override
protected void onPostExecute(ArrayList<String> tempAL){
update(tempAL);
}
}
}
In logcat, I get the following messages:
07-10 16:41:58.824 21413-21413/com.bloopbloop.ishyfishyy.thestargrabber D/URL IN MAIN IS:﹕ EMPTY!!!!!
07-10 16:41:59.894 21413-21413/com.bloopbloop.ishyfishyy.thestargrabber D/URL in workingURLS﹕ http://www.thestar.com/news/crime/2015/07/10/lecent-rosss-mother-too-grief-stricken-to-speak.html
//followed by all the other URLS I requested
In MainActivity, why is if(URLS.isEmpty()) executed BEFORE ArrayList<String> URLS = work.getValidURL(); according to the timestamp?
Why won't the ArrayList in the GetURLS class get updated?
Thanks in advance
Since myConnectiont.execute() is starting an AsyncTask, it's happening concurrently in the background. So execution continues past that in the MainActivity even though all you're networking calls haven't completed. That's why your logs are showing your ArrayList as empty: at the time the execution gets to it, it is empty. It's only after that the thread with the networking completes that they are populated, and your update() method gets called.
I'm building a IRC Bot (PircBot) and want to make a follower - thanks function for twitch.tv.
With this json link im able to call the List of ppl which currently are following Channel XY.
Ive Made up already the Code to receive the list all X seconds here:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.Charset;
import org.json.JSONException;
import org.json.JSONObject;
private String readAll(Reader rd) throws IOException {
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = rd.read()) != -1) {
sb.append((char) cp);
}
return sb.toString();
}
public JSONObject readJsonFromUrl(String url) throws IOException, JSONException {
InputStream is = new URL(url).openStream();
try {
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
String jsonText = readAll(rd);
JSONObject json = new JSONObject(jsonText);
return json;
} finally {
is.close();
}
}
public void StreamChecker() throws IOException, JSONException {
json = readJsonFromUrl("https://api.twitch.tv/kraken/channels/"+ownerchannel +"/follows");
System.out.println(json.get("_total"));
And here is the Timer that Calls the Action all X minutes:
public void LiveChecker() {
TTtwl.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
try {
StreamChecker();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
System.out.println(json.toString());
}
}, 1000*30, 1000*30);
}
Now my Question is simple:
How is the best way to check the list i received earlier with the one i received now if there are any new names (following people) so i can call them out in a IRC message?
Greetings
From the comments I learned you already know how to get the total number of Subscribers.
Just push this approach a little further and you will arrive where you wanted to go to:
private static HashMap<Integer, String> currentFollowers =
new HashMap<Integer, String>();
public static void main(String[] args) {
// get the string from the web
String jsonInputString = "";
JSONObject json = new JSONObject(jsonInputString);
// check total followers (this is what you should know)
Integer totalFollowers = json.getInt("_total");
System.out.println("Total followers: " + totalFollowers);
// check if there are new followers (exercise: what about unsubscribers?)
if(totalFollowers > currentFollowers.size()) {
// get the array of followers
JSONArray followerArray = json.getJSONArray("follows");
// go through it and check if the user is in the HashMap
for(int i = 0; i < followerArray.length(); ++i) {
JSONObject follower = new JSONObject(
followerArray.get(i).toString()
);
JSONObject userObject = follower.getJSONObject("user");
Integer id = userObject.getInt("_id");
if(!currentFollowers.containsKey(id)) {
// here you have not to print but to sendit to IRC
String name = userObject.getString("display_name");
System.out.println("New subscriber: " + name + ", welcome!");
currentFollowers.put(id, name);
}
}
}
}
Of course you could also use lists, compare the names, even create a class TwitchUser and save all things there to compare them and make it easier. You can also create a second collection you fill new each time (a bit like a "double buffered" approach) and compare both collections then.
If you just have problems with understanding how json works (i.e. getting the right objects) I recommend just having a look at the javadoc of the classes you seem to use, maybe also directly at json.org, which has nice diagrams explaining it. Also you should try
JSONObject json = new JSONObject(jsonString);
System.out.println(json.toString(2));
which indents the String and provides a great overview over the structure.