0

在我的 Android 应用程序中,我认为我的目标非常简单 - 生成已安装应用程序的列表并在每个应用程序旁边放置一个复选框,充当“排除”列表。

为了生成已安装应用程序的列表,我使用了标准的 Android 示例代码,在此处的片段中进行了演示。我不会重新发布所有内容,以使这篇文章尽可能简洁。

性能很糟糕,我关于这个主题的第一个问题是请求延迟加载应用程序图标的示例代码。将 LazyLoading 图标实现到 ListView 似乎只是在下载图像时才需要考虑。由于Android在生成应用程序列表时不使用这种方法,那么我想知道这是否是矫枉过正?

当 CheckedTextView 被选中并且视图在列表中被回收时,问题就开始了,进一步的框在列表中被勾选(在初始视图之外),或者他们“忘记”他们已经被勾选

为了解决这个问题,我必须保留对勾选了哪些项目的引用,并在 getView() 中使用以下代码

    // store CheckTextView's
    private static HashMap<Integer, CheckedTextView> mCheckedList = new HashMap<Integer, CheckedTextView>();
    // store state
    private static HashMap<Integer, Boolean> mIsChecked = new HashMap<Integer, Boolean>();

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

            View view;

            if (convertView == null) {
                view = mInflater.inflate(R.layout.list_item_icon_text, parent, false);

            } else {
                view = convertView;

            }

            final AppEntry item = getItem(position);

            ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(item.getIcon());

            CheckedTextView ctv = (CheckedTextView) view.findViewById(R.id.text1);
            ctv.setText(item.getLabel());

            // set current state
            if (mIsChecked.get(position) != null) {
                if (mIsChecked.get(position)) {
                    ctv.setChecked(true);
                }
            } else {
                ctv.setChecked(false);
            }

            ctv.setTag(position);
            mCheckedList.put(position, ctv);

            ctv.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View view) {

                    CheckedTextView ct = mCheckedList.get(view.getTag());

                    if (DE.BUG) {
                        MyLog.d("ct text: " + ct.getText().toString());
                    }

                    ct.toggle();

                    mIsChecked.put((Integer) view.getTag(), ct.isChecked());
                }

            });

            return view;

        }
    }

这行得通,但性能很糟糕,因为每个视图都被刷新/回收,并且 OnClickListener 放置在每个项目上(更多内容见下文) - Eclipse 还告诉我还有更多其他内容需要更改:

改用 new SparseArray(...) 以获得更好的性能

我的麻烦并没有就此结束.. 为了帮助用户快速访问他们想要的应用程序,我实现了一个过滤器,如下所示:

@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // Place an action bar item for searching.
    MenuItem item = menu.add("Search");
    item.setIcon(android.R.drawable.ic_menu_search);
    item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
    View searchView = SearchViewCompat.newSearchView(getActivity());
    if (searchView != null) {
        SearchViewCompat.setOnQueryTextListener(searchView,
                new OnQueryTextListenerCompat() {
            @Override
            public boolean onQueryTextChange(String newText) {
                // Called when the action bar search text has changed.  Since this
                // is a simple array adapter, we can just have it do the filtering.
                mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
                mAdapter.getFilter().filter(mCurFilter);
                return true;
            }
        });
        item.setActionView(searchView);
    }
}

我假设当输入过滤器时,ListView 被重绘并且对位置的引用变得混乱?这会导致框根据它们在显示屏上的位置而被勾选。

我必须为上面的每个条目实现一个 OnClickListener,因为我无法从 onListItemClick 获得对 CheckedTextView 的引用。这是我的许多尝试中的一些:

@Override
public void onListItemClick(final ListView listView, final View view, final int position, final long id) {

    // View v = (View) listView.getChildAt(position);
    // CheckedTextView ctv = (CheckedTextView)
    // v.findViewById(R.id.text1);
    // ctv.toggle();

    // RelativeLayout r = (RelativeLayout) view;

    // CheckedTextView ctv = (CheckedTextView)
    // r.findViewById(R.id.text1);

    // CheckedTextView ctv = (CheckedTextView) view;

    // ((CheckedTextView)
    // listView.getItemAtPosition(position)).setChecked(!((CheckedTextView)
    // listView
    // .getItemAtPosition(position)).isChecked());

    // CheckedTextView ctv = (CheckedTextView) view.getTag(position);
    // ctv.toggle();

正如@CommonsWare在本主题中回答的那样,CheckedTextView 引用findViewById(R.id.text1)不是我所追求的。

编辑 - XML 布局

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:orientation="horizontal"
    android:paddingRight="6dip" >

    <CheckedTextView
        android:id="@+id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/icon"
        android:checkMark="?android:attr/listChoiceIndicatorMultiple"
        android:paddingLeft="4dip"
        android:paddingTop="4dip"
        android:textStyle="bold"
        android:duplicateParentState="true" />

    <ImageView
        android:id="@+id/icon"
        android:layout_width="48dip"
        android:layout_height="48dip"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:paddingLeft="2dip" />

</RelativeLayout>

我准备放弃并使用单独的文本视图和复选框实现我自己的布局,但我不禁想如果我这样做我会重新发明轮子?我是不是让这件事变得比应该做的更难!?

在理想世界中:

  1. LazyLoad 应用程序图标的已安装应用程序列表。
  2. 从 onListItemClick 对实际 CheckedTextView 的引用。
  3. 存储和引用已检查项目的正确方法。

我希望有人可以提供帮助,我提前感谢你。

4

0 回答 0