2

我正在制作一个简单的任务列表应用程序,并且我正在使用数据库来保存所有内容。我编写了一个自定义 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)

第 2 期

使用此 CursorAdapter 的 ListFragment 未执行其OnListItemClick()方法。同样,我已将 ListFragment 的 ListView 注册为使用 ContextMenu(带registerForContextMenu()),但长按不会调出上下文菜单。

第 3 期

取消注释taskCheckBox.setOnCheckedChangeListener通常会导致在选中复选框时发生不好的事情。通常,它会抛出空指针异常并崩溃,因为它不知道_id要调用什么checkOffTask()uncheckTask(). (编辑:最近编辑中所做的更改......仍然没有做我想要做的事情,但至少它不会崩溃。也很烦人getItemId()要求一个职位,我不知道该怎么做从光标中为 ListView 中的给定项目检索它,或者我会使用它。)


谁能帮我解决这些问题?尽管之前就这个问题寻求帮助,但我仍然不清楚 CursorAdapters 是如何工作的。

编辑:我应该注意到我的应用程序有另一个列表,它使用了一个非常轻微的调整ResourceCursorAdapter(见链接的问题),并且这些问题都没有出现在那里。(虽然问题 3 没有理由弹出,因为它是一个简单的字符串列表。)

4

2 回答 2

2

问题 1:

将跳过,因为它已解决。

问题 2:

如上一个问题所述,如果视图具有可聚焦对象,则由于 SDK 中的错误,不可能使整个视图可点击。因此,我进入了膨胀的 XML 并将属性添加android:focusable="false"到每个项目。列表项现在可以单击和长按。

问题 3:

正如reddit 上的一位好人所说,我在“旧方法”的正确轨道上,但需要使用本地final long而不是参数。

于 2012-06-26T23:01:17.583 回答
1

首先是随机建议。不要使用 getColumnIndex - 或者至少在某处缓存它。索引总是与投影中的顺序匹配,所以常见的模式是只使用它(所以如果你的投影是 ['_id', 'something', 'else'] 然后声明 INDX_ID = 0; INDX_SOMETHING = 1; 等等。 ..)

所以像这样创建匿名内部类并不是你能做的最高效的事情。我会改为执行以下操作:

使用 bindView 中的行 ID 或位置标记视图(如 reddit 上所述,这不是v.getID())。您可以使用 checkBoxView.setTag() 来做到这一点。这使您可以随意将数据标记到视图上。

然后,在新视图中注册检查更改侦听器 - 理想情况下传递一个静态类而不是匿名内部,但至少您将通过在 newView 中执行它来限制创建这些的频率。回调将使用 v.getTag() 来获取行 ID(或您在 bindView 中放入的任何其他内容)并可以使用它来执行您想要的任何工作

于 2012-06-28T04:32:10.563 回答