質問

I'm working on a homework planner app, and I'm looking for a way to display only certain elements in an ArrayList that holds Task objects. After the user clicks on a course from a list of course titles, the list of tasks that pertain to that course should be displayed. Currently, it shows a list of all tasks, no matter which course has been selected. Each Task object stores the course that it belongs to, in a field called mBelongsToCourse. I created a Filter in my TaskAdapter to filter by course name, but I don't know where to call it to make it work. I've searched for answers to this issue extensively on here, but in every case where someone is filtering an ArrayAdapter, it seems like the filter is responding to some user input such as a search. In my case, the user input is just the intent extra of the course name when the user selects a course, which starts an intent to show my TaskListFragment, but should only show tasks for that course.

Below is my TaskListFragment Class, which includes the TaskAdapter and TaskFilter:

public class TaskListFragment extends ListFragment {

private ArrayList<Task> mTasks;
private  static String courseName;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    courseName = getActivity().getIntent().getStringExtra("name");
    getActivity().setTitle(courseName);
    mTasks = TaskLab.get(getActivity()).getTasks();

    TaskAdapter adapter = new TaskAdapter(mTasks);
    setListAdapter(adapter);
}

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    //Get the Task from the adapter
    Task t = ((TaskAdapter)getListAdapter()).getItem(position);
    // Start TaskActivity with this task
    //Intent i = new Intent(getActivity(), TaskPagerActivity.class);
    Intent i = new Intent(getActivity(), TaskActivity.class);
    i.putExtra(TaskFragment.EXTRA_TASK_ID, t.getId());
    startActivity(i);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    inflater.inflate(R.menu.fragment_task_list, menu);
} 

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.menu_item_new_task:
        Task task = new Task();
        task.setBelongsToCourse(courseName);
        Log.d("yoyo", "belongsToCourse was set as: " + task.getBelongsToCourse());
        TaskLab.get(getActivity()).addTask(task);
        Intent i = new Intent(getActivity(), TaskActivity.class);
        i.putExtra(TaskFragment.EXTRA_TASK_ID, task.getId());
        startActivityForResult(i, 0);
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    getActivity().getMenuInflater().inflate(R.menu.task_list_item_context, menu);
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
        Bundle savedInstanceState) {
    View v = super.onCreateView(inflater, parent, savedInstanceState);
    ListView listView = (ListView)v.findViewById(android.R.id.list);
    listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);

    listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {

        public void onItemCheckedStateChanged(ActionMode mode, int position,
                long id, boolean checked) {
            // Required, but not used in this implementation
        }

        // ActionMode.Callback methods
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            MenuInflater inflater = mode.getMenuInflater();
            inflater.inflate(R.menu.task_list_item_context, menu);
            return true;
        }

        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false;
            // Required, but not used in this implementation
        }
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            switch (item.getItemId()) {
            case R.id.menu_item_delete_task:
                TaskAdapter adapter = (TaskAdapter)getListAdapter();
                TaskLab taskLab = TaskLab.get(getActivity());
                for (int i = adapter.getCount() - 1; i >= 0; i--) {
                    if (getListView().isItemChecked(i)) {
                        taskLab.deleteTask(adapter.getItem(i));
                    }
                }
                mode.finish();
                adapter.notifyDataSetChanged();
                return true;
            default:
                return false;
            }
        }

        public void onDestroyActionMode(ActionMode mode) {
            // Required, but not used in this implementation
        }
    });
    return v;
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
    int position = info.position;
    TaskAdapter adapter = (TaskAdapter)getListAdapter();
    Task task = adapter.getItem(position);

    switch (item.getItemId()) {
    case R.id.menu_item_delete_task:
        TaskLab.get(getActivity()).deleteTask(task);
        adapter.notifyDataSetChanged();
        return true;
    }
    return super.onContextItemSelected(item);
}


@Override
public void onResume() {
    super.onResume();
    ((TaskAdapter)getListAdapter()).notifyDataSetChanged();
}

