Android: Display image in imageview by SimpleAdapter
Asked Answered
B

7

5

I am new android now I want to display image from an url. I am using imageview in listview. I want to add the list of images into the each row of the list item. I used SimpleAdapter but the imageview shows blank.

Here's the main activity:

package com.example.mysqltest;

    import java.util.ArrayList;
    import java.util.HashMap;
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    import android.app.ListActivity;
    import android.app.ProgressDialog;
    import android.content.Intent;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.AdapterView.OnItemClickListener;
    import android.widget.ListAdapter;
    import android.widget.ListView;
    import android.widget.SimpleAdapter;

    public class ReadComments extends ListActivity {

        // Progress Dialog
        private ProgressDialog pDialog;

        // testing on Emulator:
        private static final String READ_COMMENTS_URL = "http://192.168.30.198/test/webservice/comments.php";


        // JSON IDS:
        private static final String TAG_SUCCESS = "success";
        private static final String TAG_TITLE = "title";
        private static final String TAG_POSTS = "posts";
        private static final String TAG_POST_ID = "post_id";
        private static final String TAG_USERNAME = "username";
        private static final String TAG_MESSAGE = "message";
        private static final String TAG_IMAGE = "image";


        // An array of all of our comments
        private JSONArray mComments = null;
        // manages all of our comments in a list.
        private ArrayList<HashMap<String, String>> mCommentList;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // note that use read_comments.xml instead of our single_post.xml
            setContentView(R.layout.read_comments);
        }

        @Override
        protected void onResume() {
            // TODO Auto-generated method stub
            super.onResume();
            // loading the comments via AsyncTask
            new LoadComments().execute();
        }

        public void addComment(View v) {
            Intent i = new Intent(ReadComments.this, AddComment.class);
            startActivity(i);
        }

        /**
         * Retrieves recent post data from the server.
         */
        public void updateJSONdata() {
            mCommentList = new ArrayList<HashMap<String, String>>();

            JSONParser jParser = new JSONParser();      
            JSONObject json = jParser.getJSONFromUrl(READ_COMMENTS_URL);

            try {
                mComments = json.getJSONArray(TAG_POSTS);

                for (int i = 0; i < mComments.length(); i++) {
                    JSONObject c = mComments.getJSONObject(i);

                    // gets the content of each tag
                    String title = c.getString(TAG_TITLE);
                    String content = c.getString(TAG_MESSAGE);
                    String username = c.getString(TAG_USERNAME);
                    String image = c.getString(TAG_IMAGE);

                    // creating new HashMap
                    HashMap<String, String> map = new HashMap<String, String>();

                    map.put(TAG_TITLE, title);
                    map.put(TAG_MESSAGE, content);
                    map.put(TAG_USERNAME, username);
                    map.put(TAG_IMAGE, image);

                    // adding HashList to ArrayList
                    mCommentList.add(map);
                }

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

        /**
         * Inserts the parsed data into the listview.
         */
        private void updateList() { 
            ListAdapter adapter = new SimpleAdapter(this, mCommentList,
                    R.layout.single_post, new String[] { TAG_TITLE, TAG_MESSAGE,
                            TAG_USERNAME,TAG_IMAGE }, new int[] { R.id.title, R.id.message,
                            R.id.username, R.id.imageView1 });

            // I shouldn't have to comment on this one:
            setListAdapter(adapter);    

            ListView lv = getListView();    
            lv.setOnItemClickListener(new OnItemClickListener() {

                @Override
                public void onItemClick(AdapterView<?> parent, View view,
                        int position, long id) {}
            });
        }

        public class LoadComments extends AsyncTask<Void, Void, Boolean> {

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                pDialog = new ProgressDialog(ReadComments.this);
                pDialog.setMessage("Loading Comments...");
                pDialog.setIndeterminate(false);
                pDialog.setCancelable(true);
                pDialog.show();
            }

            @Override
            protected Boolean doInBackground(Void... arg0) {
                updateJSONdata();
                return null;

            }

            @Override
            protected void onPostExecute(Boolean result) {
                super.onPostExecute(result);
                pDialog.dismiss();
                updateList();
            }
        }
    }
