152

だから私は以前にこの問題を抱えていました、そして当然私はここで助けを求めました。ListViewとGridViewがビューのリサイクルでどのように最適化されているのかわからなかったので、Luksprogの答えは素晴らしかった。そこで彼のアドバイスで、GridViewにビューを追加する方法を変更することができました。問題は今、私には意味のない何かがあるということです。これは私のgetViewからBaseAdapterです:


public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            convertView = inflater.inflate(R.layout.day_view_item, parent, false);
        }
        Log.d("DayViewActivity", "Position is: "+position);
        ((TextView)convertView.findViewById(R.id.day_hour_side)).setText(array[position]);
        LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.day_event_layout);

        //layout.addView(new EventFrame(parent.getContext()));

        TextView create = new TextView(DayViewActivity.this);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 62, getResources().getDisplayMetrics()), 1.0f);
        params.topMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
        params.bottomMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
        create.setLayoutParams(params);
        create.setBackgroundColor(Color.BLUE);
        create.setText("Test"); 
        //the following is my original LinearLayout.LayoutParams for correctly setting the TextView Height
        //new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getResources().getDisplayMetrics()), 1.0f)   
        if(position == 0) {
            Log.d("DayViewActivity", "This should only be running when position is 0. The position is: "+position);
            layout.addView(create);
        }

        return convertView;
    }

}

問題は、スクロールすると、これが発生し、位置0ではないことです...位置6と位置8のように見え、さらに2つが位置8に配置されます。今でもListViewとGridViewを使用するコツをつかもうとしているので、なぜこれが起こっているのか理解できません。私がこの質問をしている主な理由の1つは、ListViewとGridViewのリサイクルビュー、またはこの記事の言い方であるScrapViewメカニズムについておそらく知らない他の人を助けることです。

ここに画像の説明を入力してください

後で編集

ListViewがどのように機能するかを理解するために基本的に必要なのはGoogleIOトークへのリンクを追加することです。コメントのリンクは死んでいた。したがって、user3427079は、そのリンクを更新するのに十分良かったです。ここでは簡単にアクセスできます。

4

3 に答える 3

337

最初は、リストビューのリサイクルとコンバートビューの使用メカニズムについても知りませんでしたが、丸一日の調査の後、 android.amberfogの画像を参照することで、リスト ビューのメカニズムをかなり理解しました。 ここに画像の説明を入力

リストビューがアダプターによって満たされるたびに、基本的にリストビューが画面に表示できる行数が表示され、リストをスクロールしても行数は増加しません。これは、リストビューがより効率的かつ高速に動作するように Android が使用するトリックです。画像を参照するリストビューの裏話です。ご覧のとおり、最初はリストビューに 7 つの表示項目があり、項目 1 が表示されなくなるまで上にスクロールすると、getView() はこのビュー (つまり、item1) をリサイクル業者とあなたが使用することができます

System.out.println("getview:"+position+" "+convertView);

あなたの中に

public View getView(final int position, View convertView, ViewGroup parent)
{
    System.out.println("getview:"+position+" "+convertView);
    ViewHolder holder;
    View row=convertView;
    if(row==null)
    {
        LayoutInflater inflater=((Activity)context).getLayoutInflater();
        row=inflater.inflate(layoutResourceId, parent,false);
        
        holder=new PakistaniDrama();
        holder.tvDramaName=(TextView)row.findViewById(R.id.dramaName);
        holder.cbCheck=(CheckBox)row.findViewById(R.id.checkBox);
        
        row.setTag(holder);
        
    }
    else
    {
        holder=(PakistaniDrama)row.getTag();
    }
            holder.tvDramaName.setText(dramaList.get(position).getDramaName());
    holder.cbCheck.setChecked(checks.get(position));
            return row;
    }

最初はリサイクラーにビュー (アイテム) がなかったので、最初はすべての表示されている行に対して convertview が null であることが logcat でわかります。上にスクロールして項目 1 が画面の外に出ると、現在の状態 (TextView の「テキスト」など) とともにリサイクラーに送信されます。私の場合、チェックボックスがオンになっていると、ビューに関連付けられ、リサイクル業者に保管されます)。

