Here's my app. It's supposed to get a JSON String based on a HTTP query to Google Books and show the list of all the found books. Google's response always returns only 10 books. But if you change "startIndex" parameter in your HTTP request then it will show 10 different books. My app used to only show 10 first books. After I'd done changes to my list of books so that it contained all the found books, my app stopped finding anything and started showing "No books found." regardless of what you put in your search query. Loader doesn't even start.
The only thing Logcat shows is this: "unknown bits set in runtime_flags 0x8000".
How could it be fixed?
I use an Android Emulator in Android Studio.
MainActivity.java
package com.example.android.booklisting;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.app.LoaderManager;
import android.content.Loader;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<Book>> {
/** Adapter for the list of earthquakes */
private BookAdapter mAdapter;
TextView mEmptyStateTextView;
ProgressBar loadingIndicator;
int loader_id = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadingIndicator = findViewById(R.id.loading_indicator);
Button searchButton = findViewById(R.id.search_button);
searchButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
EditText searchText = findViewById(R.id.search_text);
QueryUtils.setSearchQuery(QueryUtils.getINIITIAL_GOOGLE_BOOKS_URL()
+ searchText.getText().toString()
.replace("\\s", "+"));
mAdapter = new BookAdapter(MainActivity.this,
new ArrayList<Book>());
ListView listView = findViewById(R.id.list);
listView.setAdapter(mAdapter);
mEmptyStateTextView = findViewById(R.id.empty_view);
listView.setEmptyView(mEmptyStateTextView);
// Get a reference to the ConnectivityManager to check state of network connectivity
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
// Get details on the currently active default data network
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
// If there is a network connection, fetch data
if (networkInfo != null && networkInfo.isConnected()) {
// Get a reference to the LoaderManager, in order to interact with loaders.
LoaderManager loaderManager = getLoaderManager();
// Initialize the loader. Pass in the int ID 1 and pass in null for
// the bundle. Pass in this activity for the LoaderCallbacks parameter (which is valid
// because this activity implements the LoaderCallbacks interface).
if (loader_id == 0) {
loader_id++;
loaderManager.initLoader(loader_id, null, MainActivity.this);
}
else {
loaderManager.restartLoader(loader_id, null, MainActivity.this);
}
}
else {
// Otherwise, display error
// First, hide loading indicator so error message will be visible
View loadingIndicator = findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
// Update empty state with no connection error message
mEmptyStateTextView.setText(getString(R.string.no_internet_connection));
}
}
});
}
#NonNull
#Override
public Loader<List<Book>> onCreateLoader(int id, #Nullable Bundle args) {
// If there were no books found last time, delete "no books found"
// from the screen.
mEmptyStateTextView.setText("");
// Make loading indicator appear because the loading is about to start
loadingIndicator.setVisibility(View.VISIBLE);
// Create a new loader for the given URL
return new BookLoader(this, QueryUtils.getSearchQuery());
}
#Override
public void onLoadFinished(#NonNull Loader<List<Book>> loader, List<Book> books) {
// Hide loading indicator because the data has been loaded
loadingIndicator.setVisibility(View.GONE);
// Clear the adapter of previous book data
mAdapter.clear();
// If there is a valid list of {#link Book}s, then add them to the adapter's
// data set. This will trigger the ListView to update.
if (books != null && !books.isEmpty()) {
mAdapter.addAll(books);
}
// Set empty state text to display "No books found."
if (!QueryUtils.hasResults)
mEmptyStateTextView.setText(getString(R.string.no_books_found));
}
#Override
public void onLoaderReset(#NonNull Loader<List<Book>> loader) {
// Loader reset, so we can clear out our existing data.
mAdapter.clear();
}
}
QueryUtils.java
package com.example.android.booklisting;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.util.Log;
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;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.lang.StringBuilder;
public class QueryUtils {
private static final String INIITIAL_GOOGLE_BOOKS_URL = "https://www.googleapis.com/books/v1/volumes?startIndex=0&q=";
private static String searchQuery;
// Variable for checking if there are books found
public static boolean hasResults;
private static int numberOfIterations;
private QueryUtils() {
}
public static String getINIITIAL_GOOGLE_BOOKS_URL() {
return INIITIAL_GOOGLE_BOOKS_URL;
}
public static void setSearchQuery(String searchQuery) {
QueryUtils.searchQuery = searchQuery;
}
public static String getSearchQuery() {
return searchQuery;
}
/**
* Query the Google Books dataset and return an {#link ArrayList} object to represent a list of books.
*/
/**
* Return a list of {#link Book} objects that has been built up from
* parsing the given JSON response.
*/
private static List<Book> extractBooksFromJson(String bookJSON) {
// If the JSON string is empty or null, then return early.
if (TextUtils.isEmpty(bookJSON)) {
Log.e("nojson", "No JSON returned");
return null;
}
// Create an empty ArrayList that we can start adding books to
List<Book> books = new ArrayList<>();
// Try to parse the JSON response string. If there's a problem with the way the JSON
// is formatted, a JSONException exception object will be thrown.
// Catch the exception so the app doesn't crash, and print the error message to the logs.
try {
// Create a JSONObject from the JSON response string
JSONObject baseJsonResponse = new JSONObject(bookJSON);
Log.v("success", "JSONObject sucessfully created!");
// Check if there are books found
hasResults = false;
if (hasBooksFound(baseJsonResponse))
{
hasResults = true;
}
numberOfIterations = baseJsonResponse.getInt("totalItems")/10 + 1;
// Extract the JSONArray associated with the key called "items",
// which represents a list of items (or books).
JSONArray bookArray = baseJsonResponse.getJSONArray("items");
// For each book in the bookArray, create a {#link Book} object
for (int i = 0; i < bookArray.length(); i++) {
// Get a single Book at position i within the list of books
JSONObject currentBook = bookArray.getJSONObject(i);
// For a given book, extract the JSONObject associated with the
// key called "volumeInfo", which represents a list of all information
// for that book.
JSONObject volumeInfo = currentBook.getJSONObject("volumeInfo");
// Extract the value for the key called "title"
String title = volumeInfo.getString("title");
String authorsString = "No information";
//Extract the JSONArray associated with the key called "authors"
if (volumeInfo.has("authors")) {
JSONArray jsonAuthors = volumeInfo.getJSONArray("authors");
ArrayList<String> authors = new ArrayList<>();
StringBuilder authorsStringBuilder = new StringBuilder();
for (int j = 0; j < jsonAuthors.length(); j++) {
// Add a specific author to the "authors" list
// and add it to a the "authorsStringBuilder"
authors.add(jsonAuthors.getString(j));
authorsStringBuilder.append(authors.get(j) + ", \n");
}
//Remove the last 3 elements in the "authorsStringBuilder"
authorsStringBuilder.delete(authorsStringBuilder.length() - 3,
authorsStringBuilder.length() - 1);
//Convert StringBuilder to String
authorsString = authorsStringBuilder.toString();
}
// Extract the value for the key called "publishedDate"
String releaseDate = volumeInfo.getString("publishedDate");
//The link for a book cover
String imageLink;
// Get the JSONObject "readingModes" having information about
// whether or not a given book has a cover
JSONObject readingModes = volumeInfo.getJSONObject("readingModes");
// Extract the value for the key called "image"
boolean hasACover = readingModes.getBoolean("image");
//Check if a given book has a cover
if (hasACover)
{
// If yes, then assign a link for the book
// to the imageLink
imageLink = volumeInfo.getJSONObject("imageLinks")
.getString("thumbnail");
Log.v("Cover check", "Book has a cover");
}
else {
// If not, then assign the imageLink the default cover
imageLink = "https://books.google.ru/googlebooks/images/no_cover_thumb.gif";
}
//Get a book cover
Bitmap bookCover = getImage(imageLink);
// Create a new {#link Book} object with the magnitude, location, time,
// and url from the JSON response.
Book book = new Book(title, authorsString, releaseDate, bookCover);
// Add the new {#link Book} to the list of books.
books.add(book);
}
}
catch (JSONException e) {
// If an error is thrown when executing any of the above statements in the "try" block,
// catch the exception here, so the app doesn't crash. Print a log message
// with the message from the exception.
Log.e("QueryUtils", "Problem parsing the book JSON results", e);
}
// Return the list of books
return books;
}
/**
* Get a book cover.
*/
/**
* Return a book cover
*/
private static Bitmap getImage(String imageLink)
{
Bitmap image = null;
try {
URL url = new URL(imageLink);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
image = BitmapFactory.decodeStream(input);
} catch (IOException e) {
// Log exception
Log.e("getImage: ", "Image problems", e);
}
return image;
}
/**
* Check if there are books found
* #param baseJsonResponse — root JSONObject from the Google Books HTTP response
* #return boolean value (true if there are results, false if not)
*/
private static boolean hasBooksFound(JSONObject baseJsonResponse) {
boolean hasBooksFound = true;
try {
if (baseJsonResponse.getInt("totalItems") == 0) {
hasBooksFound = false;
}
}
catch (JSONException e)
{
Log.e("hasBooksFound: ", "JSONException", e);
}
return hasBooksFound;
}
public static int getNumberOfIterations() {
return numberOfIterations;
}
/**
* Query the Google Books dataset and return a list of {#link Book} objects.
*/
public static List<Book> fetchEarthquakeData(String requestUrl) {
// Create URL object
URL url = createUrl(requestUrl);
// Perform HTTP request to the URL and receive a JSON response back
String jsonResponse = null;
try {
jsonResponse = makeHttpRequest(url);
} catch (IOException e) {
Log.e("", "Problem making the HTTP request.", e);
}
// Extract relevant fields from the JSON response and create a list of {#link Book}s
List<Book> books = extractBooksFromJson(jsonResponse);
Log.v("QueryUtils", "fetching data");
// Return the list of {#link book}s
return books;
}
/**
* Returns new URL object from the given string URL.
*/
private static URL createUrl(String stringUrl) {
URL url = null;
try {
url = new URL(stringUrl);
} catch (MalformedURLException e) {
Log.e("QueryUtils: : ", "Error with creating URL", e);
}
return url;
}
/**
* Make an HTTP request to the given URL and return a String as the response.
*/
private static String makeHttpRequest(URL url) throws IOException {
String jsonResponse = "";
// If the URL is null, then return early.
if (url == null) {
return jsonResponse;
}
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// If the request was successful (response code 200),
// then read the input stream and parse the response.
if (urlConnection.getResponseCode() == 200) {
inputStream = urlConnection.getInputStream();
jsonResponse = readFromStream(inputStream);
} else {
Log.e("", "Error response code: " + urlConnection.getResponseCode());
}
} catch (IOException e) {
Log.e("", "Problem retrieving the earthquake JSON results.", e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (inputStream != null) {
inputStream.close();
}
}
return jsonResponse;
}
/**
* Convert the {#link InputStream} into a String which contains the
* whole JSON response from the server.
*/
private static String readFromStream(InputStream inputStream) throws IOException {
StringBuilder output = new StringBuilder();
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
BufferedReader reader = new BufferedReader(inputStreamReader);
String line = reader.readLine();
while (line != null) {
output.append(line);
line = reader.readLine();
}
}
return output.toString();
}
}
BookLoader.java
package com.example.android.booklisting;
import android.content.Context;
import androidx.annotation.Nullable;
import android.content.AsyncTaskLoader;
import java.util.ArrayList;
import java.util.List;
public class BookLoader extends AsyncTaskLoader<List<Book>> {
/** Query URL */
private String mUrl;
/**
* Constructs a new {#link BookLoader}.
*
* #param context of the activity
* #param url to load data from
*/
public BookLoader(Context context, String url) {
super(context);
mUrl = url;
}
#Override
protected void onStartLoading() {
forceLoad();
}
/**
* This is on a background thread.
*/
#Nullable
#Override
public List<Book> loadInBackground() {
if (mUrl == null) {
return null;
}
// List of 10 books from Google's JSON response
List<Book> currentBooks;
// List of all books combined from the different queries
// to Google Books changing startIndex parameter
List<Book> books = new ArrayList<>();
/*for (int i = 0; i < QueryUtils.getNumberOfIterations(); i = i + 10) {
mUrl = mUrl.replace("x=0", "x=" + i);*/
// Perform the network request, parse the response, and extract a list of earthquakes.
currentBooks = QueryUtils.fetchEarthquakeData(mUrl);
//books.addAll(currentBooks);
//}
return currentBooks;
//return books;
}
}
BookAdapter.java
package com.example.android.booklisting;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;
public class BookAdapter extends ArrayAdapter<Book> {
public BookAdapter(Activity context, ArrayList<Book> books) {
super(context, 0, books);
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View listItemView = convertView;
if (listItemView == null)
{
listItemView = LayoutInflater.from(getContext()).inflate(
R.layout.book_item, parent, false);
}
Book currentBook = getItem(position);
TextView bookTitleView = listItemView.findViewById(R.id.book_title);
bookTitleView.setText(currentBook.getTitle());
TextView bookAuthorView = listItemView.findViewById(R.id.book_author);
bookAuthorView.setText(currentBook.getAuthor());
TextView bookReleaseYearView = listItemView.findViewById(R.id.book_release_year);
bookReleaseYearView.setText(currentBook.getReleaseYear());
ImageView bookCoverView = listItemView.findViewById(R.id.book_cover);
bookCoverView.setImageBitmap(currentBook.getBookCover());
return listItemView;
}
}
Changes that cause the error can be found in BookLoader.java's loadInBackground() method:
public List<Book> loadInBackground() {
if (mUrl == null) {
return null;
}
// List of 10 books from Google's JSON response
List<Book> currentBooks;
// List of all books combined from the different queries
// to Google Books changing startIndex parameter
List<Book> books = new ArrayList<>();
/*for (int i = 0; i < QueryUtils.getNumberOfIterations(); i = i + 10) {
mUrl = mUrl.replace("x=0", "x=" + i);*/
// Perform the network request, parse the response, and extract a list of earthquakes.
currentBooks = QueryUtils.fetchEarthquakeData(mUrl);
//books.addAll(currentBooks);
//}
return currentBooks;
//return books;
}
Also here in QueryUtils class:
numberOfIterations = baseJsonResponse.getInt("totalItems")/10 + 1;
Related
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.
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);
I would like to know how I could call phonegap plugin from java, for example to call the javascript plugin that would desire: "cordova.exec(successCallback, failureCallback, 'CallListPlugin', 'list', params)"
But if I call it from the MainActivity? without going through the browser?
Regards!
CallListPlugin.java
package com.leafcut.ctrac;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.EmptyStackException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CallLog;
import android.provider.Contacts;
import android.provider.ContactsContract;
import android.text.format.DateFormat;
import android.util.Log;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
/**
* Grab call log data
*
* #author James Hornitzky
*/
public class CallListPlugin extends CordovaPlugin {
/** List Action */
private static final String ACTION = "list";
private static final String CONTACT_ACTION = "contact";
private static final String SHOW_ACTION = "show";
private static final String TAG = "CallListPlugin";
/*
* (non-Javadoc)
*
* #see com.phonegap.api.Plugin#execute(java.lang.String,
* org.json.JSONArray, java.lang.String)
*/
#Override
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {
boolean actionValid = true;
Log.d(TAG, "Plugin Called");
if (ACTION.equals(action)) {
try {
int limit = -1;
//obtain date to limit by
if (!data.isNull(0)) {
String d = data.getString(0);
Log.d(TAG, "Time period is: " + d);
if (d.equals("week"))
limit = -7;
else if (d.equals("month"))
limit = -30;
else if (d.equals("all"))
limit = -1000000; // LOL
}
//turn this into a date
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.DAY_OF_YEAR, limit);
Date limitDate = calendar.getTime();
String limiter = String.valueOf(limitDate.getTime());
//now do required search
JSONObject callInfo = getCallListing(limiter);
Log.d(TAG, "Returning " + callInfo.toString());
// result = new PluginResult(Status.OK, callInfo);
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, callInfo);
callbackContext.sendPluginResult(pluginResult);
callbackContext.success();
} catch (JSONException jsonEx) {
Log.d(TAG, "Got JSON Exception " + jsonEx.getMessage());
callbackContext.error(jsonEx.getMessage());
actionValid = false;
}
} else if (SHOW_ACTION.equals(action)) {
try {
if (!data.isNull(0)) {
viewContact(data.getString(0));
}
} catch (JSONException jsonEx) {
Log.d(TAG, "Got JSON Exception " + jsonEx.getMessage());
// result = new PluginResult(Status.JSON_EXCEPTION);
callbackContext.error(jsonEx.getMessage());
actionValid = false;
} catch (Exception e) {}
} else if (CONTACT_ACTION.equals(action)) {
try {
String contactInfo = getContactNameFromNumber(data.getString(0));
Log.d(TAG, "Returning " + contactInfo.toString());
// result = new PluginResult(Status.OK, contactInfo);
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, contactInfo);
callbackContext.sendPluginResult(pluginResult);
callbackContext.success();
} catch (JSONException jsonEx) {
Log.d(TAG, "Got JSON Exception " + jsonEx.getMessage());
// result = new PluginResult(Status.JSON_EXCEPTION);
callbackContext.error(jsonEx.getMessage());
actionValid = false;
}
} else {
// result = new PluginResult(Status.INVALID_ACTION);
actionValid = false;
Log.d(TAG, "Invalid action : " + action + " passed");
}
// return result;
return actionValid;
}
/**
* Gets the Directory listing for file, in JSON format
*
* #param file
* The file for which we want to do directory listing
* #return JSONObject representation of directory list. e.g
* {"filename":"/sdcard"
* ,"isdir":true,"children":[{"filename":"a.txt"
* ,"isdir":false},{...}]}
* #throws JSONException
*/
private JSONObject getCallListing(String period) throws JSONException {
JSONObject callLog = new JSONObject();
String[] strFields = {
android.provider.CallLog.Calls.DATE,
android.provider.CallLog.Calls.NUMBER,
android.provider.CallLog.Calls.TYPE,
android.provider.CallLog.Calls.DURATION,
android.provider.CallLog.Calls.NEW,
android.provider.CallLog.Calls.CACHED_NAME,
android.provider.CallLog.Calls.CACHED_NUMBER_TYPE,
android.provider.CallLog.Calls.CACHED_NUMBER_LABEL };
try {
Cursor callLogCursor = cordova.getActivity().getContentResolver().query(
android.provider.CallLog.Calls.CONTENT_URI,
strFields,
CallLog.Calls.DATE + ">?",
new String[] {period},
android.provider.CallLog.Calls.DEFAULT_SORT_ORDER);
int callCount = callLogCursor.getCount();
if (callCount > 0) {
JSONObject callLogItem = new JSONObject();
JSONArray callLogItems = new JSONArray();
callLogCursor.moveToFirst();
do {
callLogItem.put("date", callLogCursor.getLong(0));
callLogItem.put("number", callLogCursor.getString(1));
callLogItem.put("type", callLogCursor.getInt(2));
callLogItem.put("duration", callLogCursor.getLong(3));
callLogItem.put("new", callLogCursor.getInt(4));
callLogItem.put("cachedName", callLogCursor.getString(5));
callLogItem.put("cachedNumberType", callLogCursor.getInt(6));
//callLogItem.put("name", getContactNameFromNumber(callLogCursor.getString(1))); //grab name too
callLogItems.put(callLogItem);
callLogItem = new JSONObject();
} while (callLogCursor.moveToNext());
callLog.put("rows", callLogItems);
}
callLogCursor.close();
} catch (Exception e) {
Log.d("CallLog_Plugin",
" ERROR : SQL to get cursor: ERROR " + e.getMessage());
}
return callLog;
}
/**
* Show contact data based on id
* #param number
*/
private void viewContact(String number) {
Intent i = new Intent(ContactsContract.Intents.SHOW_OR_CREATE_CONTACT,
Uri.parse(String.format("tel: %s", number)));
this.cordova.getActivity().startActivity(i);
}
/**
* Util method to grab name based on number
*
*/
private String getContactNameFromNumber(String number) {
// define the columns I want the query to return
String[] projection = new String[] { Contacts.Phones.DISPLAY_NAME, Contacts.Phones.NUMBER };
// encode the phone number and build the filter URI
Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, Uri.encode(number));
// query time
Cursor c = cordova.getActivity().getContentResolver().query(contactUri, projection, null, null, null);
// if the query returns 1 or more results
// return the first result
if (c.moveToFirst()) {
String name = c.getString(c.getColumnIndex(Contacts.Phones.DISPLAY_NAME));
c.deactivate();
return name;
}
// return the original number if no match was found
return number;
}
}
You would want to import the package above into your main Java file with:
import com.leafcut.ctrac.CallListPlugin;
After that you should have access to any of the public methods of CallListPlugin, example:
CallListPlugin.execute(String some_string, JSONArray some_array, CallbackContext some_context);