1

カスタム SimpleAdapter が関連付けられたリストビューがあります。カスタムの SimpleAdapter を作成したのは、含まれている textview と imageview に、他のリスト項目ウィジェットとは異なるイベント ハンドラーを関連付けたいからです。したがって、基本的に、リスト項目の 2 つの部分に対して 2 つの異なるイベント ハンドラーがあります。

私のSimpleAdapterのカスタマイズは次のとおりです。

class ClickableButtonListAdapter extends SimpleAdapter {

    private static class ViewHolder {
        TextView text;
        ImageView image;
    }

    public ClickableButtonListAdapter(Context context,
        List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) {
        super(context, data, resource, from, to);
    }

    @SuppressWarnings("unchecked")
    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final View view = super.getView(position, convertView, parent);
        ViewHolder holder = (ViewHolder) view.getTag();
        if(holder == null) {
            holder = new ViewHolder();
            holder.text = (TextView) view.findViewById(R.id.comments);
            holder.image = (ImageView) view.findViewById(R.id.arrow);
            view.setTag(holder);
            final Context context = view.getContext();
            final HashMap<String, String> article = (HashMap<String,String>) getItem(position);
            OnClickListener listener = new OnClickListener() {
                @Override
                public void onClick(View view) {
                    String item_id = article.get("item_id");
                    Intent intent = new Intent(context, HNewsCommentsActivity.class);
                    intent.putExtra("item_id", item_id);
                    context.startActivity(intent);
                }
            };
            holder.text.setOnClickListener(listener);
            holder.image.setOnClickListener(listener);
        }
        return view;
    }
}

その後、onCreate アクティビティで、カスタム SimpleAdapter を次のように関連付けます。

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        try {
            final ArrayList<HashMap<String, String>> articles = getHNewsFeed();
            final SimpleAdapter adapter = new ClickableButtonListAdapter(this,
                    articles, R.layout.article,
                    new String[] {"title", "urlShort", "score", "comments", "item_id"},
                    new int[] {R.id.title, R.id.url, R.id.score, R.id.comments, R.id.item_id}
                    );
            final ListView l = (ListView) findViewById(android.R.id.list);
            l.setAdapter(adapter);
            l.setOnItemClickListener( new OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                    final HashMap<String, String> article = articles.get(position);
                    String url = article.get("url");
                    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                    startActivity(intent);
                }
            });
        } catch (Exception e) {
            Log.w(TAG, e.getMessage());
            Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

私の問題は、含まれている textview と imageview (カスタム SimpleAdapter の getView で初期化する) に関連付けられたイベント ハンドラーが、間違ったデータ ソース項目を取得し、クリックすると別の記事のデータを表示するように見えることです。ただし、リストビュー アイテムのクリック ハンドラーは、正しいデータ ソース アイテムを取得します。カスタム SimpleAdapter の getView で textview と imageview に関連付けたイベント ハンドラーが正しく機能しない理由を指摘してくれる人がいますか? 私の理解では、SimpleAdapter の 'getItem(position)' メソッドは正しいデータ ソース アイテムを返す必要があります。しかし、何らかの理由で、そうではないようです。

4

2 に答える 2

4

あなたの論理には誤りがあります。アダプターの getView メソッドは何度も呼び出され、1 つの View は異なる期間に異なるアイテムを表示できます。

それで、それがどのように機能するか:

ListView がアイテムを必要とする場合、Adapter クラスからメソッド getView を呼び出します (このビューをユーザーに表示するか、ビュー アイテムのサイズを計算するためだけに使用するかは関係ありません)。ListView は convertView パラメーターを渡します。これは、このアダプターがしばらく前に返した古いビューであり、現在は必要ありません。それを再利用し、再度膨らませなくても問題ありません (スーパーメソッドはこのように機能します)。そして、ここにあなたのコードの問題があります。古いビューが getView メソッドに渡された場合、既にタグ オブジェクトが含まれています。そして、あなたの (holder == null) == false. そして、ある記事を表すビューが別の記事を開きます。

この間違いを修正するためにロジックを変更してみてください。最善の方法は、ホルダーを 1 回だけ作成し、毎回ビュー リスナーを設定することです。

これが役立つことを願っています。

編集。問題を解決するには2つの方法があります。

@SuppressWarnings("unchecked")
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final View view = super.getView(position, convertView, parent);
    ViewHolder holder = (ViewHolder) view.getTag();
    if(holder == null) {
        holder = new ViewHolder();
        holder.text = (TextView) view.findViewById(R.id.comments);
        holder.image = (ImageView) view.findViewById(R.id.arrow);
        view.setTag(holder);
    }

    final Context context = view.getContext();
    final HashMap<String, String> article = (HashMap<String,String>) getItem(position);
    OnClickListener listener = new OnClickListener() {
        @Override
        public void onClick(View view) {
            String item_id = article.get("item_id");
            Intent intent = new Intent(context, HNewsCommentsActivity.class);
            intent.putExtra("item_id", item_id);
            context.startActivity(intent);
        }
    };
    holder.text.setOnClickListener(listener);
    holder.image.setOnClickListener(listener);

    return view;
}

