【问题标题】:Filtering a listview based on fields not displayed in listview根据列表视图中未显示的字段过滤列表视图
【发布时间】:2016-02-08 20:04:19
【问题描述】:

我目前有一个应用程序,它从互联网上抓取一个 json 文件,对其进行解析并从中创建项目对象。项目具有以下字段:类型(图像,文本)和数据(如果项目类型为图像,则为 url;如果项目类型为文本,则为文本字符串)

当应用首次加载时,列表会显示所有项目的混合类型,包括文本和图像。如果item是图片,listview的list item中只显示图片,如果是文本则显示文本。

我需要它来做(并且遇到问题)是我需要它,这样当用户从菜单“仅图像”中选择时,它只会在列表视图中显示类型为“图像”的对象并隐藏“文本”类型的项目,如果他们选择“仅文本”,则它会过滤掉所有图像列表项目并仅显示“文本”类型的项目。如果他们选择“全部”,它应该像应用首次加载时一样显示默认值。

我不在任何地方的列表视图上显示此对象的类型字段,只是对象的数据字段,它可以是从 url 或文本加载的图像。似乎我遇到的每个过滤示例都是当有人键入文本时它会过滤列表但该文本显示在列表中并且在列表中可见我需要过滤的内容在列表中不可见..我不是很确定如何完成我所需要的。有没有人有任何想法?希望我解释得足够好

编辑:这是我目前所拥有的。现在,当我从菜单中选择图像时它起作用,当我从菜单中选择文本时它起作用,当我切换回所有它是空白并且 mitems.size 为零时,即使我从未从中删除任何东西。

在创建时:

 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    tvNoInet=(TextView)findViewById(android.R.id.empty);
    setSupportActionBar(toolbar);
    if (isNetworkAvailable()) {
        getData theJsonData = new getData();
        theJsonData.execute();
    }

    myListView = (ListView) findViewById(R.id.listViewID);
    customAdapter = new ListAdapter(MainActivity.this, R.layout.list,mItems);
    myListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            if (mItems.get(position).getmType().toString().equals("text")){
                if (isNetworkAvailable()) {
                    Intent in = new Intent(MainActivity.this, MyWebView.class);
                    startActivity(in);
                }
                else{
                    Toast.makeText(getApplicationContext(), "No internet connection, try again later", Toast.LENGTH_SHORT).show();
                }

            }
            if (mItems.get(position).getmType().toString().equals("image")){
                Intent in = new Intent(MainActivity.this,FullImage.class);
                in.putExtra("imageURL",mItems.get(position).getmData().toString());
                startActivity(in);
            }
        }
    });


}

他们从选项之一(全部、图像、文本)中选择的“我的选项”菜单

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_about) {
        Intent intent = new Intent(this, About.class);
        startActivity(intent);
        return true;
    }

    if (id == R.id.all) {
        item.setChecked(true);
        customAdapter.clear();
        customAdapter.addAll(mItems);
        return true;

    }
    if (id == R.id.images) {
        item.setChecked(true);
        customAdapter.clear();
        customAdapter.addAll(mImageItems);
        return true;

    }
    if (id == R.id.text) {
        item.setChecked(true);
        customAdapter.clear();
        customAdapter.addAll(mTextItems);
        return true;
    }

    return super.onOptionsItemSelected(item);
}

我的任务是抓取 json,解析它,创建对象,然后将其添加到 mItems,如果类型是图像,也将其添加到 mImageItems,如果类型是文本,则将其添加到 mTextItems。

public class getData extends AsyncTask<String, Void, String> {
    String jsonStr = null;
    ProgressDialog progress = new ProgressDialog(MainActivity.this);
    @Override
    protected String doInBackground(String... params) {
        HttpURLConnection urlConnection = null;
        BufferedReader reader = null;

        try {
            URL url = new URL("http://host/data.json");
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();
            InputStream inputStream = urlConnection.getInputStream();
            StringBuffer buffer = new StringBuffer();
            if (inputStream == null) {
                return null;
            }
            reader = new BufferedReader(new InputStreamReader(inputStream));

            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line + "\n");
            }

