Android:ListView位置和DatePicker

3

我有一个onItemClickListener用于ListView,当项目被点击时会打开DatePicker对话框:

list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        showDatePickerDialog(view);
    }
});

public void showDatePickerDialog(View v) {
    DialogFragment newFragment = new DatePickerFragment();
    newFragment.show(getFragmentManager(), "datePicker");
}

在DatePicker中设置日期后,我有一个onDateSet方法,我想使用它来更新数据库并设置ListView中所点击项目的日期:

public void onDateSet(DatePicker view, int year, int month, int day) {
    ...
    dataSource.updateDate(adapter.getItemId(position), month + "/" + day + "/" + year);
    ...
} 

如何将被点击的项目的 ListView 位置 传递给 onDateSet ,以便我的数据库帮助程序知道要更新哪条记录?


编辑: 这是 DatePickerFragment 类:

public static class DatePickerFragment extends DialogFragment
        implements DatePickerDialog.OnDateSetListener {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Use the current date as the default date in the picker
        final Calendar c = Calendar.getInstance();
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH);
        int day = c.get(Calendar.DAY_OF_MONTH);

        // Create a new instance of DatePickerDialog and return it
        return new DatePickerDialog(getActivity(), this, year, month, day);
    }

    public void onDateSet(DatePicker view, int year, int month, int day) {
        ...
        dataSource.updateDate(adapter.getItemId(position), month + "/" + day + "/" + year);
        ...
    }
}

谢谢!

2个回答

1
position 发送到 DatePickerFragment - 我猜这是你自己的类。通过参数发送此参数(作为在片段重建中保护代码的最佳实践):
public class DatePickerFragment extends Fragment {

    private DatePickerListener datePickerListener;
    private int listPosition = -1;
    private static final String POSITION_ARG_KEY = "POSITION_ARG_KEY";

    public static DatePickerFragment newInstance(int position) {
        DatePickerFragment fragment = new DatePickerFragment();
        Bundle args = new Bundle();
        args.putInt(POSITION_ARG_KEY, position);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        if (args != null) {
            listPosition = args.getInt(POSITION_ARG_KEY);
        }
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (activity instanceof DatePickerListener) {
            datePickerListener = (DatePickerListener) activity;
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        datePickerListener = null;
    }

    public void methodThatCallsActivity() {
        if(datePickerListener) {
            datePickerListener.onDateSet(datePicker, year, month, day, this.listPosition);
        }
    }

    // / the rest of the code

    public static interface DatePickerListener {
        public void onDateSet(DatePicker view, int year, int month, int day, int listPosition);
    }
}

然后在显示该片段的活动中(必须实现DatePickerListener),

A. 发送列表位置:

public void showDatePickerDialog(int listPosition) {
    DialogFragment newFragment = DatePickerFragment.newInstance(listPosition);
    newFragment.show(getFragmentManager(), "datePicker");
}

B. 在列表项的点击事件中调用此方法:

list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        showDatePickerDialog(position);
    }
});

C. 在 onDateSet 实现中,您拥有列表位置:

public void onDateSet(DatePicker view, int year, int month, int day, int listPosition) {
    // your relevant code
}

简述:通过参数将列表视图中的列表位置从listview发送到fragment,再从fragment发送到父activity。

当我尝试将位置传递给onDateSet时,我收到一条消息,说我需要实现抽象方法onDateSet(DatePicker, int, int, int)。由于我正在实现DatePickerDialog.OnDateSetListener,它不喜欢我向方法签名添加另一个参数。有没有办法在扩展DialogFragment并实现DatePickerDialog.OnDateSetListener的同时完成它?如果我无法弄清楚,我会尝试您的方法,谢谢! - Alex
onDateSet(DatePicker, int, int, int) 属于您定义的接口吗?还是 Android 定义的? - gunar
DatePickerDialog.OnDateSetListener中,它是由Android定义的。 - Alex
然后创建一个新的接口LocalDatePickerListener并使用我描述的相同方法。不同之处在于DatePickerListener由片段实现,而LocalDatePickerListener将由宿主活动实现。 - gunar

0
通过以下方式解决了这个问题:
DatePickerFragment作为自己的类(而不是嵌套在MainActivity类中):
public class DatePickerFragment extends DialogFragment {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Use the current date as the default date in the picker
        final Calendar c = Calendar.getInstance();
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH);
        int day = c.get(Calendar.DAY_OF_MONTH);

        // Create a new instance of DatePickerDialog and return it
        return new DatePickerDialog(getActivity(), (MainActivity)getActivity(), year, month, day);
    }
}

这就是我的MainActivity类最终的样子:

public class MainActivity extends ListActivity implements DatePickerDialog.OnDateSetListener {
    private long listId = -1;
    private int listPosition = -1;
    private String date;
    ...

    protected void onCreate(Bundle savedInstanceState) {
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                listId = id;
                listPosition = position;
                showDatePickerDialog(view);
    ...

    // Show DatePicker when clicking on contact in ListView
    public void showDatePickerDialog(View view) {
        DialogFragment newFragment = new DatePickerFragment();
        newFragment.show(getFragmentManager(), "datePicker");
    }

    // Update database and ListView adapter with selected date
    public void onDateSet(DatePicker view, int year, int month, int day) {
        date = (month + 1) + " " + day + ", " + year;
        ...
        dataSource.updateDate(listId, date);
        adapter.setDate(listPosition, date);
        ...
        adapter.notifyDataSetChanged();
        dataSource.close();
    }

附注:按下DatePicker的取消按钮(以及Android返回按钮)仍会将默认日期保存到数据库并更新适配器。这里有一篇帖子可以解决这个问题:https://dev59.com/OW_Xa4cB1Zd3GeqP0WFs#15289569


1
如果窗口同时打开,你接到一个电话或任何使你的活动进入后台的操作,那么该活动就有资格被销毁。如果它被销毁,然后重新创建活动,则listId将重置为零。而且,在状态流中依赖于字段状态是一种不好的做法。要通过参数而不是状态感知来维护数据通信。 - gunar
如果活动被销毁,listId 重置有什么关系呢?当用户再次选择 ListView 行时,它会被适当地设置,对吗?不过,我理解你的观点,依赖字段状态是不好的做法。你有没有想过通过参数传递位置/ID 来修复当前的方法呢?谢谢。 - Alex
我在谈论打开对话框的情况 - 实际上,显示对话框的片段已经添加并可见。因此,在这一点上,您有一个列表ID,假设为10。当在此状态下销毁并恢复活动时,对话框将打开(Android会处理它),而listId为...零!这个问题的作者必须更改当前的'onDateSet',使其接受额外的int - 列表位置。 - gunar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接