Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android

Alessandro Maculotti
Alessandro Maculotti
4,954 Points

Display an image on a ListView

Hi! I would try to modify the BlogReader App with an Image into the listView. I found this library "CWAC Adapter" by Mark Murphy that do this work. Do you think I should use this library or I should implement a custom view?

6 Answers

Implement a custom adapter. it's really simple! Where will you be getting the images from? I have a Github Project where I extend the Simple blog reader to pull down badges. I use a gridview but the adapter for each is the same. Here's the BadgeAdapter class!

Alessandro Maculotti
Alessandro Maculotti
4,954 Points

Oh Thanks! I would get the images from a http request in AsynkTask. So now I will try to implement your class. Thanks so much.

Picasso is a fantastic library. You give it the image URL and the imageview that you want the image in and it will lazy load it for you. It will even do local caching so you don't need to worry about any of that! No need to reinvent the wheel!

What adapter would I have to use if I wanted to have thumbnails beside the title and author using JSON?

Alessandro Maculotti
Alessandro Maculotti
4,954 Points

Implement a custom adapter

SimpleAdapter adapter = new SimpleAdapter(context, date, 
                        R.layout.custom_list, keys, ids);

Create an xml layout file: custom_list.xml like this:

<ImageView
            android:id="@+id/thumbRifugio"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_marginBottom="5dp"
            android:layout_marginRight="5dp"
            android:layout_marginTop="5dp"
            android:contentDescription="@string/alt"
            android:src="@drawable/segnaposto_thumb">
        </ImageView>

            <TextView
                android:id="@android:id/text1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceListItem" />

            <TextView
                android:id="@android:id/text2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceSmall" 
                />

so where in my main activity would I put the custom adapter?

public class MainListActivity extends ListActivity {

public static final int NUMBER_OF_POSTS = 20;
public static final String TAG = MainListActivity.class.getSimpleName();
protected JSONObject mBlogData;
protected ProgressBar mProgressBar;

private final String KEY_TITLE = "title";
private final String KEY_DATE = "date";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main_list);

    mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);

    if(NetworkIsAvailable())    {
        mProgressBar.setVisibility(View.VISIBLE);
        GetBlogPostsTask getBlogPostsTask = new GetBlogPostsTask();
        getBlogPostsTask.execute();
    }
    else {
        Toast.makeText(this, "Network is unavailable!", Toast.LENGTH_LONG).show();
    }

    //String message = getString(R.string.no_items);
    //Toast.makeText(this, message, Toast.LENGTH_LONG).show();

}

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);
    try {
    JSONArray jsonPosts = mBlogData.getJSONArray("posts");
    JSONObject jsonPost = jsonPosts.getJSONObject(position);
    String blogUrl = jsonPost.getString("url");

    Intent intent = new Intent(this,BlogWebViewActivity.class);
    intent.setData(Uri.parse(blogUrl));
    startActivity(intent);
}
    catch (JSONException e) {
        logException(e);
    }
}

private void logException(Exception e) {
    Log.e(TAG, "Exception caught!", e);
}

private boolean NetworkIsAvailable() {
    ConnectivityManager manager = (ConnectivityManager) 
            getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = manager.getActiveNetworkInfo();

    boolean isAvailable = false;
    if(networkInfo != null && networkInfo.isConnected()) {
        isAvailable = true;
    }
    return isAvailable;
}

public void handleBlogResponse() {
    mProgressBar.setVisibility(View.INVISIBLE);
    if (mBlogData == null) {
        updateDisplayForError();
    }
    else {
        try {
            JSONArray jsonPosts = mBlogData.getJSONArray("posts");
            ArrayList<HashMap<String, String>> blogPosts = new ArrayList<HashMap<String, String>>();
            for (int i = 0; i < jsonPosts.length(); i++) {
                JSONObject post = jsonPosts.getJSONObject(i);
                String title = post.getString(KEY_TITLE);
                title = Html.fromHtml(title).toString();
                String date = post.getString(KEY_DATE);
                date = Html.fromHtml(date).toString();

                HashMap<String, String> blogPost = new HashMap<String, String>();
                blogPost.put(KEY_TITLE, title);
                blogPost.put(KEY_DATE, date);

                blogPosts.add(blogPost);
            }
            String[] keys = { KEY_TITLE, KEY_DATE };
            int[] ids = { android.R.id.text1, android.R.id.text2 };
            SimpleAdapter adapter = new SimpleAdapter(this, blogPosts, android.R.layout.simple_list_item_2, keys, ids);
            setListAdapter(adapter);
        } catch (JSONException e) {
            logException(e);
        }
    }

}


private void updateDisplayForError() {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);    
    builder.setTitle(getString(R.string.error_title));
    builder.setMessage(getString(R.string.error_message));
    builder.setPositiveButton(android.R.string.ok, null);
    AlertDialog dialog = builder.create();
    dialog.show();

    TextView emptyTextView = (TextView) getListView().getEmptyView();
    emptyTextView.setText(getString(R.string.no_items));
}

private class GetBlogPostsTask extends AsyncTask<Object, Void, JSONObject> {

    @Override
    protected JSONObject doInBackground(Object... params) {
        int responseCode = -1;
        JSONObject jsonResponse = null;
        StringBuilder builder = new StringBuilder();
        HttpClient client = new DefaultHttpClient();
        HttpGet httpget = new HttpGet("http://www.ilovelimerick.ie/?json=1&count=");

        try {
            HttpResponse response = client.execute(httpget);
            StatusLine statusLine = response.getStatusLine();
            responseCode = statusLine.getStatusCode();

            if (responseCode == HttpURLConnection.HTTP_OK) {
                HttpEntity entity = response.getEntity();
                InputStream content = entity.getContent();
                BufferedReader reader = new BufferedReader(new InputStreamReader(content));
                String line;
                while((line = reader.readLine()) != null){
                    builder.append(line);
                }

                jsonResponse = new JSONObject(builder.toString());
            }
            else {
                Log.i(TAG, String.format("Unsuccessful HTTP response code: %d", responseCode));
            }
        }
        catch (JSONException e) {
            logException(e);
        }
        catch (Exception e) {
            logException(e);
        }           

        return jsonResponse;
    }   

    @Override
    protected void onPostExecute(JSONObject result) {
        mBlogData = result;
        handleBlogResponse();
    }

}

}

sorry but I am very new to this!

Ben Jakuben
STAFF
Ben Jakuben
Treehouse Teacher

We cover all this (including Picasso!) in the Build a Self-Destructing Message App project. I think it's stage 7 or so. Check it out! :-)