1

我正在做一个家庭作业计划器的应用程序,我正在寻找一种方法来显示一个ArrayList中只有某些元素持有任务对象。用户从课程名称列表中单击课程后,应显示与该课程有关的任务列表。目前,它显示了所有任务的列表,不管选择了哪个课程。每个Task对象都将其所属课程存储在名为mBelongsToCourse的字段中。我在我的TaskAdapter中创建了一个过滤器来按课程名称进行过滤,但我不知道在哪里调用它来使其工作。我在这里广泛搜索了这个问题的答案,但在每个有人过滤ArrayAdapter的情况下,似乎过滤器正在响应某些用户输入,如搜索。在我的情况下,当用户选择一个课程时,用户输入只是课程名称的附加内容,该课程意图显示我的TaskListFragment,但只应显示该课程的任务。在哪里调用ArrayAdapter的过滤器?

下面是我的TaskListFragment类,其中包括TaskAdapter和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(); 
      } 
     } 
    } 
} 
} 

任何帮助将不胜感激!我一直试图解决这个问题的时间太长了,而且我还是完全迷失了。

编辑:我已经取出来的一切与我原来的过滤器做的,我不是使用此方法在我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; 
} 

要过滤的任务。在TaskListFragment的onCreate方法,我已经添加下面的中间线:

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

,我也做了logcat的打印任务列表中filteredTasks(仍然在onCreate方法)。所以当我点击课程时,添加一个任务,然后回到TaskListFragment,我得到属于该课程的任务的打印输出。而且每个课程的名单都保持独立!对于我来说,在过去一周试图做到这一点并且看不到任何结果之后,对我来说这是一个很大的进步。不过,我看到了每个课程页面上的所有任务,而不是过滤的任务。这只是我的listView没有更新的问题?

+0

*开始意图显示我的TaskListFragment,* - 发送到您的TaskListFragment(通过创建时的Bundle)目标课程并将其传递给TaskAdapter类。在TaskAdapter的构造函数中,只需筛选任务列表。如果您不想在使用适配器时更改适配器,则无需实施“过滤器”(当您首次显示该片段时,您似乎不想过滤(只有一次?) )。 – Luksprog

+0

嗨Luksprog,非常感谢您的回答!目前,我从CourseListFragment向TaskListFragment发送了一个额外的意图,它是已被点击的课程的名称。所以我也应该把它传递给我的TaskAdapter?目前,因为它们都在同一个类中,所以包含课程名称的字段可以由TaskAdapter访问,并且我试图直接在构造函数中过滤结果,但是仍然可以获得完整的任务列表,无论当然我点击。 – Elizabeth

+0

有没有什么办法可以给我更详细的说明,我应该做什么,因为我觉得我必须忽略一些我没有意识到的重要方面,因为我对android很陌生。 – Elizabeth

回答

0

在onCreate方法中,您将先前Activity的所有任务都传递给Adapter,然后将其设置为您的ListView,为什么在将它们传递给适配器之前不过滤您的任务?尽管为了避免阻塞UI太长时间,应该在不同的线程中完成繁重的工作,当您开始初始化列表以及过滤器被隐藏时显示progressDialog。

我的意思是如果你膨胀ListView,将它的适配器设置为包含所有任务的列表,如果你想在初始化之后修改列表,应该在设置适配器之前进行修改,以避免在其上放置额外的项目。如果仍想这样做,请将过滤器应用于任务列表,然后调用适配器的notifyDataSetChanged()更改项目。恕我直言,我会更改任务列表,然后再将其传递给适配器以避免这种情况。如果你有UI冻结使用不同的线程。

+0

好吧,我已经拿掉了所有与我的过滤器,并在TaskAdapter中创建了一个方法,按课程名称过滤任务。然后,在TaskListFragment的onCreate方法中,我添加了下面的中间行: TaskAdapter adapter = new TaskAdapter(mTasks); adapter.filterTasks(); setListAdapter(adapter); 这是你的意思吗?我不需要调用notifyDataSetChanged()如果我摆脱了实际的过滤器,对吧? – Elizabeth

+0

你越来越近了。将此方法放入适配器将阻止UI,如果发现UI冻结,则将其放入另一个线程。我是一个非常完美主义的开发人员,我会将该方法放在另一个类中或作为TaskListFragment中的私有方法,实际上我没有看到Adapter类作为它的位置......但是,实质上,这就是我的意思。如果它解决你的问号,我的答案是正确的,请。 – Angmar

+0

好吧,我将filterTasks()方法移入TaskListFragment。 而在我的onCreate()中,对此进行了修改: ArrayList filteredTaskList = filterTasks(mTasks); TaskAdapter adapter = new TaskAdapter(filteredTaskList); 但现在,我的TaskListFragment没有显示任何任务。 LogCat确认任务正在保存,但没有任何课程显示。我尝试过这样做,并且陷入了没有任何任务显示的事实。 – Elizabeth

相关问题