Android Open Source - singly-android Friends List Adapter






From Project

Back to project page singly-android.

License

The source code is released under:

MIT License

If you think the Android project singly-android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.singly.android.component;
/* w w w .j a v  a  2s  .  co m*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.JsonNode;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.singly.android.client.AsyncApiResponseHandler;
import com.singly.android.client.SinglyClient;
import com.singly.android.client.SinglyClient.Authentication;
import com.singly.android.sdk.R;
import com.singly.android.util.ImageCacheListener;
import com.singly.android.util.ImageInfo;
import com.singly.android.util.JSON;
import com.singly.android.util.RemoteImageCache;

/**
 * A {@link AbstractCachingBlockLoadedListAdapter} implementation customized
 * for use with the Singly Friends API.
 */
public class FriendsListAdapter
  extends AbstractCachingBlockLoadedListAdapter<Friend> {

  private LayoutInflater inflater;
  private Context context;
  private SinglyClient singlyClient;
  private String accessToken;
  private Bitmap defaultImage;
  private Map<Integer, String> sectionPositions;

  private boolean displaySectionHeaders = true;
  private boolean displayImages = true;
  private int defaultImageResource = R.drawable.friend_noimage;
  private RemoteImageCache remoteImageCache;

  private static class ViewHolder {
    TextView sectionHeader;
    ProgressBar progress;
    TextView name;
    ImageView image;
  }

  @Override
  protected void loadBlock(final int blockId, final int offset, final int limit) {

    // get the access token and query parameters
    Map<String, String> qparams = new HashMap<String, String>();
    qparams.put("access_token", accessToken);
    qparams.put("offset", String.valueOf(offset));
    qparams.put("limit", String.valueOf(limit));

    // we only need the toc on the first call
    qparams.put("toc", sectionPositions == null ? "true" : "false");

    // make a call to the api to get the block
    singlyClient.doGetApiRequest(context, "/friends/all", qparams,
      new AsyncApiResponseHandler() {

        @Override
        public void onSuccess(String response) {

          List<Friend> blockOfFriends = new ArrayList<Friend>();
          JsonNode root = JSON.parse(response);

          for (JsonNode node : root) {

            if (sectionPositions == null) {

              // create the section headers from the table of contents
              sectionPositions = Collections
                .synchronizedMap(new HashMap<Integer, String>());
              Map<String, JsonNode> tocFields = JSON.getFields(node);
              for (Map.Entry<String, JsonNode> tocField : tocFields.entrySet()) {
                String tocKey = tocField.getKey();
                JsonNode tocNode = tocField.getValue();
                if (!StringUtils.equals(tocKey, "meta")) {
                  sectionPositions.put(JSON.getInt(tocNode, "offset"),
                    StringUtils.upperCase(tocKey));
                }
              }
            }
            else {

              // parse the friend
              Friend friend = new Friend();
              friend.name = JSON.getString(node, "name");
              friend.imageUrl = JSON.getString(node, "thumbnail_url");
              friend.handle = JSON.getString(node, "handle");
              friend.description = JSON.getString(node, "description");
              friend.email = JSON.getString(node, "email");
              friend.phone = JSON.getString(node, "phone");

              // parse the friend services
              JsonNode servicesN = JSON.getJsonNode(node, "services");
              Map<String, JsonNode> serviceFields = JSON.getFields(servicesN);
              Map<String, Friend.Service> services = new LinkedHashMap<String, Friend.Service>();
              for (Map.Entry<String, JsonNode> entry : serviceFields.entrySet()) {
                Friend.Service service = new Friend.Service();
                service.id = JSON.getString(node, "id");
                service.entry = JSON.getString(node, "entry");
                service.url = JSON.getString(node, "url");
                services.put(entry.getKey(), service);
              }
              friend.services = services;

              // add friend to the block
              blockOfFriends.add(friend);
            }
          }

          // cache the block
          finishAndCacheBlock(blockId, blockOfFriends);
        }

        @Override
        public void onFailure(Throwable error, String message) {
          error.printStackTrace();
        }
      });
  }

  /**
   * Default constructor.
   * 
   * @param rows The number of total rows in this adapter, for this list.
   * @param blockSize The number of rows per block.  Total blocks will be the
   * number of rows / blockSize, plus 1 block if remainder.
   * @param blocksToPreload The number of blocks to preload when a single block
   * is loaded into the cache.  This supports smooth reverse and forward scroll.
   * If the blockSize is low the blocksToPreload should be greater.
   * @param blocksToCache The number of blocks to keep in memory.
   */
  public FriendsListAdapter(Context context, int rows, int blockSize,
    int blocksToPreload, int blocksToCache) {

    super(rows, blockSize, blocksToPreload, blocksToCache);
    this.context = context;
    this.inflater = (LayoutInflater)context
      .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    // get the singly client and access token
    this.singlyClient = SinglyClient.getInstance();
    Authentication auth = singlyClient.getAuthentication(context);
    this.accessToken = auth.accessToken;
  }

  @Override
  public View getView(int position, View row, ViewGroup parent) {

    // load any blocks for the current position
    loadBlocks(position);

    // view holder pattern
    ViewHolder viewHolder = null;
    if (row == null) {

      row = inflater.inflate(R.layout.singly_friends_row, parent, false);
      TextView sectionHeader = (TextView)row
        .findViewById(R.id.singlyFriendsRowSectionHeader);
      TextView friendNameView = (TextView)row
        .findViewById(R.id.singlyFriendsRowName);
      ProgressBar friendProgressView = (ProgressBar)row
        .findViewById(R.id.singlyFriendsRowProgress);
      ImageView friendImageView = (ImageView)row
        .findViewById(R.id.singlyFriendsRowImage);

      viewHolder = new ViewHolder();
      viewHolder.sectionHeader = sectionHeader;
      viewHolder.name = friendNameView;
      viewHolder.progress = friendProgressView;
      viewHolder.image = friendImageView;

      row.setTag(viewHolder);
    }
    else {
      viewHolder = (ViewHolder)row.getTag();
    }

    // set the section header if we have one
    viewHolder.sectionHeader.setVisibility(View.GONE);
    if (sectionPositions != null && sectionPositions.containsKey(position)) {
      viewHolder.sectionHeader.setVisibility(View.VISIBLE);
      viewHolder.sectionHeader.setText(sectionPositions.get(position));
    }

    // display the row or loading if the row isn't available yet
    viewHolder.name.setText("");
    viewHolder.image.setImageBitmap(null);
    Friend friend;

    // get the row object
    friend = getBackingObject(position);
    if (friend != null) {

      String friendName = friend.name;
      if (StringUtils.isNotBlank(friendName)) {
        viewHolder.progress.setVisibility(View.GONE);
        viewHolder.name.setText(friendName);
      }

      if (displayImages && remoteImageCache != null) {

        // populate the default image if needed
        if (defaultImage == null) {
          defaultImage = BitmapFactory.decodeResource(context.getResources(),
            defaultImageResource);
        }

        // make the image view visible
        viewHolder.image.setVisibility(View.VISIBLE);

        // setup the image to get or download, we want a 32x32 image
        ImageInfo imageInfo = new ImageInfo();
        String id = StringUtils.replace(friend.name, " ", "_");
        id = StringUtils.lowerCase(id);
        imageInfo.id = id;
        imageInfo.imageUrl = friend.imageUrl;
        imageInfo.width = 42;
        imageInfo.height = 42;
        imageInfo.format = Bitmap.CompressFormat.JPEG;
        imageInfo.quality = 80;
        imageInfo.sample = true;

        // setup a listener to just change the one image view instead of
        // calling
        // notifyDataSetChanged which redraws the entire list view screen
        final ListView mainListView = (ListView)parent;
        final int curPosition = position;

        // optimization to only change the single image in the single row
        // should the row still be visible when the image is done downloading
        // in the background
        imageInfo.listener = new ImageCacheListener() {

          @Override
          public void onSuccess(ImageInfo imageInfo, Bitmap bitmap) {

            // get the start and end visible rows in the list view
            int startRow = mainListView.getFirstVisiblePosition();
            int endRow = mainListView.getLastVisiblePosition();

            // if current position is visible get the specific row and change
            // just the image in that row. This will cause the image to update
            // on the fly even if no scrolling is happening. Nothing else in
            // the row will be invalidated
            if (curPosition >= startRow && curPosition <= endRow) {
              View rowView = mainListView.getChildAt(curPosition - startRow);
              ImageView imageView = (ImageView)rowView
                .findViewById(R.id.singlyFriendsRowImage);
              imageView.setImageBitmap(bitmap);
            }
          }

        };

        // get the friend image or the default
        Bitmap friendImage = remoteImageCache.getImage(imageInfo);
        if (friendImage == null) {
          friendImage = defaultImage;
        }
        viewHolder.image.setImageBitmap(friendImage);
      }
    }
    else {

      // loading friends, show loading text
      viewHolder.name.setText("Loading...");
      viewHolder.progress.setVisibility(View.VISIBLE);
    }

    return row;
  }

  public boolean isDisplaySectionHeaders() {
    return displaySectionHeaders;
  }

  public void setDisplaySectionHeaders(boolean displaySectionHeaders) {
    this.displaySectionHeaders = displaySectionHeaders;
  }

  public boolean isDisplayImages() {
    return displayImages;
  }

  public void setDisplayImages(boolean displayImages) {
    this.displayImages = displayImages;
  }

  public int getDefaultImageResource() {
    return defaultImageResource;
  }

  public void setDefaultImageResource(int defaultImageResource) {
    this.defaultImageResource = defaultImageResource;
  }

  public RemoteImageCache getRemoteImageCache() {
    return remoteImageCache;
  }

  public void setRemoteImageCache(RemoteImageCache remoteImageCache) {
    this.remoteImageCache = remoteImageCache;
  }

}




