JSoup parsed elements empty - android

I am trying to parse some data using JSoup, this is all happening in a asynctask (doInBackground) part of my MainActivity.
Unfortunately all the elements (9) are empty when I execute the app.
When I debug below codeline, I actually get the complete website, it`s all there.
The method readMultipleLinesRespone() is located in another class HttpUtility where I also call my Post and Get requests.
I tested this upfront by saving the website as a file and using JSoups assets ability, it worked perfectly then.
The setupAdapter() method in onPostExecute fills a ExpandableListview with data, should this info be nessecary. If you need more info pls ask.
Can somebody assist and tell me what I am doing wrong?
response1 = util.readMultipleLinesRespone(); <--- debugged and all data (seems) to be there but isn`t.
Edit: If I print response1, there is indeed no data to parse.
Logcat output:
E/Resonse:: [Ljava.lang.String;#3d3410a
Below is the method readMultipleLinesRespone from HttpUtility class:
public String[] readMultipleLinesRespone() throws IOException {
InputStream inputStream = null;
if (httpConn != null) {
inputStream = httpConn.getInputStream();
} else {
throw new IOException("Connection is not established.");
}
BufferedReader reader = new BufferedReader(new InputStreamReader(
inputStream));
List<String> response = new ArrayList<String>();
String line = "";
while ((line = reader.readLine()) != null) {
response.add(line);
}
reader.close();
return (String[]) response.toArray(new String[0]);
}
The asynctask where it`s all hapening:
private class FetchWebsiteData extends AsyncTask<Void, Void, Void> {
ProgressDialog mProgressDialog;
#Override
protected void onPreExecute() {
this.mProgressDialog = new ProgressDialog(getActivity());
mProgressDialog.setMessage("Laden...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... result) {
try {
util.sendGetRequest("https://mobile.somesite.nl/Data", null);
response1 = util.readMultipleLinesRespone();
} catch (IOException e) {
e.printStackTrace();
}
if (response1.length > 0) {
Document doc = Jsoup.parse(response1.toString());
// Get the html document title
Elements els = doc.select("span[class=item-value pull-right]");
if (els.size() > 0) {
fac_naam = els.get(0).text();
fac_straat = els.get(1).text();
fac_post = els.get(2).text();
con_tel = els.get(3).text();
con_email = els.get(4).text();
betaal_reknr = els.get(5).text();
betaal_houd = els.get(6).text();
zig_gebruiker = els.get(7).text();
zig_wacht = els.get(8).text();
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPreExecute();
setupAdapter();
mProgressDialog.dismiss();
}
}

In the meantime I solved the problem.
I did not pass the response string correctly to the asynctask which parses the required elements.
Just required a public string in which the response is being set and passed (not an elegant way but it works):
public static String HttpResponse = "";
In the HttpUtility class:
public String[] readMultipleLinesRespone() throws IOException {
...
TabFragment1.HttpResponse = response.toString();
...
return (String[]) response.toArray(new String[0]);
}
Then pass it to the asynctask:
#Override
protected Void doInBackground(Void... result) {
try {
util.sendGetRequest(LoginActivity.PersData_URL, null);
util.readMultipleLinesRespone();
} catch (IOException e) {
e.printStackTrace();
}
if (HttpResponse.length() > 0) {
Document doc = Jsoup.parse(HttpResponse.toString());
// Get the html document title
Elements els = doc.select("span[class=item-value pull-right]");
...
}
return null;
}

Related

Unit Testing Android Studio Textview

This is my main activity which gets a json array from a URL. My problem is that when I try and Unit test what should be in the textview it gives me a null pointer exeption.
public class MainActivity extends AppCompatActivity {
TextView txtJson;
ProgressDialog pd;
public static TextView testString;
String jsonString = null;
List<Location> locations;`enter code here`
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtJson = (TextView) findViewById(R.id.tvJsonItem);
testString = (TextView) findViewById(R.id.test_for_string);
new JsonTask().execute("https://wsu-dining-service.s3.amazonaws.com/current-menu.json");
}
protected void postCreate()
{
mapStrinToClass();
testString.setText(locations.get(0).getName());
}
private void mapStrinToClass()
{
ObjectMapper objectMapper = new ObjectMapper();
JsonFactory jsonFactory = objectMapper.getFactory();
try {
JsonParser jsonParser = jsonFactory.createParser(jsonString);
locations = objectMapper.readValue(jsonString,
new TypeReference<List<Location>>() {
});
} catch (IOException e) {
e.printStackTrace();
}
}
private class JsonTask extends AsyncTask<String, String, String> {
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(MainActivity.this);
pd.setMessage("Please wait");
pd.setCancelable(false);
pd.show();
}
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line+"\n");
Log.d("Response: ", "> " + line); //here u ll get whole response...... :-)
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (pd.isShowing()){
pd.dismiss();
}
jsonString = result;
postCreate();
}
}
}
My unit test
* When I run the app the textview is populated with "Tim & Jeanne's Dining Commons" but the test fails and says the testString.getText().toString(); is null
#Test
public void isMenuCorrect() {
String menuTxt = MainActivity.testString.getText().toString();
assert(menuTxt == "Tim & Jeanne's Dining Commons");
}
First of all, you should use Espresso to run UI tests, under the androidTest folder. Example:
onView(allOf(withId(R.id.tvJsonItem), withText("Tim & Jeanne's Dining Commons")).check(matches(isDisplayed()));
Basically what we're doing here is checking if a view with id R.id.tvJsonItem and with a text "Tim & Jeanne's Dining Commons" is displayed on the screen. Now how to run Espresso tests is not in this question's scope.
Second, your production code should never know what's going on in the tests, like you have created a TextView just to be used in your unit tests.
Finally, never have static references to your views since you can't guarantee your activity has been created by the time you try to access them. In fact, a view should only be seen by its parent. In your case, the reference TextView should be private in your activity.

arraymap is better than sparse array to memorise some data catched from a JSON file?

I had wrote a code which use a parse to catch some data from a JSON file but i don't know what kind of structure is better between the sparse array or the array map for memorise these data ?
I had used a array map but I don't know if it's too wasted on so little data data.
public class MainActivity extends AppCompatActivity {
private ProgressDialog pd;
private String TAG = MainActivity.class.getSimpleName();
public ArrayMap<Integer, ValoriDiSueg> ArrayDati = new ArrayMap<>();
Button buttonProg;
TextView textViewProg;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonProg = (Button) findViewById(R.id.button);
textViewProg = (TextView) findViewById(R.id.textView);
buttonProg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new JsonCLASS().execute("https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22");
}
});
}
private class JsonCLASS extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(MainActivity.this);
pd.setMessage("Please wait");
pd.setCancelable(false);
pd.show();
}
#Override
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
Log.d("Response: ", "> " + line); //here u ll get whole response...... :-)
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
The parse of these data
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
try {
JSONObject jsonObject = new JSONObject(result);
JSONArray Arr = new JSONArray(jsonObject.getString("weather"));
for (int i = 0; i < Arr.length(); i++){
JSONObject jsonPart = Arr.getJSONObject(i);
ArrayDati.put(i,new ValoriDiSueg( jsonPart.getString("main"), jsonPart.getString("description")));
//ArrayDati.put(i,new ValoriDiSueg("description : "+ jsonPart.getString("description")));
textViewProg.setText(textViewProg.getText()+"main : "+ ArrayDati.get(i).Main +"\n"+textViewProg.getText()+"description : "+ ArrayDati.get(i).Description );
}
} catch (Exception e ){
e.printStackTrace();
}
if (pd.isShowing()) {
pd.dismiss();
}
}
}
}
And I created a class:
public class ValoriDiSueg {
String Main;
String Description;
public ValoriDiSueg(String main, String description) {
this.Main = main;
this.Description = description;
}
}
any suggestions??
In simple:
If your key is int or long, you should use SparseArray, SparseLongArray as it will not boxing/un-boxing the key value when operates. Also, it provides similar classes for int/long values as long as the key is int/long.
If you key is not int nor long, such as an object or String, you should use ArrayMap instead as it will handle the conflicts of key hashes.
There are no much performance and memory usage difference between these two class as they are all requires O(log n) to search and O(n) to insert/delete (in most cases).

Using same AsyncTask subclass to make API call to different URLs

I am storing the data that I parsed from the JSON that is returned by my API request into the Firebase database.
submitButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String APIURL = "https://api.github.com/users/" + idInput.getText().toString();
String repoURL = "https://api.github.com/users/" + idInput.getText().toString() + "/repos";
new JSONTask().execute(APIURL);
//new JSONTask().execute(repoURL);
String parsedUserID = idInput.getText().toString();
SM.sendDataToProfile(parsedUserID);
viewPager.setCurrentItem(1);
//addUser(parsedUserID);
}
});
When the button is clicked, it calls a new JSONTask (asynctask) on the APIURL.
JSONTask
public class JSONTask extends AsyncTask<String, String, String> {
#Override
// Any non-UI thread process is running in this method. After completion, it sends the result to OnPostExecute
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
// Pass in a String and convert to URL
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
// Reads the data line by line
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer strBuffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
strBuffer.append(line);
}
// If we are able to get the data do below :
String retreivedJson = strBuffer.toString();
return retreivedJson;
// When we are not able to retreive the Data
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
// close both connection and the reader
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
And it does parsing in another function.
My question is, as you can see on my setOnClickListener, I tried to make two JSONTask on two different URLs because the first URL gives me the information of the user and the second URL (repoURL) gives me the information of the user's repositories. I tried to fetch the repo info of the user and store it into the DB, but it seems like this is a wrong approach.
What is a right way to call two separate AsyncTasks on two different URLs?
EDIT
private void addUserRepo(final String githubID, final String[] repoList) {
DatabaseReference users = databaseReference.child("users");
users.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List list = new ArrayList<String>(Arrays.asList(repoList));
databaseReference.child("users").child(githubID).child("Repos").setValue(list);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Using data parsed from
public void formatJSONArray(String results){
try {
JSONArray jsonArray = new JSONArray(results);
RepoInfo[] repoList = new RepoInfo[jsonArray.length()];
for(int i = 0; i < jsonArray.length(); i++){
JSONObject jsonObject=jsonArray.getJSONObject(i);
if(jsonObject.optString("name") != null) {
repoList[i].setRepoName(jsonObject.getString("name"));
//repoNameList.add(jsonObject.getString("name"));
}
if(jsonObject.optString("description") != null) {
repoList[i].setDescription(jsonObject.getString("description"));
//descriptionList.add(jsonObject.getString("description"));
}
if(jsonObject.optJSONObject("owner") != null){
JSONObject ownerObject=jsonObject.getJSONObject("owner");
if(ownerObject.optString("login")!=null) {
repoList[i].setOwner(ownerObject.getString("login"));
//userNameList.add(ownerObject.getString("login"));
}
}
}
} catch (JSONException jsonException){
}
}
The response of two different URLs will surely not be similar. So you need different parse methods for them.
One lazy way would be to use two different AsyncTasks subclasses for two different urls.
Another way would be to store a flag inside the asynctask indicating whether it is dealing with user or repo.
public class JSONTask extends AsyncTask <String , String , String> {
boolean fetchingRepo;
#Override
protected String doInBackground (String... params) {
fetchingRepo = params[0].endsWith("/repos");
//other statements
}
Now inside onPostExecute:
if(fetchingRepo){
//parse one way
} else {
//parse another way
}

i want to download the html content of a website using asynctask and display result in a listview

i want to download the html content of a website using asynctask, and use regex to manipulate the source code to get what i need and finally i want to display those result in a list view. this is my code it doesnt show error but when i run it on my emulator the app crashes
please guys i need assistant this is really important
public class DownloadTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String result = "";
URL url;
HttpURLConnection urlConnection = null;
try {
url = new URL(urls[0]);
urlConnection = (HttpURLConnection)url.openConnection();
InputStream in = urlConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char current = (char) data;
result += current;
data = reader.read();
}
return result;
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView myLV = (ListView)findViewById(R.id.teamLV);
ArrayList<String> clubName = new ArrayList<String>();
DownloadTask task = new DownloadTask();
String result = null;
try {
result = task.execute("https://www.premierleague.com/clubs").get();
//Log.i("Content of URL", result);
System.out.println(result);
Pattern p = Pattern.compile("class=\"clubName\">(.*?)<");
Matcher m = p.matcher(result);
while(m.find()){
System.out.println(m.group(1));
clubName.add(m.group(1));
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_activated_1, clubName);
myLV.setAdapter(arrayAdapter);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
try adding onPostExecute after doInBackground. then remove the part from execute.get(). The get method makes the UI blocking (which kinda makes the asynctask pointless).
also preset your adapter instead of creating a new one each time you do a loop. you might need a custom adapter (depending on what you need).
#Override
protected void onPostExecute(String result) {
//Log.i("Content of URL", result);
System.out.println(result);
Pattern p = Pattern.compile("class=\"clubName\">(.*?)<");
Matcher m = p.matcher(result);
while(m.find()){
System.out.println(m.group(1));
// clubName.add(m.group(1));
adapter.add (m.group(1));
}
}

Can I use AsyncTask inside ListFragment? or should I use AsyncTaskLoader?

I tried the code below and also tried the AsyncTaskLoader approach. The app crashes when I instantiate the AsyncTask. Pleas advise me on the best approach to load JSON in a list fragment inside tab host.
The code below is the tab fragment (I use action bar tabs in main activity):
public class TabTop extends ListFragment {
Context context = getActivity().getBaseContext();
String API_URL = "http://api.rottentomatoes.com/api/public/v1.0/movies/770672122/similar.json?apikey=crhhxb4accwwa6cy6fxrm8vj&limit=1";
ArrayList<Deal> deals;
DealsListAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
#SuppressWarnings("unused")
int a = 0;
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
GetTopDeals getTopDeals = new GetTopDeals(context);
getTopDeals.execute(API_URL);
super.onActivityCreated(savedInstanceState);
}
class GetTopDeals extends AsyncTask<String, Void, ArrayList<Deal>>{
ProgressDialog progressDialog;
public GetTopDeals(Context activity) {
this.progressDialog = new ProgressDialog(activity);
}
#Override
protected void onPostExecute(ArrayList<Deal> result) {
adapter = new DealsListAdapter(context, result);
setListAdapter(adapter);
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
progressDialog.setCancelable(true);
progressDialog.setProgress(0);
progressDialog.setMessage("loading Top deals...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
super.onPreExecute();
}
#Override
protected ArrayList<Deal> doInBackground(String... urls) {
String response = sendRequest(urls[0]); // make request for json
return processResponse(response); // parse the Json and return ArrayList to postExecute
}
private String sendRequest(String apiUrl) {
BufferedReader input = null; // get the json
HttpURLConnection httpCon = null; // the http connection object
StringBuilder response = new StringBuilder(); // hold all the data from the jason in string separated with "\n"
try {
URL url = new URL(apiUrl);
httpCon = (HttpURLConnection) url.openConnection();
if (httpCon.getResponseCode() != HttpURLConnection.HTTP_OK) { // check for connectivity with server
return null;
}
input = new BufferedReader(new InputStreamReader(httpCon.getInputStream())); // pull all the json from the site
String line;
while ((line = input.readLine()) != null) {
response.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (httpCon != null) {
httpCon.disconnect();
}
}
return response.toString();
}
}
public ArrayList<Deal> processResponse(String response) {
try {
JSONObject responseObject = new JSONObject(response); // Creates a new JSONObject with name/value mappings from the JSON string.
JSONArray results = responseObject.getJSONArray("movies"); // Returns the value mapped by name if it exists and is a JSONArray.
deals = new ArrayList<Deal>();
for (int i = 0; i < results.length(); i++) { // in this loop i copy the json array to movies arraylist in order to display listView
JSONObject jMovie = results.getJSONObject(i);
int api_id = jMovie.getInt("id");
String name = jMovie.getString("title");
String content = jMovie.getString("synopsis");
JSONObject posters = jMovie.getJSONObject("posters");
String image_url = posters.getString("profile");
}
}catch (JSONException e) {
e.printStackTrace();
}
return deals;
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Intent intent = new Intent(getActivity().getBaseContext(), DealInformation.class);
startActivity(intent);
super.onListItemClick(l, v, position, id);
}
}
Make your asynctask in his own file.
And when your asynctask is finish, implement OnPostExecute which is automatically call. Notify your adapter by a notifyDataSetChanged like that :
#Override
protected void onPostExecute(List<NewItem> list) {
Adapter.getListe().clear();
Adapter.getListe().addAll(list);
Adapter.notifyDataSetChanged();
}
thank you guys,
i want to post my answer. after some research i decided to go with AsyncTaskLoader.
this is my code
public class TabOurPicks extends ListFragment implements LoaderCallbacks<String[]> {
// when activity loads- onActivityCreated() calls the initLoader() who activate onCreateLoader()
#Override
public void onActivityCreated(Bundle savedInstance) {
super.onActivityCreated(savedInstance);
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, new String[]{}));
getLoaderManager().initLoader(0, null,this).forceLoad();
}
// onCreateLoader instantiate the asynctaskloaser who work in bg
#Override
public RSSLoader onCreateLoader(int arg0, Bundle arg1) {
return new RSSLoader(getActivity()); //
}
// after bg process invoke onLoadFinished() who work in ui thread
#Override
public void onLoadFinished(Loader<String[]> loader, String[] data) {
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, data
) );
}
#Override
public void onLoaderReset(Loader<String[]> arg0) {
// TODO Auto-generated method stub
}
and this is the inner class for the loader:
static public class RSSLoader extends AsyncTaskLoader<String[]>
{
public RSSLoader(Context context) {
super(context);
}
#Override
public String[] loadInBackground() {
String url = "http://api.rottentomatoes.com/api/public/v1.0/movies/770672122/similar.json?apikey=crhhxb4accwwa6cy6fxrm8vj&limit=1";
String response = sendRequest(url);
return processResponse(response);
}
private String sendRequest(String url) {
BufferedReader input = null; // get the json
HttpURLConnection httpCon = null; // the http connection object
StringBuilder response = new StringBuilder(); // hold all the data from the jason in string separated with "\n"
try {
URL apiUrl = new URL(url);
httpCon = (HttpURLConnection) apiUrl.openConnection();
if (httpCon.getResponseCode() != HttpURLConnection.HTTP_OK) { // check for connectivity with server
return null;
}
input = new BufferedReader(new InputStreamReader(httpCon.getInputStream())); // pull all the json from the site
String line;
while ((line = input.readLine()) != null) {
response.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (httpCon != null) {
httpCon.disconnect();
}
}
return response.toString();
}
private String[] processResponse(String response) {
String[] deals = null;
try {
JSONObject responseObject = new JSONObject(response); // Creates a new JSONObject with name/value mappings from the JSON string.
JSONArray results = responseObject.getJSONArray("movies"); // Returns the value mapped by name if it exists and is a JSONArray.
deals = new String[10];
for (int i = 0; i < 9; i++) { // in this loop i copy the json array to movies arraylist in order to display listView
JSONObject jMovie = results.getJSONObject(i);
String name = jMovie.getString("title");
deals[i] = name;
}
}catch (JSONException e) {
e.printStackTrace();
}
return deals;
}
}
}
It doesn't matter if your asynctask has its own file. You just don't want your activity to extends asynctask as this would make your activity asynchronous - but this is impossible to do anyways due to java's double inheritance rule.
Based on the architecture of your app and your programming style the asyntask can be an inner class in the activity. on the PostExecute method make sure you have given data to your adapter and that the adapter is set to the list, then just run notifyDataSetChanged().
Assuming your asynctask is loading data from cache or the network you are on the right track with your approach to this.

Categories

Resources