0

I am learning android and my code is working fine. It fetches data from website and displays it in list. but when subcat==1 it has 9 items to fetch. It displays 7 distinct item and repeats two items. first it was showing only four that was NullPointerException 5th image didn't had name so it repeated 4 image till 9 times, but now everything is fine still it shows only 7 and repeates 2 after that. Here is my code:

public class JSONAsyncTask extends AsyncTask<String, Void, Void> {
    ProgressDialog pd;
    Context context;


    JSONAsyncTask(Context context) {
        this.context = context;
    }

    @Override
    protected void onPreExecute() {

        super.onPreExecute();
        pd = new ProgressDialog(context);
        pd.setIndeterminate(true);
        pd.setCancelable(false);
        pd.setCanceledOnTouchOutside(false);
        pd.setMessage("Please wait..\nLoading data");
        pd.show();
    }

    @Override
    protected Void doInBackground(String... strings) {
        ArrayList<item> jsonArrayList = new ArrayList<item>();
        try {
            HttpClient client = new DefaultHttpClient();
            HttpGet httpget = new HttpGet("http://avdeal.in/get_all_products.php");
            HttpResponse response = client.execute(httpget);
            HttpEntity entity = response.getEntity();
            String data = EntityUtils.toString(entity);
            JSONObject jsonObject = new JSONObject(data);
            if (jsonObject != null) {
                String posts = jsonObject.getString("products");
                JSONArray postsArray = new JSONArray(posts);
                if (postsArray != null) {
                    if (postsArray.length() > 0) {
                        for (int i = 0; i < postsArray.length(); i++) {
                            JSONObject postsObject = postsArray
                                    .getJSONObject(i);
                            int subcat = postsObject.getInt("subcat_id");

                            if (subcats == subcat) {
                                int id=postsObject.getInt("id");
                                String title = postsObject.getString("product_title");
                                String price = postsObject.getString("product_price");
                                String url = "http://avdeal.in/seller/upload_images/" + postsObject.getString("product_url");


                                list1.add(new item(id, title, price, url));
                            }

                        }
                    }


                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {

        super.onPostExecute(result);
        if (list1 != null) {
            pd.dismiss();
            adp = new actorAdapter(context, R.layout.listview, list1);
            lv.setAdapter(adp);
            adp.notifyDataSetChanged();
        }
        else {
            pd.setMessage("No internet access");
        }
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                Toast.makeText(itemView.this, "Please Wait " + i + 1, Toast.LENGTH_SHORT).show();
                int id1 = list1.get(i).getId();
                String name = list1.get(i).getName();
                String price = list1.get(i).getPrice();
                Bitmap bitmap = list1.get(i).getImage();

                if (bitmap == null) {
                    Intent intent = new Intent(context, productDetail.class);
                    intent.putExtra("name", name);
                    intent.putExtra("price", price);
                    intent.putExtra("id", id1);
                    intent.putExtra("imagena", 1);
                    startActivity(intent);
                } else {
                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
                    byte[] byteArray = stream.toByteArray();
                    Intent intent = new Intent(context, productDetail.class);
                    intent.putExtra("name", name);
                    intent.putExtra("price", price);
                    intent.putExtra("image", byteArray);
                    intent.putExtra("id", id1);
                    startActivity(intent);
                }
            }
        });
    }
}

private class ImageLoadTask extends AsyncTask<String, String, Bitmap>{
            Context context;
        ImageLoadTask(Context context) {
            this.context = context;
        }
        @Override
        protected Bitmap doInBackground(String... strings) {
            for(int i = 0 ; i < list1.size() ; i++)
            {
                if (list1.get(i).getImage()==null);
                {
                    String url=list1.get(i).getUrl();
                    InputStream is = null;
                    try {
                        is = (InputStream) new URL(url).getContent();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    Bitmap b = BitmapFactory.decodeStream(is);
                    list1.set(i, new item(list1.get(i).getId(), list1.get(i).getName(), list1.get(i).getPrice(), list1.get(i).getUrl() ,b));
                }
            }
                return null;

    }

        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);

        }
        protected void onPostExecute(Bitmap result){
                super.onPostExecute(result);
                adp = new actorAdapter(context, R.layout.listview, list1);
                lv.setAdapter(adp);
                adp.notifyDataSetChanged();
        }
    }

Can I do anything to lazy load image? I tried creating another AsyncTask, but it shows image when all the images are loaded.

Can I update my ListView as soon as one image is downloaded?

Please help. Can't figure out on my own. These two problems are stopping me from learning more.