第二に、私はもっと愛している。このバージョンの Vinay S Shenoy に感謝します。

@SuppressWarnings("unchecked")
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final HashMap<String, String> article = (HashMap<String,String>) getItem(position);

    final View view = super.getView(position, convertView, parent);
    ViewHolder holder = (ViewHolder) view.getTag();
    if(holder == null) {
        holder = new ViewHolder();
        holder.text = (TextView) view.findViewById(R.id.comments);
        holder.image = (ImageView) view.findViewById(R.id.arrow);
        view.setTag(holder);
        final Context context = view.getContext();
        OnClickListener listener = new OnClickListener() {
            @Override
            public void onClick(View view) {
                String item_id = view.getTag();
                //String item_id = article.get("item_id");
                Intent intent = new Intent(context, HNewsCommentsActivity.class);
                intent.putExtra("item_id", item_id);
                context.startActivity(intent);
            }
        };
        holder.text.setOnClickListener(listener);
        holder.image.setOnClickListener(listener);
    }

    holder.text.setTag(article.get("item_id"));
    holder.image.setTag(article.get("item_id"));

    return view;
}
于 2013-01-02T04:19:24.687 に答える
2

問題は、Article オブジェクトが OnClickListener の外部で作成されるためです。

あなたがする必要があるのは、item_id をタグとして TextView と ImageView に保存することです。res/strings.xml ファイルに、ID の tag_holder と tag_item_id を使用して 2 つの文字列を追加します。次に、 getView() を次のように変更します。

 @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final View view = super.getView(position, convertView, parent);
        ViewHolder holder = (ViewHolder) view.getTag(R.string.tag_holder);
        if(holder == null) {
            holder = new ViewHolder();
            holder.text = (TextView) view.findViewById(R.id.comments);
            holder.image = (ImageView) view.findViewById(R.id.arrow);
            view.setTag(R.string.tag_holder, holder);
            final Context context = view.getContext();

            OnClickListener listener = new OnClickListener() {
                @Override
                public void onClick(View view) {
                    String item_id = (String)view.getTag(R.string.tag_item_id);
                    //String item_id = article.get("item_id");
                    Intent intent = new Intent(context, HNewsCommentsActivity.class);
                    intent.putExtra("item_id", item_id);
                    context.startActivity(intent);
                }
            };
            holder.text.setOnClickListener(listener);
            holder.image.setOnClickListener(listener);
        }

         final HashMap<String, String> article = (HashMap<String,String>) getItem(position);

            holder.text.setTag(R.string.tag_item_id, article.get("item_id");
            holder.image.setTag(R.string.tag_item_id, article.get("item_id");
        return view;
    }

さらに、この OnClick リスナーはビュー タグのみに依存するため、すべてのリスト項目に対して新しい OnClickListener() を作成しないことをお勧めします。代わりに、アダプターのコンストラクターでリスナーをインスタンス化し、すべてのリスト項目に対して同じインスタンスを使用します。

于 2013-01-02T04:09:49.210 に答える