0

私の Android アプリケーションでは、私の目標は非常に単純だと思いました。インストールされているアプリケーションのリストを生成し、それぞれの横にチェック ボックスを配置して、「除外するチェック ボックス」リストとして機能させることです。

インストールされているアプリケーションのリストを生成するために、標準の Android サンプル コードを使用しています。この投稿をできるだけ簡潔にするために、すべてを再投稿することはしません。

パフォーマンスがひどいので、このテーマに関する最初の質問は、アプリケーション アイコンを LazyLoads するサンプル コードを要求することです。ListView への LazyLoading アイコンの実装は、画像がダウンロードされている場合にのみ問題になるようです。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 が配置されているため、パフォーマンスはひどいものです (これについては以下で詳しく説明します)。

パフォーマンスを向上させるには、代わりに 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 が再描画され、位置への参照がめちゃくちゃになると思いますか? これにより、ディスプレイ上の位置に基づいてボックスがチェックされます。

onListItemClick から CheckedTextView への参照を取得できないため、上記の各エントリに OnClickListener を実装する必要がありました。ここに私の多くの試みのいくつかがあります:

@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