2012-03-15 15 views
9

かなり新しいAndroidデベロッパーはここにあります。スクロール時にgetViewが間違った位置で呼び出されました

私は奇妙な問題に遭遇しました。私は回避策がわかりません。私はここで、私が抱えているのと同じ問題だと思うが、彼らの問題に対する解決策は、ここで起こっていることには当てはまりそうにないような、多くの問題を読んだ。

BaseListを拡張し、ビューホルダーを使用する別のクラスを使用してカスタムlistViewをセットアップしました。これはカスタムリストビューのいろいろな例を見ています。テキストビュー、ボタン、プログレスバー、イメージボタンがあり、これらの項目はファイルのダウンロードに使用されるAsyncTaskに基づいて非表示/変更されます。

リストをゆっくりとスクロールすると、すべてうまく動作します。リストをすばやく上下にスクロールすると、リスト内の一部のセルのビューが他のセルに再割り当てされたようになります。

は、私は私のアダプタクラスで私の「getViewメソッド」メソッドの先頭に次の行を置く:

@Override 
    public View getView(final int pos, View convertView, ViewGroup parent) 
    { 
     Log.i("ks3","getView called, position is " + pos); 

私は画面に収まら7つの私のリスト内の項目、およびそれらの6を持っています。それが最初に表示されます場合は、私は私のログでこれを参照してください。

getView called, position is 0 
getView called, position is 1 
getView called, position is 2 
getView called, position is 3 
getView called, position is 4 
getView called, position is 5 

私は次の項目にゆっくりスクロールダウンすると、これは次のプリントアウトされます。

getView called, position is 6 

私は戻ってスクロールし、これを:

getView called, position is 0 

これらの結果を完全に生成します。

私はすぐに前後にスクロールを開始すると、それは主に位置として6と0を示し、このメッセージを何回の束を出力し、時折、私は同様にこれらが表示されます。

getView called, position is 1 
getView called, position is 5 

体位を1彼らは常に画面上にあるので、5は呼び出されるべきではありません。これは、getViewがすべて混乱したようです。同時に、私が前に述べたように、私のリストは奇妙に見えます。イメージボタンは、セルの上または下に移動しないでください。

私がスムーズにスクロールすることに戻った場合、私は位置のために0と6だけをもう一度見ます。

正直なところ、これを回避する方法がわかりません。私はあなたがリストをスクロールすることができる速度を制限することができたかもしれないが、何かを見つけることができなかったかもしれないと思った。

ありがとうございます!

編集: この質問についていくつか更新したいと思います。最初のことは、ここのコメントやlistViewのGoogleビデオから、getViewは測定などのために想像した他のもののために呼び出すことができるということに気づいたので、私は気にするべきではありません私が元々考えていたことは私の問題の一部であった(私はgetViewが間違った位置で呼ばれていると思っていた)。

第2に、「アダプターの内部にビューをキャッシュする」ことは非常に悪い考えです。私はこれが何を意味するのかがはっきりしていませんが、私が間違っていることの一つであると確信しています(ボタンのインスタンスを保存します、progressBar、imageButton ...)。

これは、getView以外のビューを更新するという事実とともに、私はnotifyDataSetChanged()を使用しません。一緒にそれらはおそらくいくつかの厄介なものが起こる原因になります。

+0

あなたのカスタムListViewが何かファンキーなことをしていない限り、これはリサイクルの問題のように聞こえ、完全なgetView()コードを投稿します。 – dmon

+0

コードでエラーが見つからず、Honeycomb以上を使用している場合は、リストレイアウトのハードウェアアクセラレーションを無効にすることができます。ハードウェアアクセラレーションは、このようなエラーを引き起こす可能 – zapl

+1

リサイクル問題のように感じます。 listViewのGoogleビデオを見て、listViewをどのように使用しているかに目立った問題がないかどうかを確認します。 – Droidmon

答えて

13

ListViewは、画面上の別の場所で表示を再利用しているとします。常に新しいビューを割り当てないことで、メモリ使用を合理的かつ迅速に保つ最適化です。

LiewViewが間違っている可能性があります。

  1. 「位置」は、アダプターのリスト内のデータの場所を指します。詳細については、this talk on how to properly use ListViewを参照してください。アダプタデータが配列内にある場合、これはその配列へのインデックスになります。
  2. "ID"はデータそのものの値を指します。あなたが名前のリストを持っていて、それらを整理すれば、彼らの位置は変わるでしょうが、彼らのIDはそうしません。
  3. "索引"は、表示可能な画面領域に対するビューの相対的な位置を指します。あなたはおそらくこれを必要としません。
  4. アダプタのgetView()メソッドの外部で操作したり、キャッシュしたりしないでください。奇妙な動作が発生します。
  5. getView(int, View, ViewGroup)の呼び出しでビューインスタンスが提供されている場合は、完全に新しいビューを展開する代わりに、そのフィールドに値を設定します。 getItemType()が正しく実装されていると仮定すると、正しく入力するとViewタイプになります。
  6. getView()メソッドを可能な限り速くし、他のスレッドでは重い作業しか行わないでください。
  7. getView()というコンテナが、必ずしもデータが表示されるというわけではありません。このフレームワークは測定目的でこれらを使用します。仕事が捨てられるかもしれないので、これはあなたがそれを作ることができるほど速いことを確かめるもう一つの理由です。
  8. 画面に表示する必要があるデータに何か不具合が生じた場合、ダウンロードが完了したら、notifyDataSetChanged()に電話をかけます。ビューを直接操作しないで、それらが再描画されるときに次のUIループに移入されます。

ListViewが直感的に実行されてから数日を費やしただけで、私はあなたの痛みを感じます。しかし、その結果は価値がありました!

+2

アーガイル、ありがとうございました。私はlistViewがどのように動作するかについては十分に分かっていないので、getView以外のビューを更新していることを認めるので、notifyDataSetChanged()を使用する方法を理解する必要があります。 – Droidmon

+0

サープルは私の痛みを感じる!この質問に回答することができますかhttp://stackoverflow.com/questions/22451081/how-to-track-the-position-of-item-while-scrolling-in-a-long-listview –

+0

私はいくつかの重い重い処理し、各項目に動的な形を追加して、私はちょうどその場所をgetview()で見つけます。私はそれを動かすことができるあなたのポイントについては? – Kenji

0

getViewは描画する必要があるが以前は画面に表示されていなかったすべてのリスト項目に対して呼び出されます。あなたが速くスクロールすると、奇妙な位置になるかもしれませんが、あなたが記述しているようにエラーを起こしてはいけません(Androidのエラーは、リストビューがかなりうまくテストされているので、ここにはないと思います)。例えば。あなたが十分速くスクロールすると、描画する必要のある2つのビューがあるかもしれません。 コードに何か間違いがあるかもしれません。

+0

ああ、それは知っておいてよかった、私はこれが嬉しいです、または少なくとも問題を引き起こしているべきではありません。 – Droidmon

4

getviewで常にこのアプローチを使用します。 convertView = inflater.inflate(R.layout.listinflate、parent、false);

あなたのアクティビティにはonScrollListenerが実装されます。また、ユーザーが実際にリスト表示アダプタに通知しているときに、アイテムを正しく更新するよう心がけないように通知します。ユーザーが逃げていなくなったときにgetViewでデータを提供するようにアダプタに指示するように指示します。

それは私のすべての問題を解決しました。 さらに、リストビューの高さにwrap_contentを使用しないでください。それにもsmoothscroll falseを設定してください。

+0

wrap_contentを使用していません – pkacprzak

1

私は同じ問題を抱えていました。アダプタには、getViewメソッドで背景色を変更していましたが、時にはリストビューが誤った背景を取得していることがありました。私は単純に各

if(...){changeBackground}

に "他に" 入れて解決 私は

else {restore default background}

を追加し、それは記録のためにスムーズに

+0

あなたは素晴らしいです!私はこの問題を解明する朝の良い塊を過ごしました。どうもありがとう! –

+0

問題ありません!それを聞いてうれしい! ;) – Mark

