my app receive a jsonArray that have names of categories and their images urls.
so i want to extract the names and also download the image by they urls.
actually i succeed to extract the names and also the urls, look at the code bellow:
private class ReadPlacesFeedTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
return readJSONFeed(urls[0]);
}
protected void onPostExecute(String result) {
try {
JSONObject jsonobject = new JSONObject(result);
JSONArray categories = new JSONArray(
jsonobject.getString("categories"));
for (int i = 0; i < categories.length(); i++) {
JSONObject category = categories.getJSONObject(i);
names.add(category.getString("name"));
images.add(category.getString("image"));
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
getBaseContext(), R.layout.row_channel_layout,
R.id.channel_name, names);
channel_list = (ListView) findViewById(R.id.channel_list);
channel_list.setAdapter(adapter);
}
}
my questions:
1. is it ok to build the adapter in the onPostExecute method ?
2.should i write another a synctasck class to download the images?,or extract the urls in doInbackground method and after that download the images, and return both of the images and the names to onPostExecute method.
actually i try this and i think it is very slow because decoding the json in the background method is very slow !
3.how could i build the listView after downloading the names, then after downloading the images, i just modify it.
thank you
1: Typically yes, though your better to make the adapter then pass the values to it on the post execute then call adapter.NotifyDataSetChanged();
2: I recommend not reinventing the wheel and using the "fantastic" picasso image loading library
http://square.github.io/picasso/
3: Create one listview, pass the names and urls to it, make the array adapter into your own custom e.g. "myListAdapter" which then sets the name value and then using picasso download and load the image into your imageview or whatever else you want to do with it.
http://www.vogella.com/tutorials/AndroidListView/article.html#adapterown_custom
E.g.
public class MainActivity extends Activity
{
ArrayList<String> myListItems = new ArrayList<String>();
ArrayAdapter<String> adapter;
#Override
protected void onCreate(Bundle savedInstanceState)
{
adapter = new ArrayAdapter(this,R.layout.row_category_layout,R.id.category_name, names);
//execute my data task
}
public void dataTask()
{
//GOT SOME DATA
myListItems.add("MYDATA");
adapter.notifyDataSetChanged();
}
Related
I am pretty new with the concept of asynctask and i have an asynctask that gets me a json from an api with parameter an then(postexecute) puts the content inside textviews to be shown(they are set visible after setting the text), the thing is i am trying to validate that the json isnt actually empty, and with my code i actually do that, but if the parameter i use is correct, the validation still detects that its empty, if i try to get it again(by pressing the button that triggers the asynctask) after 2 or three tries it will actually get it tho, i think its because i am doing it on the background, here is the asynctask
private class ConsultarDatos extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
// params comes from the execute() call: params[0] is the url.
try {
return downloadUrl(urls[0]);
} catch (IOException e) {
return "Unable to retrieve web page. URL may be invalid.";
}
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(String result) {
JSONArray ja = null;
try {
ja = new JSONArray(result);
txtNombre.setText(ja.getString(0) +" " + ja.getString(1));
txtCategoria.setText(ja.getString(2));
txtDNI.setText(ja.getString(3));
txtEstado.setText(ja.getString(4));
//working=false;
} catch (JSONException e) {
e.printStackTrace();
}
}
}
and here is what i am trying to do
btnGenerar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new ConsultarDatos().execute("https://api-adress/file.php?DNI=" + etDNI.getText().toString());
//while(working)
//{
//}
if (txtCategoria.getText()!="") {
btnGenerar.setVisibility(View.INVISIBLE);
etDNI.setVisibility(View.INVISIBLE);
txtCategoria.setVisibility(View.VISIBLE);
txtDNI.setVisibility(View.VISIBLE);
txtEstado.setVisibility(View.VISIBLE);
txtNombre.setVisibility(View.VISIBLE);
imgTarjeta.setVisibility(View.VISIBLE);
}
else
{
Toast.makeText(getApplicationContext(),"DNI Incorrecto",Toast.LENGTH_LONG).show();
}
}
});
as i commented i tried to do a while that would wait until the textsviews are all set but that just crashed my app
I resolved it, just moved the the visibility set and validation to the end of the onPostExecute and just to be sure i put the toast in the exception too just so the user gets some feedback
protected void onPostExecute(String result) {
JSONArray ja = null;
try {
ja = new JSONArray(result);
txtNombre.setText(ja.getString(0) +" " + ja.getString(1));
txtCategoria.setText(ja.getString(2));
txtDNI.setText(ja.getString(3));
txtEstado.setText(ja.getString(4));
if (txtCategoria.getText()!="") {
btnGenerar.setVisibility(View.INVISIBLE);
etDNI.setVisibility(View.INVISIBLE);
txtCategoria.setVisibility(View.VISIBLE);
txtDNI.setVisibility(View.VISIBLE);
txtEstado.setVisibility(View.VISIBLE);
txtNombre.setVisibility(View.VISIBLE);
imgTarjeta.setVisibility(View.VISIBLE);
}
else
{
Toast.makeText(getApplicationContext(),"DNI Incorrecto",Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),"DNI Incorrecto",Toast.LENGTH_LONG).show();
}
}
Use something like https://www.getpostman.com/ to see what the result of your API call is. Right now it seems like you don't know what you're getting back, and how consistently it comes back. You need to validate that your server is sending you back valid data.
Using a json library to parse the JSON response, such as GSON or Moshi would help you out as well. Right now you're trying to get the values based on arbitrary numbers. You could be having an exception from just one field missing, but there's not enough info to tell. Gson is fairly easy to set up in my experience: https://github.com/google/gson
i have generated an app over e-commerce site (magento 2) while i am trying to startup my app it processing very slowly because of many products in my server is there any possible way to speed up my usage of Async task while using JSON feeds.. Please let me for any possible ways
My one of the AsyncTask coding:
private class GetProduct extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Showing progress dialog
dialog_pro = new ProgressDialog(Healthy_Cat.this);
dialog_pro.setMessage("Please wait...");
dialog_pro.setCancelable(false);
dialog_pro.show();
}
#Override
protected Void doInBackground(Void... arg0) {
HttpHandler sh = new HttpHandler();
String jsonStr = sh.makeServiceCall(url);
if (jsonStr != null) {
try {
JSONArray items = new JSONArray(jsonStr);
for (int i = 0; i < items.length(); i++) {
JSONObject c = items.getJSONObject(i);
pro_name = c.getString("name");
String price = c.getString("price");
JSONArray array = c.getJSONArray("custom_attributes");
for (int k = 0; k < array.length(); k++) {
JSONObject jb = array.getJSONObject(k);
String attr = jb.getString("attribute_code");
if (attr.equalsIgnoreCase("special_price")) {
splprice = jb.getString("value");
}
}
String sku = c.getString("sku");
JSONArray media = c.getJSONArray("media_gallery_entries");
for(int k = 0; k < media.length(); k++) {
JSONObject jb = media.getJSONObject(k);
String imageURL = BaseURL_Helper.MediaBase +jb.getString("file");
media_image = imageURL;
// tmp hash map for single contact
Beanclass dataSet = new Beanclass();
dataSet.setTitle(pro_name);
dataSet.setImage(imageURL);
dataSet.setPrice(price);
dataSet.setSPLPrice(splprice);
dataSet.setSku(sku);
list.add(dataSet);
BeanclassList data = new BeanclassList();
data.setTitle(pro_name);
data.setImage(imageURL);
data.setSku(sku);
data.setSPLPrice(splprice);
data.setPrice(price);
listbean.add(data);
}
}
}catch (final JSONException e) {
runOnUiThread(new Runnable() {
#Override
public void run() {
no_list.setVisibility(View.VISIBLE);
}
});
}
} else {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(),
"May be Network error!!",
Toast.LENGTH_LONG)
.show();
}
});
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// Dismiss the progress dialog
/**
* Updating parsed JSON data into ListView
* */
if (dialog_pro.isShowing())
dialog_pro.dismiss();
mAdapter = new GridviewAdapter(Healthy_Cat.this,list);
gridlist.setAdapter(mAdapter);
Listadapter = new ListviewAdapter(Healthy_Cat.this,listbean);
listview_pro.setAdapter(Listadapter);
}
}
Thank u in advance..
There are few things you need to update in your code
API Calling lib: I'm using Retrofit for api calling very fast & simple to use. Support Header & Response caching too.
JSON Parsing: You are parsing JSON manually which is a time-consuming process. I'm using Google's JSON parsing Lib Gson. really very fast.
Pagination: If you having lots of data on the server then try to fetch data in small no of pieces. For example in case of "Item Listing API" try to fetch data from the server for 10-15 item at a time rather all the item at a once.
Asyntask performance speed is too low compare to Retrofit.
So For e-commerce app, You must use Retrofit.
There are a few things you can do. For starters, you don't have to parse the whole json, before updating view.
But really you yourself state the issue, which is you have too much data. This is not only a programming issue, it is also a user experience issue, too much data is confusing, especially on a mobile device.
What I suggest is breaking down your data into categories or the like. When app starts, download just a list of categories to display. Upon user choosing a category, then you download the data for that category.
When you download data, do it in chunks, so that you can start displaying right away.
There are many similar ideas that you can implement, for a better user experience.
I use Jsoup to parse HTML page and I want to show text and images in the ListView. So I created LinkedHashMap and SimpleAdapter for this. Besides text shows as is. Images don't wan't to be shown. Every time I get log message such as: "resolve Uri failed on bad bitmap uri". I tried to google this problem but still can't resolve it.
Here is the code:
#Override
protected String doInBackground(String... arg) {
Document doc;
try {
doc = Jsoup.connect("http://thesiteiuse.com/news/").get();
title = doc.select("h2[class=et_pt_title]");
picture = doc.select("img");
listViewContent.clear();
for (Element titles : title) {
Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put(ATTRIBUTE_NAME_TEXT, titles.text());
listViewContent.add(map);
}
for (Element img : picture){
Bitmap bitmap;
Map<String,Object> picMap = new LinkedHashMap<String,Object>();
String iurl;
iurl = img.absUrl("src");
Log.w("ABSurl:", iurl.toString());
URL url = new URL(iurl);
bitmap = BitmapFactory.decodeStream(url.openStream());
Log.w("BITMAP",bitmap.toString());
picMap.put(ATTRIBUTE_NAME_IMAGE, String.valueOf(bitmap));
listViewContent.add(picMap);
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
How can I solve my problem? Maybe is there another simple way to display images in the ListView which app get from the URL?
You have to create your own adapter to the listview. You should see this tutorial on how to create it: http://www.vogella.com/tutorials/AndroidListView/article.html
I first make an async task to retrieve JSON data. One of the JSON objects retrieved is an URL.
// This goes on my asynctask to get JSON data from the server
#Override
public void onPostExecute(JSONObject json) {
try {
String title = json.getString("title");
String description = json.getString("description");
String url = json.getString("url");
// Here comes the tricky part
Bitmap bitmap = Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888);
new DownloadBitmap(bitmap).execute(url);
myArrayList.add(new DataContainer(title,description,bitmap));
// End of the tricky part
}catch(Exception e) {}
adapter.NotifyDataSetChange();
}
OK as you can see I need a reference of bitmap to send to the downloader class and to the arraylist for the listview's adapter.
The problem is that the downloader class goes like this:
class DownloadBitmap extends AsyncTask<the 3 paramateres goes here>{
Bitmap bitmap;
public DownloadBitmap(Bitmap b) {
//Here I have a reference to the SAME bitmap object I added to the arraylist
bitmap = b;
}
#Override
protected void doInBackground(String... Params) {
// some code.....
// THIS IS THE PROBLEM, it re-initialize.
bitmap = BitmapFactory.decodeStream(inputstream);
}
I wasn't able to find any other way around, and If possible I'd like a solution library independant, my company has strict policy over software dependance.
You can use Universal Image Loader Library.
link
Below is my code and I get the data from the webservice(remote server) in the doinbackground(). I want to set the data on the UI. Everything works fine. But as I have huge amount of data to be retrieved from the server, the progress bar is showing for a long time. So, I decided to use something like CW endlesss adapter or according to this. It's been giving me grief for few days by now.
1) CW endless adapter: I face a lot of problems in including it as a library project and when I try to run demos, it always shows me ! symbol in red color. When I click on run, it says your project has errors, but there is not even a single clue where does that error occur. Even I am unable to understand the things that have to be done too as those are somewhat difficult for me as a beginner. So, I decided to follow as per the other.
2) In this, I am unable to get on how to use this in my scenario as I am getting the data as a whole after completion of the doInBackground().
Can someone help me on this with relevant code snippets? I would be very thankful for your help.
I am calling this asynctask in onCreate() method.
class LoadAllData extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(GetData.this);
pDialog.setMessage("Loading Data. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
/**
* getting All Data from url
* */
protected String doInBackground(String... args) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("datatobefetched", datadetails));
// getting JSON string from URL
JSONObject json = jParser.makeHttpRequest(url_all_ads, "POST", params);
Log.d("All Products: ", json.toString());
try {
// Checking for SUCCESS TAG
int check = json.getInt(CHECK);
if (Check == 1) {
// Data found
// Getting Array of Data
dataJsonArray = json.getJSONArray("totaldata");
// looping through All data
for (int i = 0; i < dataJsonArray.length(); i++) {
JSONObject jobj = dataJsonArray.getJSONObject(i);
// Storing each json item in variable
String id = jobj.getString("rowid");
String product = jobj.getString("data1");
String review = c.getString("data2");
String imagepath = c.getString("image_url");
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
// adding each child node to HashMap key => value
map.put("id", id);
map.put("product", product);
map.put("review", review);
map.put("imageurl", imagepath);
// adding map to ArrayList
productsList.add(map); // ProductList is arrayList.
}
}
else {
// no data found
}
}
catch (JSONException e) {
e.printStackTrace();
}
return null;
}
/**
* After completing background task Dismissing the progress dialog
* **/
protected void onPostExecute(String file_url) {
// dismiss the dialog after getting all products
pDialog.dismiss();
// updating UI from Background Thread
runOnUiThread(new Runnable() {
public void run() {
// Updating parsed JSON data into ListView
// Getting adapter by passing xml data ArrayList
ListView list = (ListView)findViewById(R.id.list);
adapter = new CustomListAdapter(GetAllAds.this, productsList, passedcategory);
list.setAdapter(adapter);
}
});
}
}
with the code you posted there doesn't seem to have anything that would be taking an awful a lot of time.
I don't believe making an endless list (either using the endless adapter or manually) is the case for you because apparently the web-server you're communicating with does not have the options for page (e.g. when on the URL you specific items per page and page number like this: ?per_page=20&page_no=1) and those type of list only makes sense for such.
Just as a simple test, put those lines before after your code:
long now = System.currentTimeMillis();
JSONObject json = jParser.makeHttpRequest(url_all_ads, "POST", params);
Log.d("Test", "Elapsed time is: " + Long.toString(System.currentTimeMillis() - now));
then you can check on your LogCat how long did it took to make the http request.
edit:
suggested alternative to HashMap<> as I don't believe they are very efficient ways of storing data.
public class MyData(){
JSONObject data;
public MyData(JSONObject data){ this.data=data; }
public String getId(){ return data.getString("rowid"); }
// repeat for the other info you need, also override the toString to return the data.toString();
}
that way all the JSON parsing will be done at a later point in time and in small batches and your for loop would be as simple as:
for (int i = 0; i < dataJsonArray.length(); i++) {
productList.add(new MyData(dataJsonArray.getJSONObject(i));
}