Java Source Code List

com.singly.android.client.AsyncApiResponseHandler.java
com.singly.android.client.AuthenticationActivity.java
com.singly.android.client.AuthenticationWebViewListener.java
com.singly.android.client.BaseAuthenticationWebViewClient.java
com.singly.android.client.FacebookAuthenticationActivity.java
com.singly.android.client.SinglyClient.java
com.singly.android.component.AbstractCachingBlockLoadedListAdapter.java
com.singly.android.component.AuthenticatedServicesActivity.java
com.singly.android.component.AuthenticatedServicesAdapter.java
com.singly.android.component.AuthenticatedServicesFragment.java
com.singly.android.component.DeviceOwnerActivity.java
com.singly.android.component.Friend.java
com.singly.android.component.FriendsListActivity.java
com.singly.android.component.FriendsListAdapter.java
com.singly.android.component.FriendsListFragment.java
com.singly.android.component.FriendsListRowClickListener.java
com.singly.android.component.SinglyService.java
com.singly.android.component.TableOfContentsFragment.java
com.singly.android.component.TableOfContentsTouchListener.java
com.singly.android.examples.MainActivity.java
com.singly.android.util.BitmapUtils.java
com.singly.android.util.ImageCacheListener.java
com.singly.android.util.ImageInfo.java
com.singly.android.util.JSON.java
com.singly.android.util.RemoteImageCache.java
com.singly.android.util.SinglyUtils.java
com.singly.android.util.URLUtils.java