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);
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.
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;
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 am trying to understand the concept of Strong and Causal consistency by implementing it in Multi-threaded Java. I have written the following code using the Vert.x framework. I am trying to implement the following:
Strong Consistency
Every PUT (write) request is atomic across all replicas.
At any point in time, only 1 PUT request per key can be performed on the datacenter instances.
A GET operation per key is to be blocked if a PUT operation for the same key is being processed.
The locking of datacenters is to be done at key level i.e. operations on multiple keys can run in parallel.
Causal Consistency
ALL PUT operations per key must be seen in all the datacenters in the same order.
At any point in time, different operations can be performed in different datacenters in parallel. That is, lock only one datacenter at a time for an operation per key.
A GET operation returns the value immediately without being blocked even if it is stale.
API on the Vert.x server
Here are the following GET and PUT operations that the Vert.x server will receive and must implement:
Vertx-DNS:8080/put?key=KEY&value=VALUE
This endpoint will receive the key, value pair that needs to be stored in the datacenter instances
Vertx-DNS:8080/get?key=KEY&loc=LOCATION
This endpoint will receive the key for which the value has to be returned by the Vertx server. The server has to return the value as the response to this request. The location value is 1 for datacenter1, 2 for datacenter2 and 3 datacenter3.
KeyValueLib.PUT(String datacenterDNS, String key, String value) throws IOException
This API method will put the value for the specified key in the specified datacenter instance.
KeyValueLib.GET(String datacenterDNS, String key) throws IOException
This API method returns the value for the specified key from the specified datacenter.
Code
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 java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.TimeZone;
import java.util.Iterator;
import java.util.Collections;
import java.util.List;
import java.sql.Timestamp;
import org.vertx.java.core.Handler;
import org.vertx.java.core.MultiMap;
import org.vertx.java.core.http.HttpServer;
import org.vertx.java.core.http.HttpServerRequest;
import org.vertx.java.core.http.RouteMatcher;
import org.vertx.java.platform.Verticle;
public class Coordinator extends Verticle {
//Default mode: Strongly consistent. Possible values are "strong" and "causal"
private static String consistencyType = "strong";
/**
* TODO: Set the values of the following variables to the DNS names of your
* three dataCenter instances
*/
private static final String dataCenter1 = "ec2-52-2-18-9.compute-1.amazonaws.com";
private static final String dataCenter2 = "ec2-52-2-12-29.compute-1.amazonaws.com";
private static final String dataCenter3 = "ec2-52-2-10-12.compute-1.amazonaws.com";
#Override
public void start() {
//DO NOT MODIFY THIS
KeyValueLib.dataCenters.put(dataCenter1, 1);
KeyValueLib.dataCenters.put(dataCenter2, 2);
KeyValueLib.dataCenters.put(dataCenter3, 3);
final RouteMatcher routeMatcher = new RouteMatcher();
final HttpServer server = vertx.createHttpServer();
server.setAcceptBacklog(32767);
server.setUsePooledBuffers(true);
server.setReceiveBufferSize(4 * 1024);
routeMatcher.get("/put", new Handler<HttpServerRequest>() {
#Override
public void handle(final HttpServerRequest req) {
MultiMap map = req.params();
final String key = map.get("key");
final String value = map.get("value");
//You may use the following timestamp for ordering requests
final String timestamp = new Timestamp(System.currentTimeMillis()
+ TimeZone.getTimeZone("EST").getRawOffset()).toString();
Thread t = new Thread(new Runnable() {
public void run() {
//TODO: Write code for PUT operation here.
//Each PUT operation is handled in a different thread.
//Use helper functions.
try{
switch(consistencyType) {
case "strong":
//Do
break;
case "causal":
//Do
break;
default: continue;
}
}
}
});
t.start();
req.response().end(); //Do not remove this
}
});
routeMatcher.get("/get", new Handler<HttpServerRequest>() {
#Override
public void handle(final HttpServerRequest req) {
MultiMap map = req.params();
final String key = map.get("key");
final String loc = map.get("loc");
//You may use the following timestamp for ordering requests
final String timestamp = new Timestamp(System.currentTimeMillis()
+ TimeZone.getTimeZone("EST").getRawOffset()).toString();
Thread t = new Thread(new Runnable() {
public void run() {
//TODO: Write code for GET operation here.
//Each GET operation is handled in a different thread.
//Highly recommended that you make use of helper functions.
req.response().end("0"); //Default response = 0
}
});
t.start();
}
});
routeMatcher.get("/consistency", new Handler<HttpServerRequest>() {
#Override
public void handle(final HttpServerRequest req) {
MultiMap map = req.params();
consistencyType = map.get("consistency");
req.response().end();
}
});
routeMatcher.noMatch(new Handler<HttpServerRequest>() {
#Override
public void handle(final HttpServerRequest req) {
req.response().putHeader("Content-Type", "text/html");
String response = "Not found.";
req.response().putHeader("Content-Length",
String.valueOf(response.length()));
req.response().end(response);
req.response().close();
}
});
server.requestHandler(routeMatcher);
server.listen(8001);
}
}
KeyValueLib.java
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 java.util.HashMap;
public class KeyValueLib {
public static HashMap<String, Integer> dataCenters = new HashMap();
private static String URLHandler(String string) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
try {
String string2;
URL uRL = new URL(string);
HttpURLConnection httpURLConnection = (HttpURLConnection) uRL
.openConnection();
if (httpURLConnection.getResponseCode() != 200) {
throw new IOException(httpURLConnection.getResponseMessage());
}
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(httpURLConnection.getInputStream()));
while ((string2 = bufferedReader.readLine()) != null) {
stringBuilder.append(string2);
}
bufferedReader.close();
httpURLConnection.disconnect();
} catch (MalformedURLException var2_3) {
var2_3.printStackTrace();
}
return stringBuilder.toString();
}
public static void PUT(String string, String string2, String string3)
throws IOException {
String string4 = String.format("http://%s:8001/put?key=%s&value=%s",
string, string2, string3);
String string5 = KeyValueLib.URLHandler(string4);
try {
switch (dataCenters.get(string)) {
case 1 : {
break;
}
case 2 : {
Thread.sleep(200);
break;
}
case 3 : {
Thread.sleep(800);
break;
}
}
} catch (InterruptedException var5_5) {
// empty catch block
}
if (!string5.equals("stored")) {
System.out.println("Some error happened");
}
}
public static String GET(String string, String string2) throws IOException {
String string3 = String.format("http://%s:8001/get?key=%s", string,
string2);
String string4 = KeyValueLib.URLHandler(string3);
return string4;
}
}
Can someone help me how to implement this?
I am working on a project to invoke a web service using android. I use ksoap2 for that.
I created a my own data type(just to try) which contains two string variables. It is like this
public class MyType {
String fName;
String lName;
public MyType(String s1,String s2){
fName = s1;
lName = s2;
}
}
I created this data type at both ends.(web service end and android application end). I wrote a program to invoke web service and then to concatenate given strings using my data type.
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import java.io.IOException;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import org.xmlpull.v1.XmlPullParserException;
import android.os.AsyncTask;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
public final static String URL = "http://192.168.69.1:8080/WebApplication4/MyWebService?wsdl";
public static final String NAMESPACE = "http://mywebservice.android.com/";
public static final String SOAP_ACTION_PREFIX = "/";
private static final String METHOD = "objectMethod";
private TextView textView;
MyType mt = new MyType("Upul","Tharanga");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.test);
AsyncTaskRunner runner = new AsyncTaskRunner(mt);
runner.execute();
}
private class AsyncTaskRunner extends AsyncTask<Integer, String, String> {
private String resp;
MyType a;
public AsyncTaskRunner(MyType a){
this.a = a;
}
#Override
protected String doInBackground(Integer... params) {
publishProgress("Loading contents..."); // Calls onProgressUpdate()
try {
// SoapEnvelop.VER11 is SOAP Version 1.1 constant
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
SoapObject request = new SoapObject(NAMESPACE, METHOD);
PropertyInfo pi1=new PropertyInfo();
pi1.setType(String.class);
pi1.setName("parameter");
pi1.setValue(a);
request.addProperty(pi1);
envelope.bodyOut = request;
HttpTransportSE transport = new HttpTransportSE(URL);
try {
transport.call(NAMESPACE + SOAP_ACTION_PREFIX + METHOD, envelope);
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
//bodyIn is the body object received with this envelope
if (envelope.bodyIn != null) {
//getProperty() Returns a specific property at a certain index.
//SoapPrimitive resultSOAP = (SoapPrimitive) ((SoapObject) envelope.bodyIn).getProperty(0);
//Object resultSOAP = (SoapPrimitive)((SoapObject) envelope.bodyIn).getProperty(0);
Object resultSOAP = (SoapPrimitive)((SoapObject) envelope.bodyIn).getProperty(0);
resp=resultSOAP.toString();
}
} catch (Exception e) {
e.printStackTrace();
resp = e.getMessage();
}
return resp;
}
/**
*
* #see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
#Override
protected void onPostExecute(String result) {
// execution of result of Long time consuming operation
// In this example it is the return value from the web service
textView.setText(result);
}
/**
*
* #see android.os.AsyncTask#onPreExecute()
*/
#Override
protected void onPreExecute() {
// Things to be done before execution of long running operation. For
// example showing ProgessDialog
}
/**
*
* #see android.os.AsyncTask#onProgressUpdate(Progress[])
*/
#Override
protected void onProgressUpdate(String... text) {
textView.setText(text[0]);
// Things to be done while execution of long running operation is in
// progress. For example updating ProgessDialog
}
}
}
What my web service do is take the MyType parameter as input and concatenate those two given strings and return the concatenated string.
When I run the android application I get an error(run time error I think) saying cannot serialize MyType.
Any suggestions to solve the issue?
Try implementing Serializable
public class MyType implements Serializable {
String fName;
String lName;
public MyType(String s1,String s2){
fName = s1;
lName = s2;
}
}