Barge answered 2/6, 2014 at 0:17 Comment(3)
SimpleAdapter.setViewImage works with system resources, not with network resources. You need to download the network image and set the bitmap explicitly to the ImageView. You can try this answer.Hellkite
Thanks for your comment. could you help me how to apply setViewImage in my code?Barge
Hello @VuthySok U there?Inwards
L
12

Okay. So I assume here that you insist on using SimpleAdapter. No probem, problem solved, just follow the steps:

First lets create our custom row.xml for our ListView which will consist of only one ImageView.(You can add whatever you like to it later on but now i'll assume that you only wanna load the ImageView)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="5dp"
        android:src="@drawable/ic_launcher" />


</RelativeLayout>

Second lets create our custom SimpleAdapter

package com.example.helpstack;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.SimpleAdapter;

public class MySimpleAdapter extends SimpleAdapter {
    private Context mContext;
    public LayoutInflater inflater = null;

    public MySimpleAdapter(Context context,
            List<? extends Map<String, ?>> data, int resource, String[] from,
            int[] to) {
        super(context, data, resource, from, to);
        mContext = context;
        inflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View vi = convertView;
        if (convertView == null)
            vi = inflater.inflate(R.layout.row, null);

        HashMap<String, Object> data = (HashMap<String, Object>) getItem(position);

        new DownloadTask((ImageView) vi.findViewById(R.id.imageView1))
                .execute((String) data.get("uri"));

        return vi;
    }

}

Third lets create our DownloadTask, this class will download the image:

package com.example.helpstack;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;

public class DownloadTask extends AsyncTask<String, Void, Boolean> {
    ImageView v;
    String url;
    Bitmap bm;

    public DownloadTask(ImageView v) {
        this.v = v;
    }

    @Override
    protected Boolean doInBackground(String... params) {
        url = params[0];
        bm = loadBitmap(url);
        return true;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        v.setImageBitmap(bm);
    }

    public static Bitmap loadBitmap(String url) {
        try {
            URL newurl = new URL(url);
            Bitmap b = BitmapFactory.decodeStream(newurl.openConnection()
                    .getInputStream());
            return b;
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

Now the DownloadTask is being used from inside the getView() in SimpleAdapter

Fourth lets run our amazing small project from our MainActivity.java

package com.example.helpstack;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;

public class MainActivity extends Activity {
    ListView lv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) findViewById(R.id.listView1);
        List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("uri",
                "http://upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Wiktionary_small.svg/350px-Wiktionary_small.svg.png");
        //here u can add as many uri as u want
        data.add(map);
        MySimpleAdapter adapter = new MySimpleAdapter(MainActivity.this, data,
                R.layout.row, new String[] {}, new int[] {});
        lv.setAdapter(adapter);
    }
}
Lemures answered 6/6, 2014 at 22:51 Comment(4)
I did follow your code but always close app when i runBarge
Did you add the internet permission in the manifest file ? It shouldn't close. Try to add the permission, if it doesn't work i'll send you my sample. But I suggest you tell us what are the errors occuring in logcatLemures
yes I did add permission <uses-permission android:name="android.permission.INTERNET"/>. I am not sure the problem but I open app always show message "Unfortunately, My SimpleAdapter has stopped".Barge
This is the project shared: docs.google.com/…Lemures
S
3

You can use any image cache library. Example, Picasa, Universal Image Loader..

You can cache the images from the URL and then you can use the images in your app.

You can find the libraries in the following links

http://square.github.io/picasso/ and https://github.com/nostra13/Android-Universal-Image-Loader

Senatorial answered 10/6, 2014 at 12:16 Comment(0)
T
2

You can use multiple thread to download and decode bitmap .please follow this website and try to learn how android Developer use thread pool executer to execute different image in thread. http://developer.android.com/training/multiple-threads/create-threadpool.html

Topo answered 9/6, 2014 at 10:0 Comment(0)
M
2

1) To set the image Uri to the ImageView you can use a ViewBinder
You have to implement the abstract class and override setViewValue

2) You can use Picasso to load the images in a background thread and cache them. The setViewValue method would look like this:

