Android Open Source - iPhoroidUI Endless Adapter






From Project

Back to project page iPhoroidUI.

License

The source code is released under:

Apache License

If you think the Android project iPhoroidUI 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

/*
 * Copyright (c) 2008-2009 CommonsWare, LLC
 * Portions (c) 2009 Google, Inc./*from  w  w w.  j  av a  2 s . c  o  m*/
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *  http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.klab.iphoroid.widget.listview;

import java.util.concurrent.atomic.AtomicBoolean;

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;


/**
 * Adapter that assists another adapter in appearing endless. For example, this
 * could be used for an adapter being filled by a set of Web service calls,
 * where each call returns a "page" of data.
 *
 * Subclasses need to be able to return, via getPendingView() a row that can
 * serve as both a placeholder while more data is being appended.
 *
 * The actual logic for loading new data should be done in appendInBackground().
 * This method, as the name suggests, is run in a background thread. It should
 * return true if there might be more data, false otherwise.
 *
 * If your situation is such that you will not know if there is more data until
 * you do some work (e.g., make another Web service call), it is up to you to do
 * something useful with that row returned by getPendingView() to let the user
 * know you are out of data, plus return false from that final call to
 * appendInBackground().
 */
abstract public class EndlessAdapter extends AdapterWrapper {

    abstract protected boolean cacheInBackground() throws Exception;

    abstract protected void appendCachedData();

    private View pendingView = null;

    private View dummyView = null;

    private AtomicBoolean keepOnAppending = new AtomicBoolean(true);

    private Context context;

    private int pendingResource = -1;

    /** */
    private int pagingSize;

    /**
     * Constructor wrapping a supplied ListAdapter
     */
    public EndlessAdapter(ListAdapter wrapped, int pagingSize) {
        super(wrapped);
        this.pagingSize = pagingSize;
    }

    /**
     * Constructor wrapping a supplied ListAdapter and providing a id for a
     * pending view.
     *
     * @param context
     * @param wrapped
     * @param pendingResource
     */
    public EndlessAdapter(Context context, ListAdapter wrapped, int pendingResource, int pagingSize) {
        super(wrapped);
        this.context = context;
        this.pendingResource = pendingResource;
        this.pagingSize = pagingSize;
    }

    /**
     * How many items are in the data set represented by this Adapter.
     */
    @Override
    public int getCount() {
        if (keepOnAppending.get()) {
            return super.getCount() + 1; // one more for "pending"
        }

        return super.getCount();
    }

    /**
     * Masks ViewType so the AdapterView replaces the "Pending" row when new
     * data is loaded.
     */
    public int getItemViewType(int position) {
        if (position == getWrappedAdapter().getCount()) {
            return IGNORE_ITEM_VIEW_TYPE;
        }

        return super.getItemViewType(position);
    }

    /**
     * Masks ViewType so the AdapterView replaces the "Pending" row when new
     * data is loaded.
     *
     * @see #getItemViewType(int)
     */
    public int getViewTypeCount() {
        return super.getViewTypeCount() + 1;
    }

    /**
     * Get a View that displays the data at the specified position in the data
     * set. In this case, if we are at the end of the list and we are still in
     * append mode, we ask for a pending view and return it, plus kick off the
     * background task to append more data to the wrapped adapter.
     *
     * @param position Position of the item whose data we want
     * @param convertView View to recycle, if not null
     * @param parent ViewGroup containing the returned View
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
Log.d("EndlessAdapter", "position: " + position + ", pagingSize: " + pagingSize + ", count: " + super.getCount());

    if (position == super.getCount() && keepOnAppending.get()) {
        // ????????????????????????????????????????????????
        if (dummyView == null) {
            dummyView = getDummyView(parent);
        }
        return dummyView;
    }
/*
        if (position == super.getCount() && keepOnAppending.get()) {
            if (position > pagingSize - 1) {
                if (pendingView == null) {
                    pendingView = getPendingView(parent);

                    new AppendTask().execute();
                }

                return pendingView;
            } else {
                // ????????????????????????????????????????????????
                if (dummyView == null) {
                    dummyView = getDummyView(parent);
                }
                return dummyView;
            }
        }
*/
        return super.getView(position, convertView, parent);
    }

    /**
     * Called if cacheInBackground() raises a runtime exception, to allow the UI
     * to deal with the exception on the main application thread.
     *
     * @param pendingView View representing the pending row
     * @param e Exception that was raised by cacheInBackground()
     * @return true if should allow retrying appending new data, false otherwise
     */
    protected boolean onException(View pendingView, Exception e) {
        Log.e("EndlessAdapter", "Exception in cacheInBackground()", e);

        return false;
    }

    /**
     * A background task that will be run when there is a need to append more
     * data. Mostly, this code delegates to the subclass, to append the data in
     * the background thread and rebind the pending view once that is done.
     */
    class AppendTask extends AsyncTask<Void, Void, Exception> {
        @Override
        protected Exception doInBackground(Void... params) {
            Exception result = null;

            try {
                keepOnAppending.set(cacheInBackground());
            } catch (Exception e) {
                result = e;
            }

            return result;
        }

        @Override
        protected void onPostExecute(Exception e) {
            if (e == null) {
                appendCachedData();
            } else {
                keepOnAppending.set(onException(pendingView, e));
            }

            pendingView = null;
            notifyDataSetChanged();
        }
    }

    /**
     * Inflates pending view using the pendingResource ID passed into the
     * constructor
     *
     * @param parent
     * @return inflated pending view, or null if the context passed into the
     *         pending view constructor was null.
     */
    protected View getPendingView(ViewGroup parent) {
        if (context != null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            return inflater.inflate(pendingResource, parent, false);
        }

        throw new RuntimeException("You must either override getPendingView() or supply a pending View resource via the constructor");
    }

    /**
     * ???????????????????????????????????
     * ??????????????????????????????????? View
     */
    protected abstract View getDummyView(ViewGroup parent);

    /**
     * Getter method for the Context being held by the adapter
     *
     * @return Context
     */
    protected Context getContext() {
        return context;
    }
}




Java Source Code List

org.klab.iphoroid.util.ActivityUtil.java
org.klab.iphoroid.util.Cache.java
org.klab.iphoroid.widget.adpterview.OnScrollListener.java
org.klab.iphoroid.widget.coverflow.CoverFlowGallery.java
org.klab.iphoroid.widget.coverflow.CoverFlowImageAdapterBase.java
org.klab.iphoroid.widget.flowview.CircleFlowIndicator.java
org.klab.iphoroid.widget.flowview.FlowIndicator.java
org.klab.iphoroid.widget.flowview.FlowView.java
org.klab.iphoroid.widget.flowview.TitleFlowIndicator.java
org.klab.iphoroid.widget.flowview.TitleProvider.java
org.klab.iphoroid.widget.gallery.ScrollDetectableGallery.java
org.klab.iphoroid.widget.listview.AdapterWrapper.java
org.klab.iphoroid.widget.listview.EndlessAdapter.java
org.klab.iphoroid.widget.listview.PullToRefreshEndlessListView.java
org.klab.iphoroid.widget.listview.PullToRefreshListView.java
org.klab.iphoroid.widget.listview.RefreshableArrayAdapter.java
org.klab.iphoroid.widget.support.DownloadTask.java
org.klab.iphoroid.widget.support.HasImage.java
org.klab.iphoroid.widget.support.ImageCache.java
org.klab.iphoroid.widget.support.ImageDownloadTask.java
org.klab.iphoroid.widget.support.SimpleImageDownloadTask.java