public View getView(int position, View convertView, ViewGroup parent){
    inflater= (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
    View v =convertView;
    if (v == null) {

        holder=new ViewHolder();
        v=inflater.inflate(Resource,null);
        holder.name= (TextView) v.findViewById(R.id.titles);
        holder.price= (TextView) v.findViewById(R.id.price);
        holder.img= (ImageView) v.findViewById(R.id.itemimage);
        v.setTag(holder);
        holder.name.setText(list1.get(position).getName());
        holder.price.setText((CharSequence) list1.get(position).getPrice());
        holder.img.setImageBitmap(list1.get(position).getImage());



    }
    else {
        holder = (ViewHolder) v.getTag();
    }


    return v;
}
Artem Mostyaev
  • 3,874
  • 10
  • 53
  • 60
Shashank
  • 25
  • 6

3 Answers3

1

For the lazy image load, you need to create an AsyncTask for each image not an AsyncTask for all the images (dwonload them one by one in separated AsyncTasks).

I suggest you to use one of those libraries:

This is an opinon based comparison table between 4 libs (from here), it might help you to choose:

EDIT:

For your repeated items, change your getView method like that:

public View getView(int position, View convertView, ViewGroup parent){
    inflater= (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
    View v =convertView;
    if (v == null) {

        holder=new ViewHolder();
        v=inflater.inflate(Resource,null);
        holder.name= (TextView) v.findViewById(R.id.titles);
        holder.price= (TextView) v.findViewById(R.id.price);
        holder.img= (ImageView) v.findViewById(R.id.itemimage);
        v.setTag(holder);
    }
    else {
        holder = (ViewHolder) v.getTag();
    }

        holder.name.setText(list1.get(position).getName());
        holder.price.setText((CharSequence) list1.get(position).getPrice());
        holder.img.setImageBitmap(list1.get(position).getImage());    

    return v;
}

You forgot to update the item data when you use a recycled view (v != null).

Community
  • 1
  • 1
Rami
  • 7,879
  • 12
  • 36
  • 66
  • what about repeating list?? – Shashank Aug 21 '15 at 12:02
  • yeah thats working now. what about async task can you tell me how to call async for each image. when i am calling it from main thread. it force stops, i tried to keep the first async in main thread and call async for each image in another it does not load anything and catches exception. tell me how to implement without using third party library – Shashank Aug 24 '15 at 16:19
  • You should never download an image in main thread this will cause the ANR and your app will crash. It's better and easier to use libraries, because there is many optimisation behind... Otherwise in getView() method you need to start an AsyncTask for each item and pass the ImageView and the image URL as params. When the AsyncTask finish the download you have the image and the ImageView for the current item. – Rami Aug 24 '15 at 16:44
  • no i wanted to load rest of the data in main thread and then load the image in asynctask but i now understand it was due to strict mode. i think i am gonna have to use the library because optimisation is also an issue. which library you would recommend in all those? – Shashank Aug 24 '15 at 16:54
  • It's depends in what you need, they are almost equal... but personally im more familiar with Universal-Image-Loader. – Rami Aug 24 '15 at 17:03
0

Yes, it waits because your image loader async task loops over all bitmaps and downloads them then notify the list view to draw, you may make the async task loads only one image at a time. But I suggest you use an imageloader like Picasso or Glide.

Also in your adapter use the viewholder design pattern if you are not using it.

Ahmed Gamal
  • 338
  • 2
  • 7
  • i am using viewholder and it is working. i have set a default image from layout which is set if the image==null. first i need to tackle the repeating image then i will focus on efficiency and lazyloading – Shashank Aug 21 '15 at 13:24
0

Even though loading images in background after creating the list and refreshing it when loading it is better in terms of user experience that is not the problem you are facing.

I think the problem is with your getView method in your custom adapter, and if you provide it we would be able to know for sure. The problem is that you probably check if an image for an object at a position has a picture, and if so - set it. probably something like so:

public View getView (int position, View convertView, ViewGroup parent)
{
    //some code to create the views and view holder..

    YourItem currentItem = mItems.get(position);
    if (currentItem.getBitmap() != null)
    {

       imageView.setImageBitmap(currentItem.getBitmap());
    }

    //rest of code
}

What you should do is also add an else clause since the picture from the last created view is still populating that ImageView.Either change the ImageView's visibility or it's bitmap.

EDIT:
It should look something like this:

public View getView (int position, View convertView, ViewGroup parent)
{
    //some code to create the views and view holder..

    YourItem currentItem = mItems.get(position);
    if (currentItem.getBitmap() != null)
    {
       imageView.setVisibility(View.VISIBLE);
       imageView.setImageBitmap(currentItem.getBitmap());
    }
    else
    {
       imageView.setVisibility(View.INVISIBLE);
    }

    //rest of code
}
Shahar.bm
  • 169
  • 8
  • That is what bothering me. the code is correct and the logcat is showing only useless logs. no exception no errors. – Shashank Aug 21 '15 at 13:20
  • I don't think you got what i was saying. You NEED TO ADD an else clause and set the imageView visibility. see my edited message. – Shahar.bm Aug 21 '15 at 16:21