我正在创建一个简单的任务列表应用程序,我正在使用数据库来保存所有内容。我编写了一个自定义CursorAdapter,扩展了ResourceCursorAdapter来处理数据。一切都很好,但是一旦你开始超越它,事情会变得粗略。首先,我的实施:
import android.app.AlertDialog;
import android.content.Context;
import android.database.Cursor;
import android.support.v4.widget.ResourceCursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.Filterable;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* @author Dave Smith
*
*/
public class TaskCursorAdapter extends ResourceCursorAdapter {
/**
* @param context
* @param layout
* @param c
* @param from
* @param to
* @param flags
*/
private Context context;
private int layout, isCheckedFromDb, IdFromDb;
private Cursor cursor;
public TaskCursorAdapter(Context context, int layout, Cursor c,
int flags) {
super(context, layout, c, flags);
this.context = context;
this.layout = layout;
}
public TaskCursorAdapter(Context context, int layout){
super(context, layout, null, 0);
this.context = context;
this.layout = layout;
}
public TaskCursorAdapter(Context context, int layout, Cursor c){
super(context, layout, c, 0);
this.context = context;
this.layout = layout;
}
public TaskCursorAdapter(Context context, int layout, Cursor cursor, boolean autoRequery)
{
super(context, layout, cursor, autoRequery);
this.context = context;
this.layout = layout;
}
public View newView(Context context, Cursor cursor, ViewGroup parent){
final LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(layout, parent, false);
return v;
}
public void bindView(View v, Context context, Cursor c){
CheckBox taskCheckBox = (CheckBox)v.findViewById(R.id.taskCheckBox);
TextView taskText = (TextView)v.findViewById(R.id.taskTitle);
TextView taskNote = (TextView)v.findViewById(R.id.taskNote);
final long assignedID = v.getID();
//v.setClickable(true);
//LinearLayout holder = (LinearLayout)v.findViewById(R.id.container);
//holder.setClickable(true);
//IdFromDb = c.getInt(c.getColumnIndex(NagTasksDatabaseHelper.ID));
taskText.setText(c.getString(c.getColumnIndex(NagTasksDatabaseHelper.TASK)));
taskNote.setText(c.getString(c.getColumnIndex(NagTasksDatabaseHelper.NOTE)));
//isCheckedFromDb = c.getInt(c.getColumnIndex(NagTasksDatabaseHelper.CHECKED));
taskCheckBox.setChecked(c.getInt(c.getColumnIndex(NagTasksDatabaseHelper.CHECKED))==1);
//cursor = c;
taskCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//Really Old method:
/*NagTasksDatabaseHelper helper = new NagTasksDatabaseHelper(null);
int idCol = cursor.getColumnIndex(NagTasksDatabaseHelper.ID);
int taskID = helper.getNewTaskId();
if (idCol!=-1)
{
taskID= cursor.getInt(idCol);
if (isChecked){
helper.checkOffTask(taskID);
} else {
helper.uncheckTask(taskID);
}
}
//TODO Solve how to use helper to change ISCHECKED in database
helper.close();
//Old method:
NagTasksDatabaseHelper helper = new NagTasksDatabaseHelper(null);
if (isChecked) {
helper.checkOffTask(IdFromDb);
} else {
helper.uncheckTask(IdFromDb);
}
helper.close();*/
//Current method:
if (assignedID!=View.NO_ID) {
NagTasksDatabaseHelper helper = new NagTasksDatabaseHelper(buttonView.getContext());
if (isChecked) {
helper.checkOffTask(assignedID);
} else {
helper.uncheckTask(assignedID);
}
helper.close();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(buttonView.getContext());
builder.setMessage("No ID found. Try something else.");
builder.setCancelable(true);
builder.create().show();
}
}
});
}
}
编辑:问题已经解决,但我不知道如何。
在它的当前状态下,当我点击运行时,我在Eclipse的控制台中出现错误。它根本不会影响其运行情况,但在之前的实现中,我使用的布局只有CheckBox并且只更改了CheckBox的文本,但是没有出现此错误:
[2012-06-18 16:10:15 - ddms] null
java.lang.NullPointerException
at com.android.ddmlib.JdwpPacket.writeAndConsume(JdwpPacket.java:213)
at com.android.ddmlib.Client.sendAndConsume(Client.java:575)
at com.android.ddmlib.HandleHello.sendHELO(HandleHello.java:142)
at com.android.ddmlib.HandleHello.sendHelloCommands(HandleHello.java:65)
at com.android.ddmlib.Client.getJdwpPacket(Client.java:672)
at com.android.ddmlib.MonitorThread.processClientActivity(MonitorThread.java:317)
at com.android.ddmlib.MonitorThread.run(MonitorThread.java:263)
[2012-06-18 16:10:15 - ddms] null
java.lang.NullPointerException
at com.android.ddmlib.JdwpPacket.writeAndConsume(JdwpPacket.java:213)
at com.android.ddmlib.Client.sendAndConsume(Client.java:575)
at com.android.ddmlib.HandleHello.sendHELO(HandleHello.java:142)
at com.android.ddmlib.HandleHello.sendHelloCommands(HandleHello.java:65)
at com.android.ddmlib.Client.getJdwpPacket(Client.java:672)
at com.android.ddmlib.MonitorThread.processClientActivity(MonitorThread.java:317)
at com.android.ddmlib.MonitorThread.run(MonitorThread.java:263)
使用此CursorAdapter的ListFragment未执行其OnListItemClick()
方法。同样,我已经注册了ListFragment的ListView以使用ContextMenu(带registerForContextMenu()
),但是长按不会显示上下文菜单。
取消注释taskCheckBox.setOnCheckedChangeListener
通常会在选中复选框时导致不良事件发生。通常,它会抛出空指针异常并崩溃,因为它不知道调用_id
或checkOffTask()
的{{1}}。 (编辑:在最近的编辑中所做的更改...仍然没有做我想要它做的事情,但至少它不会崩溃。也烦恼uncheckTask()
请求一个位置,我不知道如何从光标中检索ListView中的给定项目,或者我会使用它。)
有人可以帮我解决这些问题吗?尽管有asking for help on this subject before,我仍然不清楚CursorAdapters是如何工作的。
编辑我应该注意到我的应用程序有另一个列表,它使用了一个非常轻微的调整getItemId()
(参见链接的问题),并且没有出现这些问题。 (虽然问题3没有理由弹出,因为它是一个简单的字符串列表。)
答案 0 :(得分:2)
将跳过,因为它已经解决了。
如this previous question所述,如果视图具有可聚焦对象,则由于SDK中的错误,无法使整个视图可点击。所以,我进入了膨胀的XML并为每个项添加了属性android:focusable="false"
。列表项目现在可以点击并且可以长按。
正如a nice fellow on reddit所述,我使用“旧方法”走在正确的轨道上,但需要使用本地final long
代替参数。
答案 1 :(得分:1)
首先随机提出建议。不要使用getColumnIndex - 或者至少在某处缓存。索引始终与投影中的顺序匹配,因此常见模式只是使用它(因此,如果您的投影是['_id','something','else'],则声明INDX_ID = 0; INDX_SOMETHING = 1;等等。 ..)
因此,创建这样的匿名内部类并不是您可以做的最高效的事情。我会改为做以下事情:
使用bindView中的行ID或位置标记视图(如reddit中所述,这是不 v.getID())。您可以使用checkBoxView.setTag()来实现。这允许您随意将数据标记到视图上。
然后,在新视图中注册检查更改侦听器 - 理想情况下传递静态类而不是匿名内部,但至少您将限制在newView中执行此操作的频率。回调将使用v.getTag()来获取行ID(或者你在bindView中放置的任何其他内容),并且可以使用它来执行你想要的任何工作