Smart List Adapter Tutorial – Singleton Oberservable List Objects and how they can improve your app
来源:互联网 发布:mac 拼音输入法 编辑:程序博客网 时间:2024/06/07 09:06
Smart List Adapter Tutorial – Singleton Oberservable List Objects and how they can improve your app
Aug 13
Android, Development, General, Tutorial observable, observable list, observer, singleton, smart list adapter 2 Comments
This tutorial is all about observation (heh… funny nerd joke there). I come from a web development background (LAMP) and really just started coding with Java at the beginning of June… So this is a new adventure for me. As I have been working on andAMP, I found myself having to write alot of extra code to manage the current play queue of songs everywhere in my app and it really started getting on my nerves because I found myself duplicating alot of code and having multiple copies of the same array in memory… I tried setting the array as a static property of my main activity and accessing it from the other parts of my app statically (like using a class with getters and setters)… but that caused logic and stability issues due to the life cycle of the activity and just wasn’t very elegant… sloppy to say the least and when I attempted to add a widget to the app… well… let’s not go there.
So, anyway, I started looking for a method to create a smarter list. There were a few different issues that really bothered me about how I was managing the play queue. First, I had multiple copies of the ArrayList in my app… For example, I have 2 Activities and aService that use this particular list and I found that it added a TON of complexity to my app with every new copy I made of the list. In addition, I have to make sure I have a fresh copy of the current list anytime I need to use it so that I don’t use an old list… so I had all of this code to double check that everyone had the same copy of the current list. On top of that, anytime I make a change to the list, I need to make sure that my ListAdapter has the correct version of the current list… or it will show an old list of songs to the user when they want to view the play queue…. so, anyway, I found myself writing alot of stupid code to manage a simple list of Song objects. I just knew there was a better way to do it and this tutorial will show you what I discovered.
First, I decided to make a custom list object that was a Singleton Class so that I didn’t have multiple copies of the same list in memory AND this would ensure that all copies of the list were the same. In addition, I wanted the list to be thread safe because I might have the Service updating the list at the same time as an activity… and that would cause problems… so I read up on synchronization. I am still not 100% sure that how I did it is the correct way or not… but it works so I am not complaining.
Secondly, I wanted to make the list intelligent enough to inform it’s consumers when and if a change had been made to the list. This would save me alot of extra headache in manually telling the ListAdapter that the list had changed or telling the Service that the list had changed, etc. At first, I thought maybe I could attach some kind of listener to the list… and I was close. In the end I discovered Observable and Observer. These 2 classes allow me to provide a method for the consumer objects to watch the list and be notified whenever there is a change… and I think they are the best thing to happen to Lists since add() (lol… another nerd joke). All jokes aside, these discoveries gave my lists super powers and are on the way to super charging my applications. Below is the source code for you to look at… let me know what you think. I haven’t seen any Android specific tutorials about how to do this… if you know of one, please let me know so I can link it.
/res/layout/main.xml
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/base"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center_horizontal">
<Button
android:id="@+id/button"
android:text="Add Item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center">
</Button>
<Button
android:id="@+id/clear"
android:text="Clear List"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center">
</Button>
</LinearLayout>
<ListView android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false" />
</LinearLayout>
/res/layout/list_item.xml
2
3
4
5
6
7
8
<TextView android:id="@+id/text"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="40dip"
android:textSize="18dip"
android:textStyle="bold"
android:textColor="#FFFFE0" />
/res/values/array.xml
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<resources>
<string-array name="colors">
<item>red</item>
<item>blue</item>
<item>green</item>
<item>orange</item>
<item>purple</item>
<item>yellow</item>
<item>white</item>
<item>black</item>
<item>gold</item>
<item>silver</item>
</string-array>
<string-array name="cars">
<item>chevy</item>
<item>ford</item>
<item>toyota</item>
<item>nissan</item>
<item>volkswagon</item>
<item>bmw</item>
<item>buick</item>
<item>mercury</item>
<item>pontiac</item>
<item>honda</item>
</string-array>
</resources>
/SmartListAdapter/src/com/androidworkz/smartlistadapter/SmartListAdapterExample.java
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import android.app.ListActivity;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
public class SmartListAdapterExample extends ListActivity {
private static final int EXIT = 0;
private LayoutInflater inflater;
SmartList smartList1;
String[] colors;
String[] cars;
Random random;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Resources resources = getResources();
colors = resources.getStringArray(R.array.colors);
cars = resources.getStringArray(R.array.cars);
random = new Random();
smartList1 = SmartList.getInstance();
int x = 0;
while(x < 5) {
int rndcolor = random.nextInt(colors.length - 1);
int rndcar = random.nextInt(cars.length - 1);
smartList1.add(colors[rndcolor]+" "+cars[rndcar]);
x++;
}
SmartListAdapter smartAdapter = new SmartListAdapter(this);
inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.main, (ViewGroup) findViewById(R.id.base));
ListView list = (ListView) layout.findViewById(android.R.id.list);
list.setAdapter(smartAdapter);
Button addItem = (Button) layout.findViewById(R.id.button);
Button clearList = (Button) layout.findViewById(R.id.clear);
addItem.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
int rndcolor = random.nextInt(colors.length - 1);
int rndcar = random.nextInt(cars.length - 1);
smartList1.add(colors[rndcolor]+" "+cars[rndcar]);
Log.v("SmartList", "Count is :"+smartList1.size());
}
});
clearList.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
smartList1.clear();
}
});
setContentView(layout);
}
private class SmartListAdapter extends BaseAdapter implements Observer {
private LayoutInflater mInflater;
private SmartList smartList2;
class ViewHolder {
TextView text;
}
public SmartListAdapter(Context context) {
mInflater = LayoutInflater.from(context);
smartList2 = SmartList.getInstance();
smartList2.addObserver(this);
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(smartList2.get(position));
return holder.text;
}
public int getCount() {
return smartList2.size();
}
public Object getItem(int position) {
return smartList2.get(position);
}
public long getItemId(int position) {
return position;
}
@Override
public void update(Observable arg0, Object arg1) {
smartList2 = SmartList.getInstance();
notifyDataSetChanged();
Log.v("SmartListAdapter", "Count is :"+smartList2.size());
}
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
int NONE = Menu.NONE;
menu.add(NONE, EXIT, 1, "Exit");
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case EXIT:
quit();
break;
}
return super.onOptionsItemSelected(item);
}
public void quit() {
// if the Android engineers see this their heads will explode
int pid = android.os.Process.myPid();
android.os.Process.killProcess(pid);
System.exit(0);
finish()
}
}
/SmartListAdapter/src/com/androidworkz/smartlistadapter/SmartList.java
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Observable;
public class SmartList extends Observable implements List<String> {
List<String> delegate;
public SmartList(List<String> delegate) {
this.delegate = delegate;
}
private SmartList() {
this.delegate = new ArrayList<String>();
}
public static synchronized SmartList getInstance() {
if (instance == null)
instance = new SmartList();
return instance;
}
private static SmartList instance;
@Override
public String toString() {
return delegate.toString();
}
@Override
public boolean add(String song) {
boolean result = delegate.add(song);
if (result) {
setChanged();
}
notifyObservers();
return result;
}
@Override
public void add(int position, String song) {
delegate.add(position, song);
setChanged();
notifyObservers();
}
@Override
public boolean addAll(Collection<? extends String> c) {
boolean result = delegate.addAll(c);
if(result) {
setChanged();
}
notifyObservers();
return result;
}
@Override
public boolean addAll(int position, Collection<? extends String> c) {
boolean result = delegate.addAll(position, c);
if(result) {
setChanged();
}
notifyObservers();
return result;
}
@Override
public void clear() {
delegate.clear();
setChanged();
notifyObservers();
}
@Override
public boolean contains(Object song) {
return delegate.contains(song);
}
@Override
public boolean containsAll(Collection<?> c) {
return delegate.containsAll(c);
}
@Override
public String get(int position) {
return delegate.get(position);
}
@Override
public int indexOf(Object song) {
return delegate.indexOf(song);
}
@Override
public boolean equals(Object song) {
return delegate.equals(song);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public Iterator<String> iterator() {
return delegate.iterator();
}
@Override
public int lastIndexOf(Object song) {
return delegate.lastIndexOf(song);
}
@Override
public ListIterator<String> listIterator() {
return delegate.listIterator();
}
@Override
public ListIterator<String> listIterator(int position) {
return delegate.listIterator(position);
}
@Override
public String remove(int position) {
String result = delegate.remove(position);
setChanged();
notifyObservers();
return result;
}
@Override
public boolean remove(Object song) {
boolean result = delegate.remove(song);
if (result) {
setChanged();
}
notifyObservers();
return result;
}
@Override
public boolean removeAll(Collection<?> c) {
boolean result = delegate.removeAll(c);
if (result) {
setChanged();
}
notifyObservers();
return result;
}
@Override
public boolean retainAll(Collection<?> c) {
boolean result = delegate.retainAll(c);
if (result) {
setChanged();
}
notifyObservers();
return result;
}
@Override
public String set(int position, String song) {
String result = delegate.set(position, song);
setChanged();
notifyObservers();
return result;
}
@Override
public int size() {
return delegate.size();
}
@Override
public List<String> subList(int fromPosition, int toPosition) {
return delegate.subList(fromPosition, toPosition);
}
@Override
public Object[] toArray() {
return delegate.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return delegate.toArray(a);
}
}
Addendum:
I wanted to note that your Activity can implement Observer as well so that you can use Observable with POJO (Plain Old Java Objects). For example, You can create a Singleton class that contains your application state and variables (I haven’t tried storing objects in one of these but it’s great for basic types (Boolean, Integer, String, Long, etc)). If your Activity is observing multiple objects… this is how you capture which object is sending the update notification:
Here is an actual work in progress for my ApplicationState object
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.util.Observable;
public class ApplicationState extends Observable {
private boolean PartyShuffleMode = false;
private boolean QueueMode = false;
private boolean ShuffleMode = false;
private boolean ContinuousMode = false;
private ApplicationState() {}
public static synchronized ApplicationState getInstance() {
if (instance == null)
instance = new ApplicationState();
return instance;
}
public void setPartyShuffleMode(boolean partyShuffleMode) {
PartyShuffleMode = partyShuffleMode;
setChanged();
notifyObservers();
}
public boolean isPartyShuffleMode() {
return PartyShuffleMode;
}
public void setQueueMode(boolean queueMode) {
QueueMode = queueMode;
setChanged();
notifyObservers();
}
public boolean isQueueMode() {
return QueueMode;
}
public void setShuffleMode(boolean shuffleMode) {
ShuffleMode = shuffleMode;
setChanged();
notifyObservers();
}
public boolean isShuffleMode() {
return ShuffleMode;
}
public void setContinuousMode(boolean continuousMode) {
ContinuousMode = continuousMode;
setChanged();
notifyObservers();
}
public boolean isContinuousMode() {
return ContinuousMode;
}
private static ApplicationState instance;
}
Let’s say you are observing SmartList as well as your ApplicationState object. Below you can see how to instantiate the Singleton objects and add the Observer. in the update method for the Observer you compare the Observable argument (observable) with the Singleton to see if that was the object that was updated. I found that the Object argument was null everytime I tried to do something with it… so I am not sure what it’s purpose really is.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void onCreate() {
ApplicationState state = ApplcationState.getInstance();
state.addObserver(this);
SmartList smartList = SmartList.getInstance();
smartList.addObserver(this);
/* ....... the rest of your onCreate() */
}
@Override
public void update(Observable observable, Object object) {
if (observable.equals(SmartList.getInstance())) {
smartList = SmartList.getInstance();
}
if (observable.equals(ApplicationState.getInstance())) {
state = ApplicationState.getInstance();
}
}
}
Download Complete Eclipse Project
- Smart List Adapter Tutorial – Singleton Oberservable List Objects and how they can improve your app
- How to improve quality and syntax of your Android code
- How To Improve Your English
- how to improve your eyesight
- Smart App Banners Tutorial
- and they can cause
- excel tool: List objects / file and folders
- Python Tutorial :Loops and List Comprehensions 其他
- BLToolKit: how to insert a list of objects?
- How to Improve Your Public Speaking: 27 Tips, Tricks, and Tutorials
- how to improve your english skill
- 中级2 How to improve your English
- How did YOU improve your tech skills?
- Glossary-How Do They Crack Your Password?
- How a Small Change Can Boost Your Motivation and Performance
- how many hairstyles can they see?
- how many hairstyles can they see?
- ActionScript 3.0基础教程2-Display List and Display Objects
- 拉手IPO路演PPT解析:拉手上市为何“被推迟”?
- POJ1164 + USACO Section 2.1 The Castle - 简单的DFS...
- Android 初步
- linux解压缩命令
- Memcached 笔记
- Smart List Adapter Tutorial – Singleton Oberservable List Objects and how they can improve your app
- android的color值
- com.microsoft.sqlserver.jdbc.SQLServerException: 不支持此游标类型/并发组合
- System.Net.Mail 发送邮件代码
- Android数据存储之SharedPreferences方式
- java中HashMap详解
- 卡拉ok应用Soulo Karaoke评测
- qt4 显示中文
- Android 控件seekbar进度条、ratingbar星星评分条