0

I've been trying to get my ListView to populate with images from a website URL that is known by the adapter. The activity inflates each image, but my emulator won't even start, and just displays black. I've searched fruitlessly throughout my code, and have tried many things, but unfortunately, I am now stuck. First class is my Adapter Class which provides a View for every index Second class is my Activity Class which loads the views. Third class is a helper class.

There are also two layout XML files and an XML manifest

GalleryAdapter.java

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

import com.example.imageshow.R;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;


public class GalleryAdapter extends ArrayAdapter<JSONObject>{
    DrawableManager dM = new DrawableManager();
    Server s = new Server();
    Context ctx;
    LayoutInflater myInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    public GalleryAdapter(Context context, int resource) {
        super(context, resource);
        ctx = context;
        // TODO Auto-generated constructor stub
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        if (convertView==null){
            convertView = myInflater.inflate(R.layout.gallery_item, parent, true);
        }
        TextView name = (TextView) convertView.findViewById(R.id.name);
        name.setText(s.galleryObjects.get(position).getName());
        TextView eventDate = (TextView) convertView.findViewById(R.id.eventDate);
        eventDate.setText(s.galleryObjects.get(position).getEventDate());
        ImageView image = (ImageView) convertView.findViewById(R.id.image);
        String imageUrl = s.galleryObjects.get(position).getImageURL();

        //which one works??
        //1
        image.setImageDrawable(dM.fetchDrawable(imageUrl));
        //2
        try {
              image = (ImageView) convertView.findViewById(R.id.image);
              Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL(imageUrl).getContent());
              image.setImageBitmap(bitmap); 
            } catch (MalformedURLException e) {
              e.printStackTrace();
            } catch (IOException e) {
              e.printStackTrace();
            }
        //3
        //new DownloadImageTask(image).execute(s.galleryObjects.get(position).getImageURL());
        return convertView;
    }



    public static Bitmap getBitmapFromURL(String src) {
        try {
            Log.e("src",src);
            URL url = new URL(src);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.connect();
            InputStream input = connection.getInputStream();
            Bitmap myBitmap = BitmapFactory.decodeStream(input);
            Log.e("Bitmap","returned");
            return myBitmap;
        } catch (IOException e) {
            e.printStackTrace();
            Log.e("Exception",e.getMessage());
            return null;
        }
    }

    class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
        ImageView bmImage;

        public DownloadImageTask(ImageView bmImage) {
            this.bmImage = bmImage;
        }

        protected Bitmap doInBackground(String... urls) {
            String urldisplay = urls[0];
            Bitmap mIcon11 = null;
            try {
                InputStream in = new java.net.URL(urldisplay).openStream();
                mIcon11 = BitmapFactory.decodeStream(in);
            } catch (Exception e) {
                Log.e("Error", e.getMessage());
                e.printStackTrace();
            }
            return mIcon11;
        }

        protected void onPostExecute(Bitmap result) {
            bmImage.setImageBitmap(result);
        }
    }

}

GalleryActivity.java

import com.example.imageshow.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.ListView;

public class GalleryActivity extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        GalleryAdapter p = new GalleryAdapter(this,0);
        setContentView(R.layout.galleries);
        ListView l = (ListView) findViewById(R.id.galleryList);
        ImageView moreButton = (ImageView) findViewById(R.id.moreButton);
        ImageView cameraButton = (ImageView) findViewById(R.id.cameraButton);
        moreButton.setOnClickListener(new MoreButtonListener());
        cameraButton.setOnClickListener(new CameraButtonListener());
        l.setAdapter(p);
        setVisible(true);
    }

    public class MoreButtonListener implements OnClickListener{

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub

        }

    }

    public class CameraButtonListener implements OnClickListener{

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub

        }

    }
}

DrawableManager.Java

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ImageView;

public class DrawableManager {
    private final Map<String, Drawable> drawableMap;

    public DrawableManager() {
        drawableMap = new HashMap<String, Drawable>();
    }

    public Drawable fetchDrawable(String urlString) {
        if (drawableMap.containsKey(urlString)) {
            return drawableMap.get(urlString);
        }

        try {
            InputStream is = fetch(urlString);
            Drawable drawable = Drawable.createFromStream(is, "src");


            if (drawable != null) {
                drawableMap.put(urlString, drawable);
                Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
                        + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
                        + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
            } else {
              Log.w(this.getClass().getSimpleName(), "could not get thumbnail");
            }

            return drawable;
        } catch (MalformedURLException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        } catch (IOException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        }
    }

    public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
        if (drawableMap.containsKey(urlString)) {
            imageView.setImageDrawable(drawableMap.get(urlString));
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageView.setImageDrawable((Drawable) message.obj);
            }
        };

        Thread thread = new Thread() {
            @Override
            public void run() {
                //TODO : set imageView to a "pending" image
                Drawable drawable = fetchDrawable(urlString);
                Message message = handler.obtainMessage(1, drawable);
                handler.sendMessage(message);
            }
        };
        thread.start();
    }

    private InputStream fetch(String urlString) throws MalformedURLException, IOException {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpGet request = new HttpGet(urlString);
        HttpResponse response = httpClient.execute(request);
        return response.getEntity().getContent();
    }
}

