Android lists: nice example.
authorgumartinm <gustavo@gumartinm.name>
Tue, 24 Apr 2012 06:59:45 +0000 (08:59 +0200)
committergumartinm <gustavo@gumartinm.name>
Tue, 24 Apr 2012 06:59:45 +0000 (08:59 +0200)
From: http://www.learn-android.com/2011/11/22/lots-of-lists-custom-adapter/

17 files changed:
Android/Lists/AndroidManifest.xml [new file with mode: 0644]
Android/Lists/gen/de/example/lists/BuildConfig.java [new file with mode: 0644]
Android/Lists/gen/de/example/lists/R.java [new file with mode: 0644]
Android/Lists/proguard-project.txt [new file with mode: 0644]
Android/Lists/project.properties [new file with mode: 0644]
Android/Lists/res/drawable-hdpi/ic_launcher.png [new file with mode: 0644]
Android/Lists/res/drawable-ldpi/ic_launcher.png [new file with mode: 0644]
Android/Lists/res/drawable-mdpi/ic_launcher.png [new file with mode: 0644]
Android/Lists/res/drawable-mdpi/news_icon_1.png [new file with mode: 0644]
Android/Lists/res/drawable-mdpi/news_icon_2.png [new file with mode: 0644]
Android/Lists/res/drawable-xhdpi/ic_launcher.png [new file with mode: 0644]
Android/Lists/res/layout/main.xml [new file with mode: 0644]
Android/Lists/res/layout/news_entry_list_item.xml [new file with mode: 0644]
Android/Lists/res/values/strings.xml [new file with mode: 0644]
Android/Lists/src/de/example/lists/ListActivityActivity.java [new file with mode: 0644]
Android/Lists/src/de/example/lists/NewsEntry.java [new file with mode: 0644]
Android/Lists/src/de/example/lists/NewsEntryAdapter.java [new file with mode: 0644]

