Fastest way to parse JSON - android

I have an app that loads data from a JSON URL, but it takes about 8 seconds to load and I believe this is because of parsing.
I want to know if is there a faster way to parse it faster and easier?
This is the function I am using to read the JSON:
public class LoadJson extends AsyncTask <String, Void, String> {
#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);
}
String finalJson = buffer.toString();
return finalJson;
} catch (Exception e) {
e.printStackTrace();
return "Faild";
}
}
}
and:
public JSONArray ExcuteLoad() {
LoadJson task = new LoadJson();
String resualt = null;
try {
resualt = task.execute("MY_JSON_FILE_URL").get();
JSONObject json = new JSONObject(resualt);
JSONArray jarray = json.getJSONArray("marcadores");
return jarray;
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
UPDATE 1:
Ok folks i change the code base on what you suggested about using onPostExecute but the problem is i can't return the value of jsonarray outside of asyncTask, got really confused....
public class LoadJson extends AsyncTask <String, Void, String> {
public class LoadJson extends AsyncTask <String, Void, String> {
public interface AsyncResponse {
void processFinish(String output);
}
public AsyncResponse delegate = null;
public LoadJson (AsyncResponse delegate){
this.delegate = delegate;
}
#Override
protected String doInBackground(String... params) {
String resualt = "";
URL url;
HttpURLConnection urlConnection = null;
try {
url = new URL(params[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;
resualt += current;
data = reader.read();
}
return resualt;
}
catch (Exception e) {
e.printStackTrace();
return "Failed";
}
}
#Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
}
and My Fragment class:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
LoadJson asyncTask = (LoadJson) new LoadJson (new LoadJson.AsyncResponse(){
#Override
public void processFinish(String output){
//Here you will receive the result fired from async class
//of onPostExecute(result) method.
try {
JSONObject jsonObject = new JSONObject(output);
JSONArray jsonArray = jsonObject.getJSONArray("marcadores");
} catch (JSONException e) {
e.printStackTrace();
}
}
}).execute();

Your problem isn't parsing the JSON. You can't speed that up. Using a different library (probably) isn't going to make that faster either. (I'm talking about load times, not development time).
It comes down to how you make the request as well as your internet speed.
For example, this is not how you use an AsyncTask.
resualt = task.execute("MY_JSON_FILE_URL").get();
Because you just made an asynchronous call into a synchronous one. In other words, the get() method will block and wait for a result, therefore taking time and cause the data to load slowly.
Now, sure, libraries reduce the complexity of AsyncTask and make development "faster and easier", but the quick answer here is to actually use onPostExecute of the AsyncTask class to load the data asynchronously, off the main thread.
The best example I can give is Using a callback to return the data
Update
private JSONArray array;
private void parseJSON(JSONArray array) {
this.array = array;
// TODO: something
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
LoadJson asyncTask = (LoadJson) new LoadJson (new LoadJson.AsyncResponse(){
#Override
public void processFinish(String output){
//Here you will receive the result fired from async class
//of onPostExecute(result) method.
try {
JSONObject jsonObject = new JSONObject(output);
JSONArray jsonArray = jsonObject.getJSONArray("marcadores");
for (int i = 0; i < jsonArray.length; i++) {
// TODO: Parse the array, fill an arraylist
}
// TODO: Set / notify an adapter
// Or....
parseJSON(jsonArray);
} catch (JSONException e) {
e.printStackTrace();
}
}
}).execute();

Related

How to Update recyclerView items after doInBackground

I'm using recyclerView in my app in which I'm calculating the route distance between the cities in other thread than UI thread. Now I want to refresh the recyclerView's distance field only whenever the distance is calculated.
TIA
public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.ListItemViewHolder> {
private List<DashBoardData> dashBoardData;
private Context context;
public DashboardAdapter(List<DashBoardData> dashBoardData, Context context) {
if (dashBoardData == null) {
throw new IllegalArgumentException("Data must not be null");
}
this.dashBoardData = dashBoardData;
this.context = context;
}
#NonNull
#Override
public ListItemViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_layout, viewGroup, false);
return new ListItemViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ListItemViewHolder holder, int position) {
holder.tvSource.setText(dashBoardData.get(position).getSource());
holder.tvDestination.setText(dashBoardData.get(position).getDestination());
getDistance(context,
dashBoardData.get(position).getStartLocation(),
dashBoardData.get(position).getEndLocation());
holder.tvDistance.setText("");
}
#Override
public int getItemCount() {
return dashBoardData.size();
}
public final static class ListItemViewHolder extends RecyclerView.ViewHolder {
TextView tvSource, tvDestination, tvDistance;
public ListItemViewHolder(View itemView) {
super(itemView);
tvSource = (TextView) itemView.findViewById(R.id.tv_from_source);
tvDestination = (TextView) itemView.findViewById(R.id.tv_to_destination);
tvDistance = itemView.findViewById(R.id.tv_distance);
}
}
public static void getDistance(Context context, String srcLocation, String destLocation) {
String url = getDirectionsUrl(context, srcLocation, destLocation);
DownloadTask downloadTask = new DownloadTask();
downloadTask.execute(url);
}
public static class DownloadTask extends AsyncTask<String, Void, String> {
// Downloading data in non-ui thread
#Override
protected String doInBackground(String... url) {
String data = "";
try {
// Fetching the data from web service
String urlEncoded = (url[0]).replaceAll(" ", "");
data = downloadUrl(urlEncoded);
} catch (Exception e) {
Log.d("Background Task", e.toString());
}
return data;
}
// Executes in UI thread, after the execution of
// doInBackground()
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
ParserTask parserTask = new ParserTask();
// Invokes the thread for parsing the JSON data
parserTask.execute(result);
}
}
private static String downloadUrl(String strUrl) throws IOException {
String data = "";
InputStream iStream = null;
HttpURLConnection urlConnection = null;
try {
URL url = new URL(strUrl);
urlConnection = (HttpURLConnection) url.openConnection();
// Connecting to url
urlConnection.connect();
// Reading data from url
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
StringBuffer sb = new StringBuffer();
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
data = sb.toString();
br.close();
} catch (Exception e) {
Log.d("Exception downloading url", e.toString());
} finally {
if (iStream != null) {
iStream.close();
}
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return data;
}
private static class ParserTask extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... jsonData) {
JSONObject jObject;
String distance = "0 Mt";
try {
jObject = new JSONObject(jsonData[0]);
JSONArray jRoutes = null;
JSONArray jLegs = null;
jRoutes = jObject.getJSONArray("routes");
for (int i = 0; i < jRoutes.length(); i++) {
jLegs = ((JSONObject) jRoutes.get(i)).getJSONArray("legs");
for (int j = 0; j < jLegs.length(); j++) {
distance = (String) ((JSONObject)((JSONObject) jLegs.get(j)).get("distance")).get("text");
}
}
} catch (Exception e) {
e.printStackTrace();
}
return distance;
}
#Override
protected void onPostExecute(String result) {
//update ui
}
}
}
this is my adapter and I'm passing a dashboard list to this. After parsing the json data for distance I want to notify the distance field in onPostExecute() method.
The easiest way of doing that is once you are done updating all your data you call notify dataset changed on your adapter something like this:
//Some Code
mAdapter.notifyDataSetChanged();
Where mAdapter is the reference for your RecyclerView Adapter.