0

を働いたと@マークの答えを拡張

Androidは次のタスクを行います。私は100要素のリストを持っているとしましょう。あなたはロードしています、getviewは要素0,1,2,3 ... 10のように呼び出されます。そして、次の位置は11になります。ただし、位置11は位置0と同じビューを再利用します。したがって、位置11のビューは存在しますが、値が間違っています(0値)。

回答:ビューがnullの場合はデータを変更してください。ビューがnullの場合は、ビューの値を収縮して変更します。そうでない場合は、ビューの値を変更します。

その後、アダプタは次のようにする必要があり、私は単一のTextViewでitem_view(レイアウト)を持っていると言うことができます:

右バージョン:

public class XXXAdapter extends ArrayAdapter<XXX> {.... 
@NonNull 
@Override 
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { 
    if (convertView==null) { 
     LayoutInflater inflater = LayoutInflater.from(this.getContext()); 
     convertView = inflater.inflate(R.layout.**itemofthelayout**, parent, false); 
    } 
    ***Object** item=this.getItem(position); 
    TextView txt= (TextView) convertView.findViewById(R.id.**idsometextviewinsidelayout**); 
    txt.setText(String.valueOf(position)); 
    return convertView; 
    // return super.getView(position, convertView, parent); 
} 

間違ったバージョン:

public class XXXAdapter extends ArrayAdapter<XXX> {.... 
@NonNull 
@Override 
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { 
    if (convertView==null) { 
     LayoutInflater inflater = LayoutInflater.from(this.getContext()); 
     convertView = inflater.inflate(R.layout.**itemofthelayout**, parent, false); 
     ***Object** item=this.getItem(position); 
     TextView txt= (TextView) convertView.findViewById(R.id.**idsometextviewinsidelayout**); 
     txt.setText(String.valueOf(position)); 
     return convertView; 
     // return super.getView(position, convertView, parent); 
    } 
} 
関連する問題