diff --git a/Android/Lists/AndroidManifest.xml b/Android/Lists/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..222741d
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="de.example.lists"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk android:minSdkVersion="15" />
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name" >
+        <activity
+            android:name=".ListActivityActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/Android/Lists/gen/de/example/lists/BuildConfig.java b/Android/Lists/gen/de/example/lists/BuildConfig.java
new file mode 100644 (file)
index 0000000..3e4ca63
--- /dev/null
@@ -0,0 +1,6 @@
+/** Automatically generated file. DO NOT MODIFY */
+package de.example.lists;
+
+public final class BuildConfig {
+    public final static boolean DEBUG = true;
+}
\ No newline at end of file
diff --git a/Android/Lists/gen/de/example/lists/R.java b/Android/Lists/gen/de/example/lists/R.java
new file mode 100644 (file)
index 0000000..dca0664
--- /dev/null
@@ -0,0 +1,33 @@
+/* AUTO-GENERATED FILE.  DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found.  It
+ * should not be modified by hand.
+ */
+
+package de.example.lists;
+
+public final class R {
+    public static final class attr {
+    }
+    public static final class drawable {
+        public static final int ic_launcher=0x7f020000;
+        public static final int news_icon_1=0x7f020001;
+        public static final int news_icon_2=0x7f020002;
+    }
+    public static final class id {
+        public static final int list=0x7f050000;
+        public static final int news_entry_icon=0x7f050001;
+        public static final int news_entry_subtitle=0x7f050003;
+        public static final int news_entry_title=0x7f050002;
+    }
+    public static final class layout {
+        public static final int main=0x7f030000;
+        public static final int news_entry_list_item=0x7f030001;
+    }
+    public static final class string {
+        public static final int app_name=0x7f040001;
+        public static final int desc=0x7f040002;
+        public static final int hello=0x7f040000;
+    }
+}
diff --git a/Android/Lists/proguard-project.txt b/Android/Lists/proguard-project.txt
new file mode 100644 (file)
index 0000000..f2fe155
--- /dev/null
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/Android/Lists/project.properties b/Android/Lists/project.properties
new file mode 100644 (file)
index 0000000..0840b4a
--- /dev/null
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-15
diff --git a/Android/Lists/res/drawable-hdpi/ic_launcher.png b/Android/Lists/res/drawable-hdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..96a442e
Binary files /dev/null and b/Android/Lists/res/drawable-hdpi/ic_launcher.png differ
diff --git a/Android/Lists/res/drawable-ldpi/ic_launcher.png b/Android/Lists/res/drawable-ldpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..9923872
Binary files /dev/null and b/Android/Lists/res/drawable-ldpi/ic_launcher.png differ
diff --git a/Android/Lists/res/drawable-mdpi/ic_launcher.png b/Android/Lists/res/drawable-mdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..359047d
Binary files /dev/null and b/Android/Lists/res/drawable-mdpi/ic_launcher.png differ
diff --git a/Android/Lists/res/drawable-mdpi/news_icon_1.png b/Android/Lists/res/drawable-mdpi/news_icon_1.png
new file mode 100644 (file)
index 0000000..f7afc6f
Binary files /dev/null and b/Android/Lists/res/drawable-mdpi/news_icon_1.png differ
diff --git a/Android/Lists/res/drawable-mdpi/news_icon_2.png b/Android/Lists/res/drawable-mdpi/news_icon_2.png
new file mode 100644 (file)
index 0000000..d2921c3
Binary files /dev/null and b/Android/Lists/res/drawable-mdpi/news_icon_2.png differ
diff --git a/Android/Lists/res/drawable-xhdpi/ic_launcher.png b/Android/Lists/res/drawable-xhdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..71c6d76
Binary files /dev/null and b/Android/Lists/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/Android/Lists/res/layout/main.xml b/Android/Lists/res/layout/main.xml
new file mode 100644 (file)
index 0000000..dd5ea07
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <TextView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/hello" />
+    
+    <ListView android:id="@+id/list"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/Android/Lists/res/layout/news_entry_list_item.xml b/Android/Lists/res/layout/news_entry_list_item.xml
new file mode 100644 (file)
index 0000000..3c3d3bf
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Layout for individual news entries in a list -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+    
+    <!-- Icon shown next to the title/subtitle -->
+    <ImageView
+        android:id="@+id/news_entry_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentLeft="true"
+        android:padding="3dp"
+        android:orientation="vertical"
+        android:contentDescription="@string/desc"/>
+    
+    
+        
+    <!-- Title of the news entry -->
+    <TextView
+        android:id="@+id/news_entry_title"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@id/news_entry_icon"
+        android:layout_alignTop="@id/news_entry_icon"
+           android:layout_margin="5dp"
+        android:textSize="14sp"
+        android:textStyle="bold" />
+    
+    <!-- Subtitle contains author and date -->
+    <TextView
+        android:id="@+id/news_entry_subtitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignLeft="@id/news_entry_title"
+        android:layout_below="@id/news_entry_title" 
+        android:textSize="12sp" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/Android/Lists/res/values/strings.xml b/Android/Lists/res/values/strings.xml
new file mode 100644 (file)
index 0000000..a3e87a0
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="hello">Hello World, ListActivityActivity!</string>
+    <string name="app_name">ListActivity</string>
+    <string name="desc">description</string>
+
+</resources>
\ No newline at end of file
diff --git a/Android/Lists/src/de/example/lists/ListActivityActivity.java b/Android/Lists/src/de/example/lists/ListActivityActivity.java
new file mode 100644 (file)
index 0000000..2c5902b
--- /dev/null
@@ -0,0 +1,49 @@
+package de.example.lists;
+
+import java.util.ArrayList;
+import java.util.GregorianCalendar;
+import java.util.List;
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ListView;
+
+public class ListActivityActivity extends Activity {
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+        
+        // Setup the list view
+        final ListView newsEntryListView = (ListView) findViewById(R.id.list);
+        final NewsEntryAdapter newsEntryAdapter = new NewsEntryAdapter(this, R.layout.news_entry_list_item);
+        newsEntryListView.setAdapter(newsEntryAdapter);
+        
+        // Populate the list, through the adapter
+        for(final NewsEntry entry : getNewsEntries()) {
+               newsEntryAdapter.add(entry);
+        }
+    }
+    
+    private List<NewsEntry> getNewsEntries() {
+       
+       // Let's setup some test data.
+       // Normally this would come from some asynchronous fetch into a data source
+       // such as a sqlite database, or an HTTP request
+       
+       final List<NewsEntry> entries = new ArrayList<NewsEntry>();
+       
+       for(int i = 1; i < 50; i++) {
+               entries.add(
+                       new NewsEntry(
+                                       "Test Entry " + i,
+                                       "Anonymous Author " + i,
+                                       new GregorianCalendar(2011, 11, i).getTime(),
+                                       i % 2 == 0 ? R.drawable.news_icon_1 : R.drawable.news_icon_2
+                       )
+               );
+       }
+       
+       return entries;
+    }
+}
\ No newline at end of file
diff --git a/Android/Lists/src/de/example/lists/NewsEntry.java b/Android/Lists/src/de/example/lists/NewsEntry.java
new file mode 100644 (file)
index 0000000..51728ab
--- /dev/null
@@ -0,0 +1,51 @@
+package de.example.lists;
+
+import java.util.Date;
+
+/**
+ * Encapsulates information about a news entry
+ */
+public final class NewsEntry {
+       
+       private final String title;
+       private final String author;
+       private final Date postDate;
+       private final int icon;
+
+       public NewsEntry(final String title, final String author, 
+                       final Date postDate, final int icon) {
+               this.title = title;
+               this.author = author;
+               this.postDate = postDate;
+               this.icon = icon;
+       }
+
+       /**
+        * @return Title of news entry
+        */
+       public String getTitle() {
+               return title;
+       }
+
+       /**
+        * @return Author of news entry
+        */
+       public String getAuthor() {
+               return author;
+       }
+
+       /**
+        * @return Post date of news entry
+        */
+       public Date getPostDate() {
+               return postDate;
+       }
+
+       /**
+        * @return Icon of this news entry
+        */
+       public int getIcon() {
+               return icon;
+       }
+
+}
diff --git a/Android/Lists/src/de/example/lists/NewsEntryAdapter.java b/Android/Lists/src/de/example/lists/NewsEntryAdapter.java
new file mode 100644 (file)
index 0000000..05b26d0
--- /dev/null
@@ -0,0 +1,102 @@
+package de.example.lists;
+
+import android.widget.ArrayAdapter;
+import java.text.DateFormat;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * Adapts NewsEntry objects onto views for lists
+ */
+public final class NewsEntryAdapter extends ArrayAdapter<NewsEntry> {
+
+       private final int newsItemLayoutResource;
+
+       public NewsEntryAdapter(final Context context, final int newsItemLayoutResource) {
+               super(context, 0);
+               this.newsItemLayoutResource = newsItemLayoutResource;
+       }
+
+       @Override
+       public View getView(final int position, final View convertView, final ViewGroup parent) {
+               
+               // We need to get the best view (re-used if possible) and then
+               // retrieve its corresponding ViewHolder, which optimizes lookup efficiency
+               final View view = getWorkingView(convertView);
+               final ViewHolder viewHolder = getViewHolder(view);
+               final NewsEntry entry = getItem(position);
+               
+               // Setting the title view is straightforward
+               viewHolder.titleView.setText(entry.getTitle());
+               
+               // Setting the subTitle view requires a tiny bit of formatting
+               final String formattedSubTitle = String.format("By %s on %s", 
+                       entry.getAuthor(), 
+                       DateFormat.getDateInstance(DateFormat.SHORT).format(entry.getPostDate())
+               );
+               
+               viewHolder.subTitleView.setText(formattedSubTitle);
+               
+               // Setting image view is also simple
+               viewHolder.imageView.setImageResource(entry.getIcon());
+               
+               return view;
+       }
+
+       private View getWorkingView(final View convertView) {
+               // The workingView is basically just the convertView re-used if possible
+               // or inflated new if not possible
+               View workingView = null;
+               
+               if(null == convertView) {
+                       final Context context = getContext();
+                       final LayoutInflater inflater = (LayoutInflater)context.getSystemService
+                     (Context.LAYOUT_INFLATER_SERVICE);
+                       
+                       workingView = inflater.inflate(newsItemLayoutResource, null);
+               } else {
+                       workingView = convertView;
+               }
+               
+               return workingView;
+       }
+       
+       private ViewHolder getViewHolder(final View workingView) {
+               // The viewHolder allows us to avoid re-looking up view references
+               // Since views are recycled, these references will never change
+               final Object tag = workingView.getTag();
+               ViewHolder viewHolder = null;
+               
+               
+               if(null == tag || !(tag instanceof ViewHolder)) {
+                       viewHolder = new ViewHolder();
+                       
+                       viewHolder.titleView = (TextView) workingView.findViewById(R.id.news_entry_title);
+                       viewHolder.subTitleView = (TextView) workingView.findViewById(R.id.news_entry_subtitle);
+                       viewHolder.imageView = (ImageView) workingView.findViewById(R.id.news_entry_icon);
+                       
+                       workingView.setTag(viewHolder);
+                       
+               } else {
+                       viewHolder = (ViewHolder) tag;
+               }
+               
+               return viewHolder;
+       }
+       
+       /**
+        * ViewHolder allows us to avoid re-looking up view references
+        * Since views are recycled, these references will never change
+        */
+       private static class ViewHolder {
+               public TextView titleView;
+               public TextView subTitleView;
+               public ImageView imageView;
+       }
+       
+       
+}