編輯:關於Android編程

Android中Adapter中edittext,checkbox記住狀態解決方案(一)
在上篇文章解決了adapter中checkbox記住狀態和edittext可編輯的問題,下面談談怎麼解決記住edittext中的內容和保證在操作加、減按鈕的時候,操作的edittext對象是沒有錯位的問題。
一、記住edittext中的內容
解決的思路和checkbox差不多,不過還是有些差別,checkbox只有兩種狀態,而edittext的值是不固定的。checkbox我們是用一個enum類型的list來保存狀態的,所以edittext就不能了,可以用map和實體類,我為了方便就用了hashMap。
// 用來存儲editext中數據的list private List在初始化的時候先模擬數據
for (CartBean cartBean : list) {
mData.add(new HashMap());
}
edittext的監聽,並且有個log
mHolder.num.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
if (!TextUtils.isEmpty(s.toString())) {
if(!TextUtils.isEmpty(s.toString())){
mData.get(position).put(etValue,
s.toString());
Log.i(afterTextChanged, position+position);
}
}
}
});
根據list對應位置的position取出edittext的值
String value = mData.get(position).get(etValue);
if (!TextUtils.isEmpty(value)) {
mHolder.num.setText(value);
} else {
mHolder.num.setText(1);
}
代碼出來了,然後在測試的時候可以發現仍然會出現錯亂的問題,後來當多次來回滑動列表之後,再滑動列表,讓第一個剛好完全出來,下一個剛好進來,這時候第一個item會被剛進來的item重用,執行上面的賦值代碼的時候log應該是這樣
01-27 15:55:46.612: I/afterTextChanged(4784): position0 01-27 15:55:46.622: I/afterTextChanged(4784): position1 01-27 15:55:46.632: I/afterTextChanged(4784): position2 01-27 15:55:46.642: I/afterTextChanged(4784): position3 01-27 15:55:46.642: D/AbsListView(4784): unregisterIRListener() is called 01-27 15:55:46.642: D/AbsListView(4784): unregisterIRListener() is called 01-27 15:55:46.662: D/AbsListView(4784): unregisterIRListener() is called 01-27 15:55:46.682: D/AbsListView(4784): unregisterIRListener() is called 01-27 15:55:56.882: I/afterTextChanged(4784): position4一個操作只觸發一個監聽
結果發現是這樣
01-27 15:53:43.772: I/afterTextChanged(4784): position0 01-27 15:53:43.772: I/afterTextChanged(4784): position5 01-27 15:53:43.772: I/afterTextChanged(4784): position5 01-27 15:53:43.772: I/afterTextChanged(4784): position9 01-27 15:53:43.772: I/afterTextChanged(4784): position5 01-27 15:53:43.772: I/afterTextChanged(4784): position0 01-27 15:53:43.772: I/afterTextChanged(4784): position6 01-27 15:53:43.772: I/afterTextChanged(4784): position15 01-27 15:53:43.772: I/afterTextChanged(4784): position15 01-27 15:53:43.772: I/afterTextChanged(4784): position11 01-27 15:53:43.772: I/afterTextChanged(4784): position6 01-27 15:53:43.772: I/afterTextChanged(4784): position2 01-27 15:53:43.772: I/afterTextChanged(4784): position8 01-27 15:53:43.772: I/afterTextChanged(4784): position12 01-27 15:53:43.772: I/afterTextChanged(4784): position18 01-27 15:53:43.772: I/afterTextChanged(4784): position13 01-27 15:53:43.772: I/afterTextChanged(4784): position9 01-27 15:53:43.772: I/afterTextChanged(4784): position4 01-27 15:53:43.772: I/afterTextChanged(4784): position4一個操作觸發了很多個監聽,觸發了多個監聽,就必然會導致多個地方的edittext的值被改變,所以才出現錯亂的問題。後來我想到可能是在adapter反復執行
mHolder.num.addTextChangedListener(new TextWatcher()的緣故,為了證實自己的想法,我點進去看了下監聽的源碼,發現
public void addTextChangedListener(TextWatcher watcher) {
if (mListeners == null) {
mListeners = new ArrayList();
}
mListeners.add(watcher);
}
原來android是用了arraylist把所有加進來的監聽都存起來了,所以才會有一個操作觸發多個監聽的問題。那麼checkbox沒出現這樣的原因應該是每次都重新設置監聽對象了吧
public void setOnClickListener(OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
果然每次都重新設置一個新的。其實根據方法名能夠看出來方法的用途的,一個是add,一個是set。
if (convertView == null) {
....
class MyTextWatcher implements TextWatcher {
public MyTextWatcher() {}
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
if (!TextUtils.isEmpty(s.toString())) {
mData.get(position).put(etValue, s.toString()); //
Log.i(afterTextChanged, position + position);
}
}
}
mHolder.num.addTextChangedListener(new MyTextWatcher(mHolder));
}
這樣只在convertview為null的時候才添加監聽,這樣保證了一個edittext只會有一個監聽。再試試,發現還是不對,改變過的值都無法保存。出了問題還是看log
01-27 16:59:40.512: I/afterTextChanged(12344): position0 01-27 16:59:40.532: I/afterTextChanged(12344): position1 01-27 16:59:40.542: I/afterTextChanged(12344): position2 01-27 16:59:40.552: I/afterTextChanged(12344): position3 01-27 16:59:42.772: I/afterTextChanged(12344): position4 01-27 16:59:43.712: I/afterTextChanged(12344): position0 01-27 16:59:44.502: I/afterTextChanged(12344): position1 01-27 16:59:45.392: I/afterTextChanged(12344): position2 01-27 16:59:46.632: I/afterTextChanged(12344): position3 01-27 16:59:47.492: I/afterTextChanged(12344): position4 01-27 16:59:47.842: I/afterTextChanged(12344): position0 01-27 16:59:49.142: I/afterTextChanged(12344): position1 01-27 16:59:51.662: I/afterTextChanged(12344): position2 01-27 16:59:52.822: I/afterTextChanged(12344): position3 01-27 16:59:53.192: I/afterTextChanged(12344): position4 01-27 17:00:06.662: I/afterTextChanged(12344): position0看到監聽裡面的position的值是0-4,也就是說無論列表怎麼滑動,position的值都只是convertview為空的時候初始化好的。這樣當第一項滾出屏幕,底下一項進入屏幕的時候,執行到這段代碼
//這時代碼position肯定是大於4的,假設是5,但mData中位置為5的地方是空值,這就導致第一項和第6項就都被設為1了
String value = mData.get(position).get(etValue);
if (!TextUtils.isEmpty(value)) {
mHolder.num.setText(value);
} else {
mHolder.num.setText(1);
}
想解決這個問題,就得在監聽回調的方法裡能夠動態獲取到position的值。這裡我們可以這樣做
if (convertView == null) {
......
class MyTextWatcher implements TextWatcher {
public MyTextWatcher(ViewHolder holder) {
mHolder = holder;
}
/**
* 這裡其實是緩存了一屏數目的viewholder, 也就是說一屏能顯示10條數據,那麼內存中就會有10個viewholder
* 在這的作用是通過edittext的tag拿到對應的position,用於儲存edittext的值
*/
private ViewHolder mHolder;
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
if (!TextUtils.isEmpty(s.toString())) {
//通過tag來取position
int position = (Integer) mHolder.num.getTag();
mData.get(position).put(etValue, s.toString()); //
Log.i(afterTextChanged, position + position);
}
}
}
mHolder.num.addTextChangedListener(new MyTextWatcher(mHolder));
convertView.setTag(mHolder);
} else {
mHolder = (ViewHolder) convertView.getTag();
}
//每次用position動態更新edittext的tag
mHolder.num.setTag(position);
雖然viewholder就固定的那幾個,但是我們可以通過edittext的tag從而達到動態更新position值的效果。
然後再測試就會發現edittext能夠記住內容了。
二、保證在操作加、減按鈕的時候,操作的edittext對象是沒有錯位的
正常監聽是這樣寫
mHolder.add.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
strNum = mData.get(position).get(etValue);
int intnum = Integer.parseInt(strNum);
intnum++;
mHolder.num.setText( + intnum);
}
});
但這樣寫在adapter中是行不通的,因為當觸發回調的時候,edittext已經不是add按鈕注冊監聽時候的那個了,而是最後一個加載的item中的edittext。edittext的對象已經變了就是導致操作edittext錯位的根本原因。這個問題的解決方法我在上篇文章裡面已經說過了,就是把edittext存起來。代碼我就不貼了,下面我會貼出demo鏈接,感興趣的可以下載看看。有什麼好的建議可以留言分享出來,共同學習。
Android Support Annotations 使用詳解
在Android Support Library19.1版本中,Android工具小組引入了幾個很酷的注解類型,供開發者在工程中使用。Support Libr
[Cordova] 改進InAppBrowser插件(WebView),讓其(input type=file)支持選擇文件
1、支持幾乎所有安卓版本,從安卓2.x~7.0安卓4.4、4.4.1和4.4.2是無法支持的,因為當時Google說WebView上傳文件不安全,就去掉了。所以這3個版本
Android組件Glide實現圖片平滑滾動效果
Glide是一款基於Android的圖片加載和圖片緩存組件,它可以最大性能地在Android設備上讀取、解碼、顯示圖片和視頻。Glide可以將遠程的圖片、視頻、動畫圖片等
從零開始學android(Intent初步.四十.)
Intent意圖是android中非常重要的部分,他在Activity,service中有較為廣泛的應用。 1 public void startActiv