Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ListView onScroll add more items

    private class getArticles extends AsyncTask<Void, Void, Void> {

    String url;

    getArticles(String paramUrl) {
        this.url = paramUrl;
    }


    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        mProgressDialog = new ProgressDialog(App.this);
        mProgressDialog.setMessage("Učitavanje artikala...");
        mProgressDialog.setIndeterminate(false);
        mProgressDialog.setCancelable(false);
        mProgressDialog.show();
    }

    @Override
    protected Void doInBackground(Void... params) {

        arraylist = new ArrayList<>();

        try {

            Document document = Jsoup.connect(url).get();
            Elements els = document.select("ul.category3 > li");

            for (Element el : els) {

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

                Elements slika = el.select("div.category3-image > a > img");
                Elements naslov = el.select("div.category3-text > a.main-headline");
                Element datum_noformat = el.select("div.category3-text > div.headlines-info > ul.headlines-info > li").first();
                Element datum = datum_noformat.html(datum_noformat.html().replaceAll("Posted ", ""));
                Elements desc = el.select("div.category3-text > p");
                Elements link = el.select("div.category3-text > a.main-headline");
                Element br_kom = el.select("div.category3-text > div.headlines-info > ul.headlines-info > li.comments-icon").first();

                map.put("naslov", naslov.text());
                map.put("datum", datum.text());
                map.put("desc", desc.text());
                map.put("ikona", slika.attr("src"));
                map.put("link", link.attr("abs:href"));
                map.put("brkom", br_kom.text());
                arraylist.add(map);


            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        listview = (ListView) findViewById(R.id.listview);
        adapter = new ArtikliAdapter(App.this, arraylist);
        listview.setAdapter(adapter);
        mProgressDialog.dismiss();
    }

I searched for a lot of codes for onlistview scrolling, but didn't know how to implement it. The problem is, when I call my asynctask, I have an url param, like new getArticles("http://example.com").execute();

I want to implement an onscrolllistener, but it goes like this, my param is usually set to: http://www.example.com/category/categoryname/, so the second page goes like http://www.example.com/category/categoryname/page/2/, the third one goes http://www.example.com/category/categoryname/page/3/ and so on. Each page has got 7 items that need to be parsed.

How could I implement onscrolllistener, because of the url param?

Thanks in advance.

like image 646
dynamitem Avatar asked Sep 07 '15 19:09

dynamitem


2 Answers

Base on this link, I have written following solution to add elements ( 30 elements at a time, i.e page size = 30) to listview asynchronously.

Create a class named EndlessListView as follows:

public class EndlessListView extends ListView implements OnScrollListener {

private View footer;
private boolean isLoading;
private EndlessListener listener;// listner
private EndlessAdapter endlessAdapter;// adapter.

private int maxNoOfElement;

public EndlessListView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    this.setOnScrollListener(this);
}

public EndlessListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.setOnScrollListener(this);
}

public EndlessListView(Context context) {
    super(context);
    this.setOnScrollListener(this);
}

public void setListener(EndlessListener listener) {
    this.listener = listener;
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount) {

    if (getAdapter() == null)
        return;

    if (getAdapter().getCount() == 0 || getAdapter().getCount() <= 5)
        return;

    int l = visibleItemCount + firstVisibleItem;
    if (l >= totalItemCount && !isLoading) {
        // It is time to add new data. We call the listener
        Log.e("LOAD", "DATA");
        isLoading = true;
        listener.loadData();

    }
}

public void setMaxElemnt(int maxNoOfElement) {
    this.maxNoOfElement = maxNoOfElement;
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}

public void setLoadingView(int resId) {
    LayoutInflater inflater = (LayoutInflater) super.getContext()
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    footer = (View) inflater.inflate(resId, null);
    this.addFooterView(footer);
}

public void setAdapter(EndlessAdapter adapter) {
    super.setAdapter(adapter);
    this.endlessAdapter = adapter;

}

public void addNewData(List<Integer> data) {
    endlessAdapter.setData(data);
    endlessAdapter.notifyDataSetChanged();
    isLoading = false;
}

public static interface EndlessListener {
    public void loadData();

}

 }

After this we have to create the adapter for it,called

EndlessAdapter

