CM Woo
CM Woo

Reputation: 23

The image order go wrong after downloaded with bitmap in android

i wish to display my data and image which download from an URL but after i download the image from URL, the order of the image go wrong. I displayed my data and images using card view and recycle view, but the first image in first card go to second, while the second image at third card and the third one will missing and the first one will empty. Anyone can help me on this?

Below is my code. Tq

SimpleCardViewAdapter.java

public class SimpleCardViewAdapter extends RecyclerView.Adapter<SimpleCardViewAdapter.ViewHolder> {

private List<CardViewData> mDataset;
Bitmap downloadedBitmap;
ImageView row_image;

public SimpleCardViewAdapter(List<CardViewData> dataset) {
    mDataset = dataset;
}

@Override
public ViewHolder onCreateViewHolder(final ViewGroup viewGroup, int i) {
    View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_layout, viewGroup, false);
    return new ViewHolder(v);
}

@Override
public void onBindViewHolder(final ViewHolder viewHolder, int i) {
    final CardViewData cardViewData = mDataset.get(i);

    viewHolder.mTitle.setText(cardViewData.getTitle());
    viewHolder.mDescription.setText(cardViewData.getDescription());
    String var = cardViewData.getImage();

    new Thread(new getImageTask(var)).start();
    viewHolder.mImage.setImageBitmap(downloadedBitmap);

    viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(v.getContext(), "Title: " + cardViewData.getTitle(), Toast.LENGTH_SHORT).show();
        }
    });
}

class getImageTask implements Runnable {

    String imageUrl;

    getImageTask(String imgUrl){
        imageUrl = imgUrl;
    }

    @Override
    public void run() {
        try {
            URL url = new URL(imageUrl);
            downloadedBitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Message msg = new Message();
        Bundle b = new Bundle();
        b.putString("mfeApi", "1");
        msg.setData(b);
        handlerGroupedProductsImage.sendMessage(msg);
    }

}

Handler handlerGroupedProductsImage = new Handler() {
    public void handleMessage(Message msg) {
        Bundle b = msg.getData();
        String done = b.getString("mfeApi");
    };
};



@Override
public int getItemCount() {
    return mDataset == null ? 0 : mDataset.size();
}

public static class ViewHolder extends RecyclerView.ViewHolder {

    public TextView mTitle;
    public TextView mDescription;
    public ImageView mImage;

    public ViewHolder(View itemView) {
        super(itemView);

        mTitle = (TextView) itemView.findViewById(R.id.row_title);
        mDescription = (TextView) itemView.findViewById(R.id.row_description);
        mImage = (ImageView) itemView.findViewById(R.id.row_image);
    }
}

Activity.java

private void getData() {

    try {

        final String toSend = "http://www.test.com.my/test/api/kipcard_helpAPI.php";

        new Thread(new Runnable() {
            @Override
            public void run() {
                URL url = null;
                HttpURLConnection conn = null;
                String receivedString = null;
                try {
                    url = new URL(toSend);
                    conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("POST");
                    InputStream in = new BufferedInputStream(conn.getInputStream());
                    receivedString = IOUtils.toString(in, "UTF-8");
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                Message msg = new Message();
                Bundle b = new Bundle();
                b.putString("mfeApi", receivedString);
                msg.setData(b);
                hGet.sendMessage(msg);
            }
        }).start();

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

}



Handler hGet = new Handler() {
    public void handleMessage(Message msg) {
        Bundle b = msg.getData();
        String s = b.getString("mfeApi");

        items =  s.split("\\|\\|");
        size = items.length;

        List <CardViewData> list =  new ArrayList<CardViewData>();
        for(int i = 0 ; i <= size-3 ; i+=3){
            Log.d("here",items[i] +"" );
            //new Thread(new getImageTask(imahr)).start();
            list.add(new CardViewData(items[i+2], items[i+3], items[i+1]));
        }
        mAdapter = new SimpleCardViewAdapter(list);

        mRecyclerView.setAdapter(mAdapter);
    };
};

Upvotes: 0

Views: 80

Answers (3)

xAqweRx
xAqweRx

Reputation: 1236

Instead of

new Thread(new getImageTask(var)).start();
viewHolder.mImage.setImageBitmap(downloadedBitmap);

Try using

 final int position = i;
 viewHolder.position = i;
 new AsyncTask<Object, Void, Bitmap>() {
        private AlbumViewHolder v;

        @Override
        protected Bitmap doInBackground( Object[] params ) {
            v = (AlbumViewHolder) params[ 0 ];
            // download here your image
            return b;
        }

        @Override
        protected void onPostExecute( Bitmap result ) {
            super.onPostExecute( result );
            if ( v.position == position && result != null ) {
                // If this item hasn't been recycled already, hide the
                // progress and set and show the image
                    v.mImageView.setImageBitmap( result );
                    v.mImageView.setVisibility( View.VISIBLE );
                    v.mProgressBar.setVisibility( View.GONE );
            }
        }
    }.execute( viewHolder );

and in ViewHolder :

public static class ViewHolder extends RecyclerView.ViewHolder {

    public TextView mTitle;
    public TextView mDescription;
    public ImageView mImage;
    public int position;

    public ViewHolder(View itemView) {
        super(itemView);

        mTitle = (TextView) itemView.findViewById(R.id.row_title);
        mDescription = (TextView) itemView.findViewById(R.id.row_description);
        mImage = (ImageView) itemView.findViewById(R.id.row_image);
    }
}

And one more thing - your ViewHolder should have position parameter. And think about caching.

Upvotes: 1

Lalit Pratap Singh
Lalit Pratap Singh

Reputation: 175

Try this: add Context to your constructor

public SimpleCardViewAdapter(List<CardViewData> dataset, Activity activity){
   this.mActivity = activity;
}

change in onBindViewHolder method:

 new Thread(new getImageTask(var, viewHolder.mImage)).start();

and change your task like this:

    class getImageTask implements Runnable {

        String imageUrl;
        ImageView imageView

        getImageTask(String imgUrl, ImageView imageView){
            imageUrl = imgUrl;
            this.imageView = imageView;
        }

        @Override
        public void run() {
            try {

                URL url = new URL(imageUrl);
                //change this line also
                Bitmap bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
                //set you downloaded image now...
                //new change ....

                mActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                       //Your code to run in GUI thread here
                       if(bitmap != null)
                       imageView.setImageBitmap(bitmap);
                    }
                });


            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            Message msg = new Message();
            Bundle b = new Bundle();
            b.putString("mfeApi", "1");
            msg.setData(b);
            handlerGroupedProductsImage.sendMessage(msg);
        }

    }

***but it will not cache bitmap, every time you scroll your recycler inside app it will download it again and again.

Upvotes: 0

csenga
csenga

Reputation: 4114

The problem is here:

   new Thread(new getImageTask(var)).start();
   viewHolder.mImage.setImageBitmap(downloadedBitmap);

As the thread do it's job parallel not synchronously downloadedBitmap can hold another's thread "old" result.

Upvotes: 1

Related Questions