JSON resolve from URL and post textview

how to resolve this json for Android Studio
and need each item is individually displayed in the textview
Thank you all....
url content only
{"s":true,"code":0,"errors":[],"c":"2.54","y":"5.8","i":"2.9","x":"0"}
My Someone Activity
public class aFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_a, null);
super.onCreate(savedInstanceState);
new TransTask()
.execute("MYURL");
return view;
}
class TransTask extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... params) {
StringBuilder sb = new StringBuilder();
try {
URL url = new URL(params[0]);
BufferedReader in = new BufferedReader(
new InputStreamReader(url.openStream()));
String line = in.readLine();
while(line!=null){
Log.d("HTTP", line);
sb.append(line);
line = in.readLine();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.d("JSON", s);
parseJSON(s);
}
private void parseJSON(String s) {
try{
JSONObject jsonObject = new JSONObject(s);
String name = jsonObject.getString("s");
String title = jsonObject.getString("code");
String tag = jsonObject.getString("errors");
String info = jsonObject.getString("c");
String info = jsonObject.getString("y");
String inf = jsonObject.getString("i");
String in = jsonObject.getString("x");
}
catch(JSONException e) {
e.printStackTrace();
}
}
why super.onPostExecute(s); cannot resolve method 'onPostExecute(java.lang.string)'
You could set the values for various widgets in the 'onPostExecute' method for your AsyncTask.
Initialize a JSONObject with the string returned. Then use the various methods like getBoolean, getString, getDouble, etc. for the values. You can even get nested json objects or arrays using getJSONObject and getJSONArray methods. Using JSONObject will require you to handle a JSONException in your code.
JSONObject jsonObject = new JSONObject(stringObject);
boolean s = jsonObject.getBoolean("s");
int code = jsonObject.getInt("code");
JSONArray errors = jsonObject.getJSONArray("errors");
//Similar to above
Alternately, you can also use a library like GSON to deserialize your json.

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));
}
}