            if (buffer.length() == 0) {
                return null;
            }
            jsonStr = buffer.toString();
        } catch (IOException e) {
            Log.e("MAIN", "Error ", e);
            return null;
        } finally{
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (final IOException e) {
                    Log.e("PlaceholderFragment", "Error closing stream", e);
                }
            }
        }
        try {

            JSONArray itemsArray = new JSONArray(jsonStr);

            String itemID=null;
            String itemType=null;
            String itemDate=null;
            String itemData=null;
            for (int i = 0; i < itemsArray.length(); i++) {
                JSONObject jsonItem=itemsArray.getJSONObject(i);
                if (jsonItem.has("id")){
                    itemID=jsonItem.getString("id");
                }
                if (jsonItem.has("type")){
                    itemType=jsonItem.getString("type");
                }
                if (jsonItem.has("date")){
                    itemDate=jsonItem.getString("date");
                }
                if (jsonItem.has("data")){
                    itemData=jsonItem.getString("data");
                }
                Item myItem=new Item(itemID,itemType,itemDate,itemData);
                mItems.add(myItem);
                if (itemType.equals("image")){
                    mImageItems.add(myItem);
                }
                else if (itemType.equals("text")){
                    mTextItems.add(myItem);
                }




            }
            Log.e("ALL SIZE: ", String.valueOf(mItems.size()));
            Log.e("TEXT SIZE: ", String.valueOf(mTextItems.size()));
            Log.e("IMAGE SIZE: ", String.valueOf(mImageItems.size()));
        } catch (JSONException jsone) {
            jsone.printStackTrace();
            Log.e(LOG_TAG, "Error processing Json Data");
        }

最后是我的适配器:

class ListAdapter extends ArrayAdapter<Item>  {
   private List<Item> items;

    public ListAdapter(Context context, int textViewResourceId) {
        super(context, textViewResourceId);

    }

    public ListAdapter(Context context, int resource, List<Item> items) {

        super(context, resource, items);

        this.items = items;

    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View v = null;
        TextView tn = null;
        ImageView img = null;

        if (convertView == null) {
            LayoutInflater vi;
            vi = LayoutInflater.from(getContext());
            v = vi.inflate(R.layout.list, null);
        }
        else {
            v=convertView;
        }

        Item p = items.get(position);
        tn = (TextView) v.findViewById(R.id.tvText);
        img = (ImageView) v.findViewById(R.id.thumbnail);
            if (p.getmType().equals("image")) {
                img.setVisibility(View.VISIBLE);
                Picasso.with(getContext()).load(p.getmData()).error((R.drawable.placeholder_error)).placeholder(R.drawable.placeholder).resize(90,0).into(img);
                tn.setText("ID: " + p.getmID()+"\nTYPE: " + p.getmType() +"\nDate: " + p.getmDate()+ "\nDATA: " +  p.getmData());
            } else {
                img.setVisibility(View.INVISIBLE);
                tn.setText("ID: " + p.getmID()+"\nTYPE: " + p.getmType() +"\nDate: " + p.getmDate()+ "\nDATA: " +  p.getmData());
            }
        return v;
    }
}

现在当应用程序加载混合列表时显示所有项目,如果我从菜单中选择“图像”,那么只有图像类型显示在列表中,如果我选择“文本”,则只有文本项目显示并且我可以在图像和文本之间来回切换。但是,当我再次选择“全部”时,列表为空白且 mItems.size 为 0。我对此感到头疼。哈哈 我发现的一种方法是当我将 Item 对象添加到列表时,我有一个名为 mAllItems 的第四个列表,它基本上设置为与 mItems 完全相同,所以我在哪里做 mItems.add(myItem);下一行是 mAllItems.add(myItem),在菜单选择中我只是将 All 设置为 mAllItems。我知道我可能做错了,但你必须以某种方式学习对吗?

【问题讨论】:

  • 您是否尝试仅更改适配器的数据集?
  • 我不知道该怎么做。我仍在学习,这是我使用带有适配器的列表视图并使用对象填充列表的第一个应用程序。有没有办法将适配器设置为 mItems 中类型等于一个或另一个的所有项目?

标签: android listview object android-arrayadapter


【解决方案1】:

我认为你很接近。

您已经有三个列表。由于适配器是 ListView 的模型,因此在适配器中包含这些列表会更有意义。

public class ListAdapter extends BaseAdapter {

    public enum ListMode {
        IMAGES_AND_TEXT,
        IMAGES_ONLY,
        TEXT_ONLY
    }

    private ListMode mListMode = ListMode.IMAGES_AND_TEXT;

    private List<Item> mItems;

    private List<Item> mImages;

    private List<Item> mTexts;

    @Override
    public int getCount() {
        switch (mListMode) {
            case IMAGES_AND_TEXT:
                return mItems == null ? 0 : mItems.size();
            case IMAGES_ONLY:
                return mImages == null ? 0 : mImages.size();
            case TEXT_ONLY:
                return mTexts == null ? 0 : mTexts.size();
        }
        return 0;
    }