上下にスクロールすると、リストビューは新しいビューを作成せず、リサイクラーにあるビューを使用します。Logcatでは、'convertView' が null ではないことに気付くでしょう。これは、新しいアイテム 8 が convertview を使用して描画されるためです。それは私のコードで。チェックボックスがあり、位置0でチェックした場合(item1にチェックボックスがあり、チェックしたとしましょう)、下にスクロールすると、アイテム8チェックボックスがすでにチェックされていることがわかります。これが、リストビューが同じビューを使用している理由です。パフォーマンスの最適化のため、新しい を作成していません。

大事な事

1 . リストビューに描画されるビューの高さを測定するためにアダプターに子を強制的に取得させ、リストがスクロールされていなくても convertview を返すなどの予期しない動作を引き起こす可能性があるため、リストビューの and を設定しないでください。常にlayout_height使用または修正幅高さ。layout_widthwrap_contentgetView()match_parent

2 . layout_heightリストビューの後にいくつかのレイアウトまたはビューを使用したい場合、リストビューの後にビューを設定すると質問が頭に浮かぶ可能性があるfill_parentため、リストビューをレイアウト。たとえば、リニアレイアウトを使用し、そのレイアウトの高さと幅を要件に合わせて設定し、リストビューの高さの属性をレイアウトのように設定します(レイアウトの幅が320で高さが280の場合など)、リストビュー高さが同じであること. これにより、レンダリングされるビューの正確な高さと幅が getView() に通知され、getView() はランダムな行を何度も呼び出すことはなく、スクロールが発生する前に変換ビューを返すなどの問題も発生しません。これは私自身、リストビューが lineaLayout 内にない限り、ビュー呼び出しを繰り返してビューを変換するなどの問題もあり、Listview を LinearLayout 内に置くことは私にとって魔法のように機能しました.(理由はわかりませんでした)

01-01 14:49:36.606: I/System.out(13871): getview 0 null
01-01 14:49:36.636: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.636: I/System.out(13871): getview 1 android.widget.RelativeLayout@406082c0
01-01 14:49:36.646: I/System.out(13871): getview 2 android.widget.RelativeLayout@406082c0
01-01 14:49:36.646: I/System.out(13871): getview 3 android.widget.RelativeLayout@406082c0
01-01 14:49:36.656: I/System.out(13871): getview 4 android.widget.RelativeLayout@406082c0
01-01 14:49:36.666: I/System.out(13871): getview 5 android.widget.RelativeLayout@406082c0
01-01 14:49:36.666: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.696: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.706: I/System.out(13871): getview 1 null
01-01 14:49:36.736: I/System.out(13871): getview 2 null
01-01 14:49:36.756: I/System.out(13871): getview 3 null
01-01 14:49:36.776: I/System.out(13871): getview 4 null

しかし、今では解決しました。私は説明が得意ではありませんが、理解するために一日を費やしたので、私のような他の初心者が私の経験の助けを得ることができると思いました. ListViewフレームワークの仕組みについて説明します。これは非常に面倒でトリッキーであるため、初心者はそれを理解するのにあまりにも多くの問題を発見しました

于 2013-01-01T07:24:30.057 に答える
8

ホルダー パターンで、ホルダー オブジェクトに位置を設定する場合は、毎回設定する必要があります。たとえば、次のように注意してください。

@Override
public final View getView(int position, View view, ViewGroup parent) {
    Holder holder = null;
    if (view == null) {
        LayoutInflater inflater = (LayoutInflater) App.getContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(getContainerView(), parent, false);
        holder = getHolder(position, view, parent);
        holder.setTag(tag);
        view.setTag(holder);
    } else {
        holder = (Holder) view.getTag();
    }
    holder.position = position;
    draw(holder);
    return holder.getView();
}

これは抽象クラスの例です。

getHolder(position, view, parent);

のすべての設定操作を行います

ImageViews, TextViews, etc..
于 2014-04-14T10:56:11.737 に答える
3

ホルダー パターンを使用すると、目的を達成できます。

このパターンの説明は次の場所にあります。

リスト ビューのリサイクルは、画面を下にスクロールし、リスト ビューのアイテムが非表示になっているときに発生します。これらは、新しいリスト ビュー アイテムを表示するために再利用されます。

于 2015-12-19T13:24:35.440 に答える