get the value of AsyncTask method

i have create an android application on where the user can select the start and end point of the location.
This application will use the Google-Direction web service and make the HTTPRequest.
I will make this as short, I want to call the asynctask method in the JSONParser class from the main_activity.
The issue is, I don't know how to display the result in the main_activtiy method
here is the asynctask method
public class JSONParser {
InputStream is = null;
JSONObject jObj = null;
String json = "";
public JSONParser() {
}
public void getJSONFromUrl(final String url, final responseListener target) {
new AsyncTask<Void, Void, String>() {
protected String doInBackground(Void... params) {
HttpURLConnection httpURLConnection = null;
StringBuilder stringBuilder = new StringBuilder();
try {
httpURLConnection = (HttpURLConnection) new URL(url).openConnection();
InputStreamReader inputStreamReader = new InputStreamReader(httpURLConnection.getInputStream());
int read;
char[] buff = new char[1024];
while ((read = inputStreamReader.read(buff)) != -1) {
stringBuilder.append(buff, 0, read);
}
return stringBuilder.toString();
} catch (MalformedURLException localMalformedURLException) {
return "";
} catch (IOException localIOException) {
return "";
} finally {
if (httpURLConnection != null)
httpURLConnection.disconnect();
}
}
protected void onPostExecute(String result) {
super.onPostExecute(result);
target.onResponseComplete(result);
}
}.execute();
}
here is how the main method is calling the method
new JSONParser().getJSONFromUrl(url, new responseListener() {
#Override
public void onResponseComplete(String response) {
try {
ArrayList<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
JSONArray step = new JSONObject(response).getJSONArray("routes").getJSONObject(0).getJSONArray("legs")
.getJSONObject(0).getJSONArray("steps");
for (int i = 0; i < step.length(); i++) {
HashMap<String,Object> row = new HashMap<String,Object>();
row.put("Distance", step.getJSONObject(i).getJSONObject("distance").getString("text"));
list.add(row);
}
}catch (Exception e){
e.printStackTrace();
}
}
});
}
the issue right know is how i want to display the Arraylist List value and put it into the TextView call jarak
You can change your List to be
ArrayList<HashMap<String, String>>
as you are getting a string from
step.getJSONObject(i).getJSONObject("distance").getString("text")
To get it out you can use (assuming your textview is called jarak)
for(HashMap<String,String> map : list) {
for(Entry<String, String> entry : map.entrySet()) {
jarak.setText(entry.getKey() + ", " + entry.getValue());
}
}
Hope that helps

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