boolean setViewValue (View view, Object data, String textRepresentation) {
  if(view.getId() == R.id.imageView1) {
    Picasso.with(view.getContext()).load(textRepresentation).into((ImageView) view);
    return true;
  }
  return false;
}

You return true if you want to take care of the binding. You return false for the default behavior.

3) Set your adapter to use the ViewBinder by calling adapter.setViewBinder(ViewBinder);

Marmolada answered 10/6, 2014 at 19:33 Comment(0)
S
1

for now, my suggestion for you is:
1. download the image from url
2. save it as drawable in the storage
3. set this drawable to the image src of imageview
(I didn't see you do this part of job from your code...)

Sherillsherilyn answered 2/6, 2014 at 0:36 Comment(0)
C
1

I suggest you use Universal Image Loader, it uses asynchronous image downloading, caching and displaying, there you can find examples how to implement it. After you do it you dont have to concern about the number of images, or its size.

If you download the project you will find this example that does all the work you want:

/**
 * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
 */
public class ImageListActivity extends AbsListViewBaseActivity {

    DisplayImageOptions options;

    String[] imageUrls;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ac_image_list);

            // here you get a String array with images URL
        Bundle bundle = getIntent().getExtras();
        imageUrls = bundle.getStringArray(Extra.IMAGES);

        options = new DisplayImageOptions.Builder()
            .showImageOnLoading(R.drawable.ic_stub)
            .showImageForEmptyUri(R.drawable.ic_empty)
            .showImageOnFail(R.drawable.ic_error)
            .cacheInMemory(true)
            .cacheOnDisc(true)
            .considerExifParams(true)
            .displayer(new RoundedBitmapDisplayer(20))
            .build();

        listView = (ListView) findViewById(android.R.id.list);
        ((ListView) listView).setAdapter(new ItemAdapter());
        listView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                startImagePagerActivity(position);
            }
        });
    }

    @Override
    public void onBackPressed() {
        AnimateFirstDisplayListener.displayedImages.clear();
        super.onBackPressed();
    }
    // it gets the position of listView and opens that image in a new Activity
    private void startImagePagerActivity(int position) {
        Intent intent = new Intent(this, ImagePagerActivity.class);
        intent.putExtra(Extra.IMAGES, imageUrls);
        intent.putExtra(Extra.IMAGE_POSITION, position);
        startActivity(intent);
    }

    class ItemAdapter extends BaseAdapter {

        private ImageLoadingListener animateFirstListener = new AnimateFirstDisplayListener();

        private class ViewHolder {
            public TextView text;
            public ImageView image;
        }

        @Override
        public int getCount() {
            return imageUrls.length;
        }

        @Override
        public Object getItem(int position) {
            return position;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            View view = convertView;
            final ViewHolder holder;
            if (convertView == null) {
                view = getLayoutInflater().inflate(R.layout.item_list_image, parent, false);
                holder = new ViewHolder();
                holder.text = (TextView) view.findViewById(R.id.text);
                holder.image = (ImageView) view.findViewById(R.id.image);
                view.setTag(holder);
            } else {
                holder = (ViewHolder) view.getTag();
            }

            holder.text.setText("Item " + (position + 1));
                    // here is the place where is loaded the image using Universal ImageLoader , imageUrls[position] is a list of images URL
            imageLoader.displayImage(imageUrls[position], holder.image, options, animateFirstListener);

            return view;
        }
    }

    private static class AnimateFirstDisplayListener extends SimpleImageLoadingListener {

        static final List<String> displayedImages = Collections.synchronizedList(new LinkedList<String>());

        @Override
        public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
            if (loadedImage != null) {
                ImageView imageView = (ImageView) view;
                boolean firstDisplay = !displayedImages.contains(imageUri);
                if (firstDisplay) {
                    FadeInBitmapDisplayer.animate(imageView, 500);
                    displayedImages.add(imageUri);
                }
            }
        }
    }
}
Camarena answered 6/6, 2014 at 22:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.