Layout file

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#fbfbfb" >
            <ImageView
                android:id = "@+id/cameraButton"
                android:layout_height="wrap_content"
                android:layout_width = "wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:clickable = "true"
                android:adjustViewBounds="true"
                android:padding="10dp"
                android:maxHeight="400dp"
                android:src="@drawable/ic_launcher"
                android:background="#b9b9b9">
            </ImageView>
            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:clickable="false"
                android:maxHeight="400dp"
                android:text="SPORTSPHOTOS.com"
                android:textColor="#123123" >
            </TextView>
            <ImageView
                android:id = "@+id/moreButton"
                android:layout_height="wrap_content"
                android:layout_width = "wrap_content"
                android:layout_alignParentRight="true"
                android:adjustViewBounds="true"
                android:clickable="true"
                android:padding="10dp"
                android:maxHeight="60dp"
                android:layout_centerVertical="true"
                android:src="@drawable/more"
                >
            </ImageView>
        </RelativeLayout>
        <ScrollView
            android:layout_width = "fill_parent"
            android:layout_height="fill_parent">

            <ListView
                android:id="@+id/galleryList"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" >
            </ListView>

        </ScrollView>


    </LinearLayout>

</LinearLayout>

Layout file

<?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="match_parent" >

    <LinearLayout
        android:layout_width = "match_parent"
        android:layout_height = "wrap_content"
        android:padding="20dp"
        android:orientation="vertical"
    >

    <TextView
        android:id="@+id/name"
        android:text="Great Wall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="2dp">
    </TextView>

    <TextView
        android:id="@+id/eventDate"
        android:text="08-15-2014"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="2dp">

    </TextView>

    <LinearLayout 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="10dp">

        <ImageView
            android:id="@+id/image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:maxHeight="200dp"
            android:padding="10dp">  
        </ImageView>

    </LinearLayout>

    </LinearLayout>

</RelativeLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.imageshow"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-permission android:name="android.permission.INTERNET" />

    <uses-sdk
        android:minSdkVersion="18"
        android:targetSdkVersion="21" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.SECOND" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity
            android:name=".GalleryActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
  • Are you getting any error on logcat ? – Alok Nair Aug 07 '14 at 06:26
  • Yes, but I don't know what any of them mean. I did change true to false on getView() in the first class though. – Joseph Bao Aug 07 '14 at 06:40
  • Post your logcat error along with question – Alok Nair Aug 07 '14 at 06:51
  • 2
    why don't u try some image loader library like [Android-Universal-Image-Loader](https://github.com/nostra13/Android-Universal-Image-Loader) or [LazyList](https://github.com/thest1/LazyList) or [picasso](http://square.github.io/picasso/) – Kaushik Aug 07 '14 at 07:10
  • Thanks, I'll try again with suggest solutions and post an update. – Joseph Bao Aug 07 '14 at 14:39
  • *Comment from [Smartphone Developer](http://stackoverflow.com/users/3132094/smartphone-developer):* it seems like you are just setting an adapter in oncreate of your GalleryActivity class but what you are not doing is notify adapter after getting images.. do something like `adapter.notifyDataSetChanged();` after completing Asynctask – Artjom B. Aug 12 '14 at 10:28

2 Answers2

0

I think none of the solutions will work. Make sure the loading of the image via http is in the background (which is not is solution 2). The main problem with loading images in the background within a listview is the View Recycling (How ListView's recycling mechanism works). When a view is reused the image you are loading should not be set to the initial imageView. As your view is recycled another image should be loaded in the imageView. Therefor keep track of the relation between and imageView and the url. (for example by putting the url in the imageView.setTag(url)) Just before setting the image to the imageView check whether the imageView.getTag() matches the url you just loaded.

However to make it a bit easier I always use AndroidQuery. Asynchronous loading an image from the network only takes two lines:

//load an image to an ImageView from network, cache image to file and memory
AQuery aq = new AQuery(convertView);
aq.id(R.id.image).image("http://www.vikispot.com/z/images/vikispot/android-w.png");

See https://code.google.com/p/android-query/wiki/ImageLoading for more options. (like caching etc)

Community
  • 1
  • 1
userM1433372
  • 5,345
  • 35
  • 38
0

When implementing your own ImageLoader, try to use a cache to store bitmaps so that it will not download images always. Hard download of image in the getView() method of adapter is not encouraged.

or

Try to use a Image Loading Library like Picasso, UIL etc. These libraries will handle image caching, disk caching for you.

santoshavss
  • 221
  • 1
  • 6