private class TaskAdapter extends ArrayAdapter<Task> implements Filterable {

    private ArrayList<Task> taskList;
    private Filter taskFilter;

    public TaskAdapter(ArrayList<Task> tasks) {
        super(getActivity(), 0, tasks);
        this.taskList = tasks;
        this.taskFilter = new TaskFilter();
        getFilter().filter(courseName);
        notifyDataSetChanged();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // If we weren't given a view, inflate one
        if (convertView == null) {
            convertView = getActivity().getLayoutInflater()
                    .inflate(R.layout.list_item_task, null);
        }

        // Configure the view for this Task
        Task t = getItem(position);

        TextView titleTextView =
                (TextView)convertView.findViewById(R.id.task_list_item_titleTextView);
        titleTextView.setText(t.getTitle());
        TextView dateTextView =
                (TextView)convertView.findViewById(R.id.task_list_item_dateTextView);
        dateTextView.setText(t.getDate().toString());
        CheckBox completedCheckBox =
                (CheckBox)convertView.findViewById(R.id.task_list_item_completedCheckBox);
        completedCheckBox.setChecked(t.isCompleted());
        return convertView;
    }

    @Override
    public Filter getFilter() {
        if (taskFilter == null)
            taskFilter = new TaskFilter();
        return taskFilter;
    }

    private class TaskFilter extends Filter {

        @Override
        protected FilterResults performFiltering (CharSequence constraint) {
            FilterResults results = new FilterResults();
            if (constraint == null | constraint.length() == 0) {
                results.values = taskList;
                results.count = taskList.size();
            } else {
                ArrayList<Task> newTaskList = new ArrayList<Task>();
                for (Task t : taskList) {
                    if (t.getBelongsToCourse().toUpperCase().equals(constraint.toString().toUpperCase())) {
                        newTaskList.add(t);
                    }
                }
                results.values = newTaskList;
                results.count = newTaskList.size();
            } return results;
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint,
                FilterResults results) {

            // Now we have to inform the adapter about the new list filtered
            if (results.count == 0)
                notifyDataSetInvalidated();
            else {
                taskList = (ArrayList<Task>)results.values;
                notifyDataSetChanged();
            }
        }
    }
}
}

Any help would be greatly appreciated! I have been trying to solve this problem for far too long, and I'm still completely lost.

EDIT: I've taken out everything to do with my original Filter, and am instead using this method in my TaskAdapter:

public ArrayList<Task> filterTasks() {
     ArrayList<Task> filteredTasks = new ArrayList<Task>();
     for (Task t: taskList) {
          if (t.getBelongsToCourse().equals(courseName)) {
               filteredTasks.add(t);
          }
     } return filteredTasks;
}

To filter the tasks. In the onCreate method of TaskListFragment, I've added the middle line below:

TaskAdapter adapter = new TaskAdapter(mTasks);
adapter.filterTasks();
setListAdapter(adapter);

I've also made LogCat print out the list of tasks in filteredTasks (still in the onCreate method). So when I click on a course, add a task, then go back to the TaskListFragment, I get a printout of the tasks that belong to that course. And the lists are staying separate for each course! This is great progress for me so far after muddling through trying to do this for the past week and seeing no results. Still, though, I'm seeing all of the tasks on every course page, not the filtered tasks. Is this just an issue of my listView not updating?

役に立ちましたか?

解決

In the onCreate method you pass all the tasks of the previous Activity on to your Adapter then set it to your ListView, why don't you filter your tasks before passing them to the adapter? the heavy work should be done in a different thread though to avoid blocking the UI for too long, show a progressDialog when you start initializing the List and when it's filtered hide it.

I mean if you inflate the ListView, set it's Adapter to it with the list that contains all tasks, if you want to modify the List after initializing you should do it before setting the Adapter, to avoid putting extra items on it. If you still want to do it so, apply the filter to the task list, then call notifyDataSetChanged() for the Adapter to change items. IMHO I would change the List of Tasks before passing it to the Adapter to avoid this. If you have UI freezing use a different thread.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top