summaryrefslogtreecommitdiff
path: root/src/plugins/android.codeutils/templates/activity_samples/endless_list/endless_list_activity.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/android.codeutils/templates/activity_samples/endless_list/endless_list_activity.java')
-rw-r--r--src/plugins/android.codeutils/templates/activity_samples/endless_list/endless_list_activity.java334
1 files changed, 334 insertions, 0 deletions
diff --git a/src/plugins/android.codeutils/templates/activity_samples/endless_list/endless_list_activity.java b/src/plugins/android.codeutils/templates/activity_samples/endless_list/endless_list_activity.java
new file mode 100644
index 0000000..2ea453e
--- /dev/null
+++ b/src/plugins/android.codeutils/templates/activity_samples/endless_list/endless_list_activity.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 #package_name#;
+
+import java.util.ArrayList;
+import java.util.List;
+import android.app.Activity;
+import android.app.LauncherActivity.ListItem;
+import android.app.ListActivity;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import #ManifestPackageName#.R;
+
+/**
+ * Class which holds an example of a endless list. It means a list will be
+ * displayed and it will always have items to be displayed. <br>
+ * New data is loaded asynchronously in order to provide a good user experience.
+ */
+public class #class_name# extends ListActivity {
+
+ /**
+ * Adapter for endless list.
+ */
+ private EndlessListAdapter arrayAdapter = null;
+
+ /**
+ * Variable which controls when new items start being fetched. For instance
+ * you may want to start get element when the list have 5 elements left to
+ * be displayed.
+ */
+ private int totalSizeToBe = 0;
+
+ /**
+ * Variable which controls when new items are being loaded. If this variable
+ * is true, it means items are being loaded, otherwise it is set to false.
+ */
+ private boolean isLoading = false;
+
+ /**
+ * The number of elements which are retrieved every time the service is
+ * called for retrieving elements.
+ */
+ private static final int BLOCK_SIZE = 15;
+
+ /**
+ * The number of elements left in the list when the asynchronous service
+ * will be called.
+ */
+ private static final int LOAD_AHEAD_SIZE = 5;
+
+ /**
+ * The number of items added to the <i>totalSizeToBe</i> field.
+ */
+ private static final int INCREMENT_TOTAL_MINIMUM_SIZE = 15;
+
+ /**
+ * Property to save the number of items already loaded
+ */
+ private static final String PROP_ITEM_COUNT = "item_count";
+
+ /**
+ * Property to save the top most index of the list
+ */
+ private static final String PROP_TOP_ITEM = "top_list_item";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ arrayAdapter = new EndlessListAdapter(this, R.layout.#layout_name#endless_list/listrow.xml#, new ArrayList<ListElement>());
+
+ // download asynchronously initial list
+ Downloaditems downloadAction = new Downloaditems();
+ downloadAction.execute(new Integer[] {
+ 0, BLOCK_SIZE });
+
+ setListAdapter(arrayAdapter);
+ getListView().setOnScrollListener(new EndlessListScrollListener());
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ outState.putInt(PROP_ITEM_COUNT, arrayAdapter.getCount());
+ for (int i = 0; i < arrayAdapter.getCount(); i++) {
+ outState.putSerializable(Integer.toString(i),
+ arrayAdapter.getItemAt(i));
+ }
+ outState.putInt(PROP_TOP_ITEM, getListView().getFirstVisiblePosition());
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle state) {
+ super.onRestoreInstanceState(state);
+ int count = state.getInt(PROP_ITEM_COUNT);
+ for (int i = 0; i < count; i++) {
+ arrayAdapter.add((ListElement) state.get(Integer.toString(i)));
+ }
+ getListView().setSelection(state.getInt(PROP_TOP_ITEM));
+ }
+
+ @Override
+ protected void onListItemClick(ListView lv, View v, int position, long id) {
+ // your action here
+ Toast.makeText(
+ lv.getContext(),
+ getString(R.string.selected_element_message,
+ arrayAdapter.getItemAt(position).text),
+ Toast.LENGTH_SHORT).show();
+ }
+
+ /**
+ * This method represents a service which takes a long time to be executed.
+ * To simulate it, it is inserted a lag of 1 second. <br>
+ * This method basically creates a <i>cache</i> number of
+ * {@link ListElement} and returns it. It creates {@link ListElement}s with
+ * text higher than <i>itemNumber</i>.
+ *
+ * @param itemNumber
+ * Basic number to create other elements.
+ * @param numberOfItemsToBeCreated
+ * Number of items to be created.
+ *
+ * @return Returns the created list of {@link ListElement}s.
+ */
+ private List<ListElement> retrieveItems(Integer itemNumber, int numberOfItemsToBeCreated) {
+ List<ListElement> results = new ArrayList<ListElement>();
+ try {
+ // wait for 1 second in order to simulate the long service
+ Thread.sleep(1000);
+ // create items
+ for (int i = 0; i <= numberOfItemsToBeCreated; i++) {
+ String itemToBeAdded = getString(R.string.list_item_number,
+ (itemNumber + i));
+ results.add(new ListElement(itemToBeAdded, R.drawable.listicon));
+ }
+ } catch (InterruptedException e) {
+ // treat exception here
+ }
+ return results;
+ }
+
+ /**
+ * Listener which handles the endless list. It is responsible for
+ * determining when the long service will be called asynchronously.
+ */
+ class EndlessListScrollListener implements OnScrollListener {
+
+ @Override
+ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+ int totalItemCount) {
+
+ // load more elements if there are LOAD_AHEAD_SIZE left in the list to be displayed
+ boolean loadMore = firstVisibleItem + visibleItemCount >= totalItemCount
+ - LOAD_AHEAD_SIZE;
+
+ /*
+ * Add one more condition: only get more results in case the list achieves
+ * a minimum size. This is necessary in order to avoid that this method is called
+ * each time the condition above is reached and the scroll is pressed.
+ */
+ if (loadMore && totalSizeToBe <= totalItemCount) {
+ totalSizeToBe += INCREMENT_TOTAL_MINIMUM_SIZE;
+ // call service
+ Downloaditems downloadAction = new Downloaditems();
+ downloadAction.execute(new Integer[] {
+ totalItemCount, BLOCK_SIZE });
+ }
+ }
+
+ @Override
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ // do nothing
+ }
+ }
+
+ /**
+ * Asynchronous job call. This class is responsible for calling
+ * the long service and managing the <i>isLoading</i> flag.
+ */
+ class Downloaditems extends AsyncTask<Integer, Void, List<ListElement>> {
+
+ // indexes constants
+ private static final int ITEM_NUMBER_INDES = 0;
+ private static final int NUMBER_OF_ITEMS_TO_BE_CREATED_INDEX = 1;
+
+ @Override
+ protected void onPreExecute() {
+ // flag loading is being executed
+ isLoading = true;
+ }
+
+ @Override
+ protected List<ListElement> doInBackground(Integer... params) {
+
+ // execute the long service
+ return retrieveItems(params[ITEM_NUMBER_INDES], params[NUMBER_OF_ITEMS_TO_BE_CREATED_INDEX]);
+ }
+
+ @Override
+ protected void onPostExecute(List<ListElement> result) {
+ arrayAdapter.setNotifyOnChange(true);
+ for (ListElement item : result) {
+ // it is necessary to verify whether the item was already added
+ // because this job is called many times asynchronously
+ synchronized (arrayAdapter) {
+ if (!arrayAdapter.contains(item)) {
+ arrayAdapter.add(item);
+ }
+ }
+ }
+ // flag the loading is finished
+ isLoading = false;
+ }
+ }
+
+ /**
+ * Adapter which handles the list be be displayed.
+ */
+ class EndlessListAdapter extends ArrayAdapter<ListElement> {
+
+ private final Activity context;
+ private final List<ListElement> items;
+ private final int rowViewId;
+
+ /**
+ * Instantiate the Adapter for an Endless List Activity.
+ *
+ * @param context {@link Activity} which holds the endless list.
+ * @param rowviewId Identifier of the View which holds each row of
+ * the List.
+ * @param items Initial set of items which are added to list being displayed.
+ */
+ public EndlessListAdapter(Activity context, int rowviewId, List<ListElement> items) {
+ super(context, rowviewId, items);
+ this.context = context;
+ this.items = items;
+ this.rowViewId = rowviewId;
+ }
+
+ /**
+ * Check whether a {@link ListItem} is already in this adapter.
+ *
+ * @param item Item to be verified whether it is in the adapter.
+ *
+ * @return Returns <code>true</code> in case the {@link ListElement} is
+ * in the adapter, <code>false</code> otherwise.
+ */
+ public boolean contains(ListElement item) {
+ return items.contains(item);
+ }
+
+ /**
+ * Get a {@link ListElement} at a certain position.
+ *
+ * @param index Position where the {@link ListElement} is retrieved.
+ *
+ * @return Returns the {@link ListElement} give a certain position.
+ */
+ public ListElement getItemAt(int index) {
+ return items.get(index);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+
+ ImageView imageView;
+ TextView textView;
+
+ View rowView = convertView;
+
+ /*
+ * We inflate the row using the determined layout. Also,
+ * we fill the necessary data in the text and image views.
+ */
+ LayoutInflater inflater = context.getLayoutInflater();
+ rowView = inflater.inflate(rowViewId, null, true);
+ textView = (TextView) rowView.findViewById(R.id.text01);
+ imageView = (ImageView) rowView.findViewById(R.id.img01);
+ textView.setText(items.get(position).text);
+ imageView.setImageResource(items.get(position).imageId);
+
+ /*
+ * If we reached the last position of the list and the loading
+ * operation is still being performed, set the loading message
+ * instead the normal value.
+ *
+ * Moreover, we modify the layout in order to center the loading message.
+ */
+ if (isLoading && position == items.size() - 1) {
+ textView.setText(R.string.loading_message);
+
+ // wrap content of the text view in order to center it
+ LayoutParams layoutParameters = (LayoutParams) textView.getLayoutParams();
+ layoutParameters.width = LayoutParams.WRAP_CONTENT;
+
+ // set image to the center, the text field will go along
+ imageView.setImageResource(android.R.drawable.progress_indeterminate_horizontal);
+ LinearLayout linearLayout = (LinearLayout) rowView.findViewById(R.id.vw01);
+ linearLayout.setGravity(Gravity.CENTER);
+ }
+
+ return rowView;
+ }
+ }
+} \ No newline at end of file