나는 커스텀 CursorAdapter의 코드가 만족 스러울 때까지는 리뷰를 작성하지 않고 오랫동안 나를 괴롭혔던 약간의 문제를 수정했다. (흥미롭게도, 내 앱 사용자 중 누구도 그런 문제를보고하지 않았다.).안드로이드 용으로 적절히 코딩 된 ListView에 대한이 커스텀 커서 어댑터입니까?
이내 사용자 정의 CursorAdapter 내가 볼 예제들은 newView()
및 bindView()
대신 getView()
오버라이드 (override) :
여기에 내 질문의 작은 설명입니다. 나는이 두 가지 방법 사이에서 ViewHolder 패턴을 사용한다. 하지만 내 주요 문제는 내가 각 목록 항목에 사용하고있는 사용자 정의 레이아웃과 함께, 그것은 ToggleButton
가 포함되어 있습니다.
목록 항목보기가 스크롤되지 않고 스크롤 된 다음보기로 돌아갈 때 단추 상태가 유지되지 않는 것이 문제였습니다. 이 문제는 cursor
이 ToggleButton
을 눌렀을 때 데이터베이스 데이터가 변경되었음을 전혀 알지 못했기 때문에 존재했으며 항상 동일한 데이터를 가져오고있었습니다. ToggleButton
을 클릭 할 때 커서를 다시 쿼리하려고 시도했지만 문제가 해결되었지만 속도가 매우 느려졌습니다.
나는이 문제를 해결했으며 리뷰를 위해 전체 수업을 게시하고 있습니다. 필자는 코딩 결정을보다 잘 설명하기 위해이 특정 질문에 대한 코드를 철저히 설명했습니다.
이 코드가 좋게 보입니까? 어떻게 개선 시키거나 최적화 시키거나 변경할 것입니까?
P.S : CursorLoader가 분명히 개선되었음을 알고 있지만 당분간 큰 코드 재 작성을 처리 할 시간이 없습니다. 그것은 내가 로드맵에서 가지고있는 것입니다.
여기에 코드입니다 :
public class NotesListAdapter extends CursorAdapter implements OnClickListener {
private static class ViewHolder {
ImageView icon;
TextView title;
TextView description;
ToggleButton visibility;
}
private static class NoteData {
long id;
int iconId;
String title;
String description;
int position;
}
private LayoutInflater mInflater;
private NotificationHelper mNotificationHelper;
private AgendaNotesAdapter mAgendaAdapter;
/*
* This is used to store the state of the toggle buttons for each item in the list
*/
private List<Boolean> mToggleState;
private int mColumnRowId;
private int mColumnTitle;
private int mColumnDescription;
private int mColumnIconName;
private int mColumnVisibility;
public NotesListAdapter(Context context, Cursor cursor, NotificationHelper helper, AgendaNotesAdapter adapter) {
super(context, cursor);
mInflater = LayoutInflater.from(context);
/*
* Helper class to post notifications to the status bar and database adapter class to update
* the database data when the user presses the toggle button in any of items in the list
*/
mNotificationHelper = helper;
mAgendaAdapter = adapter;
/*
* There's no need to keep getting the column indexes every time in bindView() (as I see in
* a few examples) so I do it once and save the indexes in instance variables
*/
findColumnIndexes(cursor);
/*
* Populate the toggle button states for each item in the list with the corresponding value
* from each record in the database, but isn't this a slow operation?
*/
for(mToggleState = new ArrayList<Boolean>(); !cursor.isAfterLast(); cursor.moveToNext()) {
mToggleState.add(cursor.getInt(mColumnVisibility) != 0);
}
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = mInflater.inflate(R.layout.list_item_note, null);
/*
* The ViewHolder pattern is here only used to prevent calling findViewById() all the time
* in bindView(), we only need to find all the views once
*/
ViewHolder viewHolder = new ViewHolder();
viewHolder.icon = (ImageView)view.findViewById(R.id.imageview_icon);
viewHolder.title = (TextView)view.findViewById(R.id.textview_title);
viewHolder.description = (TextView)view.findViewById(R.id.textview_description);
viewHolder.visibility = (ToggleButton)view.findViewById(R.id.togglebutton_visibility);
/*
* I also use newView() to set the toggle button click listener for each item in the list
*/
viewHolder.visibility.setOnClickListener(this);
view.setTag(viewHolder);
return view;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
Resources resources = context.getResources();
int iconId = resources.getIdentifier(cursor.getString(mColumnIconName),
"drawable", context.getPackageName());
String title = cursor.getString(mColumnTitle);
String description = cursor.getString(mColumnDescription);
/*
* This is similar to the ViewHolder pattern and it's need to access the note data when the
* onClick() method is fired
*/
NoteData noteData = new NoteData();
/*
* This data is needed to post a notification when the onClick() method is fired
*/
noteData.id = cursor.getLong(mColumnRowId);
noteData.iconId = iconId;
noteData.title = title;
noteData.description = description;
/*
* This data is needed to update mToggleState[POS] when the onClick() method is fired
*/
noteData.position = cursor.getPosition();
/*
* Get our ViewHolder with all the view IDs found in newView()
*/
ViewHolder viewHolder = (ViewHolder)view.getTag();
/*
* The Html.fromHtml is needed but the code relevant to that was stripped
*/
viewHolder.icon.setImageResource(iconId);
viewHolder.title.setText(Html.fromHtml(title));
viewHolder.description.setText(Html.fromHtml(description));
/*
* Set the toggle button state for this list item from the value in mToggleState[POS]
* instead of getting it from the database with 'cursor.getInt(mColumnVisibility) != 0'
* otherwise the state will be incorrect if it was changed between the item view scrolling
* out of view and scrolling back into view
*/
viewHolder.visibility.setChecked(mToggleState.get(noteData.position));
/*
* Again, save the note data to be accessed when onClick() gets fired
*/
viewHolder.visibility.setTag(noteData);
}
@Override
public void onClick(View view) {
/*
* Get the new state directly from the toggle button state
*/
boolean visibility = ((ToggleButton)view).isChecked();
/*
* Get all our note data needed to post (or remove) a notification
*/
NoteData noteData = (NoteData)view.getTag();
/*
* The toggle button state changed, update mToggleState[POS] to reflect that new change
*/
mToggleState.set(noteData.position, visibility);
/*
* Post the notification or remove it from the status bar depending on toggle button state
*/
if(visibility) {
mNotificationHelper.postNotification(
noteData.id, noteData.iconId, noteData.title, noteData.description);
} else {
mNotificationHelper.cancelNotification(noteData.id);
}
/*
* Update the database note item with the new toggle button state, without the need to
* requery the cursor (which is slow, I've tested it) to reflect the new toggle button state
* in the list because the value was saved in mToggleState[POS] a few lines above
*/
mAgendaAdapter.updateNote(noteData.id, null, null, null, null, visibility);
}
private void findColumnIndexes(Cursor cursor) {
mColumnRowId = cursor.getColumnIndex(AgendaNotesAdapter.KEY_ROW_ID);
mColumnTitle = cursor.getColumnIndex(AgendaNotesAdapter.KEY_TITLE);
mColumnDescription = cursor.getColumnIndex(AgendaNotesAdapter.KEY_DESCRIPTION);
mColumnIconName = cursor.getColumnIndex(AgendaNotesAdapter.KEY_ICON_NAME);
mColumnVisibility = cursor.getColumnIndex(AgendaNotesAdapter.KEY_VISIBILITY);
}
}
나는 SparseArray라는 아이디어를 좋아했고, 그 클래스에 대해 몰랐다. 이것은 버튼 상태를 모두'List'에 저장하는 대신에보다 효율적으로 캐싱하는 방법입니다. 하지만 사용자가 작업을 떠날 때 결과를 데이터베이스에 커밋하기를 좋아하지 않습니다. 그 상황을 처리하려면 추가 코드가 필요합니다. 결국, 당신이 열거 한 두 번째 해결책을 선택하고있는 것 같습니다. 기본적으로 내가 처음에 무엇을했는지. 나는 아직도 당신의 대답을 좋아하지만 아마도 1 ~ 2 일 더 가고 있습니다 :) –