public class EndlessAdapter extends BaseAdapter {
private List<Integer> mIntegers;
private Context context;

public EndlessAdapter(Context context) {
    this.context = context;
}

public void setData(List<Integer> mIntegers) {
    this.mIntegers = mIntegers;
}

@Override
public int getCount() {
    if (mIntegers == null)
        return 0;
    return mIntegers.size();
}

@Override
public Integer getItem(int index) {

    if (mIntegers == null) {
        return null;
    } else {
        return mIntegers.get(index);
    }
}

@Override
public long getItemId(int arg0) {
    // TODO Auto-generated method stub
    return 0;
}

class ViewHolder {
    TextView textView;
}

@Override
public View getView(int index, View view, ViewGroup viewGroup) {
    ViewHolder holder;
    if (view == null) {
        holder = new ViewHolder();
        view = ((LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE))
                .inflate(R.layout.rows, viewGroup, false);
        holder.textView = (TextView) view.findViewById(R.id.mtext);
        view.setTag(holder);

    } else {
        holder = (ViewHolder) view.getTag();
    }
    holder.textView.setText(getItem(index) + "");
    return view;
}

   }

Now in xml of the activity we could use EndlessListView(in com.example.stackoverflow package) as follows :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<com.example.stackoverflow.EndlessListView
    android:id="@+id/endlessListView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

</RelativeLayout>

After this step we need to make following change in the MainActivity

    public class MainActivity extends Activity implements EndlessListener {
private EndlessAdapter adapter;
private EndlessListView endlessListView;
private List<Integer> data;
private int gStartIndex = 30;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    endlessListView = (EndlessListView) findViewById(R.id.endlessListView);
    adapter = new EndlessAdapter(this);
    data = new ArrayList<Integer>();

    endlessListView.setLoadingView(R.layout.footer);
    // endlessListView.showFooter();
    endlessListView.setListener(this);
    endlessListView.setAdapter(adapter);
    gStartIndex = 0;
    fillData(gStartIndex);
}

private void fillData(int startIndex) {

    new AsyncLoadData().execute(startIndex);

}

@Override
public void loadData() {

    fillData(gStartIndex);

}

private class AsyncLoadData extends AsyncTask<Integer, Integer, Void> {

    @Override
    protected Void doInBackground(Integer... params) {
        int gendIndex = params[0] + 30;
        gStartIndex = gendIndex;
        /***
         * Here you could add your n/w code. To simulate the n/w comm. i am
         * adding elements to list and making it sleep for few sec.
         * */
        for (int i = params[0]; i < gendIndex; i++) {
            publishProgress(i);

        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        data.add(values[0]);
    }

    @Override
    protected void onPostExecute(Void result) {
        endlessListView.addNewData(data);
    }
}

    }
like image 142
avinash Avatar answered Oct 17 '22 14:10

avinash


This custom ScrollListView that I just found has OnBottomReachedListener which you can implement from your Activity or Fragment and receive events when user hits the bottom of the page. You would also need to track the current page and when bottom is hit to download the next page. The latest data should be added to your existing ArrayList and you should call notifyDataSetChanged() on your adapter so ListView can render the new data. You don't have to create new adapter, you just need to update the data source which is your ArrayList.

If you support orientation change you would must to save in onSaveInstanceState() your current page number so when Activity or Fragment is recreated it can continue from correct page. And you would have to keep the ArrayList data source safe of configuration changes because you don't want to downloaded it again. I would suggest using the Fragment with setRetainInstance() set to true to persist ArrayList.

Here is my custom code for keeping data around using RetainFragment:

/**
 * A simple non-UI Fragment that stores a single Object
 * and is retained over configuration changes.
 */
public class RetainFragment<E extends Object> extends Fragment {

    /** Object for retaining. */
    private E mObject;

    /**
     * Empty constructor as per the Fragment documentation
     */
    public RetainFragment() {}

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Make sure this Fragment is retained over a configuration change
        setRetainInstance(true);
    }

    /**
     * Store a single object in this Fragment.
     *
     * @param object The object to store
     */
    public void setObject(E object) {
        mObject = object;
    }

    /**
     * Get the stored object.
     *
     * @return The stored object
     */
    public E getObject() {
        return mObject;
    }
}

Example of RetainFragment usage in your Activity:

FragmentManager fm = getFragmentManager();
mRetainFragment = (RetainFragment<ArrayList>) fm.findFragmentByTag(RETAIN_FRAG);
if (mRetainFragment == null) {
    mRetainFragment = new RetainFragment<>();
    mRetainFragment.setObject(new ArrayList());
    fm.beginTransaction().add(mRetainFragment, RETAIN_FRAG).commit();
}

ArrayList yourArrayList = mRetainFragment.getObject();
// Now your ArrayList is saved accrossed configuration changes
like image 33
Aleksandar Ilic Avatar answered Oct 17 '22 13:10

Aleksandar Ilic