    @Override
    public Object getItem(int position) {
        switch (mListMode) {
            case IMAGES_AND_TEXT:
                return mItems == null ? null : mItems.get(position);
            case IMAGES_ONLY:
                return mImages == null ? null : mImages.get(position);
            case TEXT_ONLY:
                return mTexts == null ? null : mTexts.get(position);
        }
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;    // not really used
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View v = null;
        TextView tn = null;
        ImageView img = null;

        if (convertView == null) {
            LayoutInflater vi;
            vi = LayoutInflater.from(getContext());
            v = vi.inflate(R.layout.list, null);
        } else {
            v=convertView;
        }

        Item p = items.get(position);
        tn = (TextView) v.findViewById(R.id.tvText);
        img = (ImageView) v.findViewById(R.id.thumbnail);
        if (p.getmType().equals("image")) {
            img.setVisibility(View.VISIBLE);
            Picasso.with(getContext()).load(p.getmData()).error((R.drawable.placeholder_error)).placeholder(R.drawable.placeholder).resize(90,0).into(img);
            tn.setText("ID: " + p.getmID()+"\nTYPE: " + p.getmType() +"\nDate: " + p.getmDate()+ "\nDATA: " +  p.getmData());
        } else {
            img.setVisibility(View.INVISIBLE);
            tn.setText("ID: " + p.getmID()+"\nTYPE: " + p.getmType() +"\nDate: " + p.getmDate()+ "\nDATA: " +  p.getmData());
        }
        return v;
    }

    /**
     * Call this when the filter is selected, e.g.
     * <code>mAdapter.setListMode(ListMode.IMAGES_AND_TEXT);</code>
     * @param listMode
     */
    public void setListMode(ListMode listMode) {
        mListMode = listMode;
        notifyDataSetChanged();
    }

    /**
     * After you receive the JSON, call this method to add the items to the adapter.
     * @param items
     */
    public void setItems(JSONArray jsonArray) {

        mItems = new ArrayList<>();
        mImages = new ArrayList<>();
        mTexts = new ArrayList<>();
        for (int i = 0; i < jsonArray.length(); i++) {
            Item item = new Item(jsonArray.get(i));
            mItems.add(item);
            if (item.isImage()) {
                mImages.add(item);
            }
            if (item.isText()) {
                mTexts.add(item);
            }
        }

        notifyDataSetChanged();
    }

}

像这样实例化你的适配器:

    .
    .
    .
    myListView = (ListView) findViewById(R.id.listViewID);
    customAdapter = new ListAdapter();
    myListView.setAdapter(customAdapter);
    .
    .
    .

当您的AsyncTask 运行时,设置适配器上的项目:

        .
        .
        .
        JSONArray itemsArray = new JSONArray(jsonStr);
        customAdapter.setItems(itemsArray);
        .
        .
        .

从菜单中更改您的视图,如下所示:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
        case R.id.action_about:
            Intent intent = new Intent(this, About.class);
            startActivity(intent);
            return true;

        case R.id.all:
            item.setChecked(true);
            customAdapter.setListMode(ListMode.IMAGES_AND_TEXT);
            return true;

        case R.id.images:
            item.setChecked(true);
            customAdapter.setListMode(ListMode.IMAGES_ONLY);
            return true;

        case R.id.text:
            item.setChecked(true);
            customAdapter.setListMode(ListMode.TEXT_ONLY);
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

另外,我会在您的 Item 类中添加一个构造函数,该类采用 JSONObject

    public Item(JSONObject jsonItem) {

        String itemID=null;
        String itemType=null;
        String itemDate=null;
        String itemData=null;

        if (jsonItem.has("id")) {
            itemID=jsonItem.getString("id");
        }
        if (jsonItem.has("type")) {
            itemType=jsonItem.getString("type");
        }
        if (jsonItem.has("date")){
            itemDate=jsonItem.getString("date");
        }
        if (jsonItem.has("data")){
            itemData=jsonItem.getString("data");
        }
        this(itemID,itemType,itemDate,itemData);
    }

【讨论】:

  • 我认为我无法让它工作,因为我使用的是 ArrayAdapter。我对此感到迷茫。我启动了一个异步任务,它获取 json 数据,对其进行解析并将其放入项目列表中。所以我有 mItems、mImageItems 和 mTextItems。所以当我填充列表时,它看起来像这样:实际上我只是要用我的代码编辑我的问题。
  • 我已经编辑了我的问题以包含我的代码(如果你可以这样称呼它)
  • 根据您的代码更新了我的答案。我认为适配器负责管理作为单个列表变体的三个列表更合适。
  • 好的,谢谢,在您的帮助下我得到了它!我现在正在阅读适配器中的代码,以尝试了解它如何更好地工作。我要做的最后一件事是弄清楚如何根据当前的列表来保存和恢复列表状态。我现在正在玩这个。
  • 哦,那个。我经常为适配器创建一个saveInstanceState()restoreInstanceState() 方法,它们将在活动/片段中的适当位置被调用。告诉我进展如何。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-22
  • 2020-06-28
  • 1970-01-01
  • 2015-02-04
  • 1970-01-01
相关资源
最近更新 更多