カスタムリストビューアダプターのgetViewメソッドが複数回呼び出され、一貫した順序ではない


162

カスタムリストアダプターがあります。

class ResultsListAdapter extends ArrayAdapter<RecordItem> {

オーバーライドされた「getView」メソッドで、位置を確認し、それがconvertViewかどうかを確認するために印刷を行います。

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        System.out.println("getView " + position + " " + convertView);

この出力(リストが最初に表示されたとき、まだユーザー入力はありません)

04-11 16:24:05.860: INFO/System.out(681): getView 0 null  
04-11 16:24:29.020: INFO/System.out(681): getView 1 android.widget.RelativeLayout@43d415d8  
04-11 16:25:48.070: INFO/System.out(681): getView 2 android.widget.RelativeLayout@43d415d8  
04-11 16:25:49.110: INFO/System.out(681): getView 3 android.widget.RelativeLayout@43d415d8  
04-11 16:25:49.710: INFO/System.out(681): getView 0 android.widget.RelativeLayout@43d415d8  
04-11 16:25:50.251: INFO/System.out(681): getView 1 null  
04-11 16:26:01.300: INFO/System.out(681): getView 2 null  
04-11 16:26:02.020: INFO/System.out(681): getView 3 null  
04-11 16:28:28.091: INFO/System.out(681): getView 0 null  
04-11 16:37:46.180: INFO/System.out(681): getView 1 android.widget.RelativeLayout@43cff8f0  
04-11 16:37:47.091: INFO/System.out(681): getView 2 android.widget.RelativeLayout@43cff8f0  
04-11 16:37:47.730: INFO/System.out(681): getView 3 android.widget.RelativeLayout@43cff8f0  

私の知る限り、明示的には見つかりませんでしたが、getView()は可視の行に対してのみ呼び出されます。私のアプリは4つの表示された行から始まっているので、少なくとも0〜3の位置番号の循環は理にかなっています。しかし、残りは混乱です:

  • getviewが各行に対して3回呼び出されるのはなぜですか?
  • まだスクロールしていないときに、これらのconvertViewはどこから来ますか?

私は少し研究しましたが、良い答えが得られなかったので、人々がこの問題をレイアウトの問題に関連付けていることに気付きました。そのため、ここではリストを含むレイアウトを示します。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent" 
    android:orientation="vertical" >

    <TextView android:id="@+id/pageDetails"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" />

    <ListView android:id="@+id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" 
        android:drawSelectorOnTop="false" />

</LinearLayout>

個々の行のレイアウト:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="108dp"    
android:padding="4dp">

<ImageView
    android:id="@+id/thumb"        
    android:layout_width="120dp"
    android:layout_height="fill_parent"        
    android:layout_alignParentTop="true"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_marginRight="8dp"        
    android:src="@drawable/loading" />

<TextView  
    android:id="@+id/price"
    android:layout_width="wrap_content"
    android:layout_height="18dp"         
    android:layout_toRightOf="@id/thumb"
    android:layout_alignParentBottom="true"       
    android:singleLine="true" />

<TextView  
    android:id="@+id/date"
    android:layout_width="wrap_content"
    android:layout_height="18dp"         
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true" 
    android:paddingRight="4dp"       
    android:singleLine="true" />

<TextView
    android:id="@+id/title"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="17dp" 
    android:layout_toRightOf="@id/thumb"
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true"
    android:paddingRight="4dp"   
    android:layout_alignWithParentIfMissing="true"
    android:gravity="center" />

</RelativeLayout>

お時間をいただきありがとうございます

回答:


271

これは問題ではありませんgetView()。呼び出される順序や、何回呼び出されるかについての保証はありません。あなたの特定のケースでは、あなたにListViewそれを与えることによって可能な最悪のことをしていheight=wrap_contentます。これListViewにより、レイアウト時にアダプターから数人の子を測定し、その大きさを知る必要があります。これは、スクロールする前に渡されるを提供ListViewするものです。convertViewsgetView()


10
これは正当な理由だとは思いません。変更できるようにしたい場合は問題ありませんが、現在、この動作を実行している理由に答えていません。
cdpnet 2011

45
@cdpnetそれはそれをやった理由を彼はあなたが、言ったListViewの高さを持っているwrap_content、それはそれの高さで確認されていませんので、したがって、それはで収まるかを確認するために、テスタの種類などから、いくつかの子供を産む。あなたの変更ListViewfill_parent、その後、あなたのログをチェック呼び出しを劇的に減らす必要があります。
Blundell 2012

4
2.3と4.x時代のListView間の動作が大幅に変更されました。要点は、ListViewが設計されているため、cells / list_itemsは純粋なビューである必要があり、すばやく描画できるように最適化する必要があることです。Romainが発表したListViewでのGoogle I / Oトークによると、ビューのレンダリングを最適化して結果を破棄するためだけにgetViewが呼び出される可能性があります。私の意見では、これはiOS UITableViewほど開発者にやさしいものではありませんが、そうです。
Cameron Lowell Palmer

4
どうもありがとうございます!getView()が頻繁に呼び出される理由がわかりませんでした。私はwrap_contentをfill_parentに切り替えましたが、私のアプリは再び高速になりました:)
Julia Hexen

28
ListViewsをlayout_height = wrap_contentに設定すると、パフォーマンスの問題が非常に多くなるため、警告が表示されます。
nathanielwolf

53

試してみてくださいmatch_parent上のlayout_heightリストビューのプロパティ。getView()頻繁に呼び出されるのを防ぎます。


4
フレッドTがリストビューのlayout_heightを指定していることに注意してください。行ではなく、
繰り返し

8
APIレベル8以上でfill_parentはに置き換える必要があることに注意してくださいmatch_parent
Jason Axelson 2013年

getView()メソッドは、幅と高さをListViewのmatch_parentとして設定することにより、パフォーマンスの問題を解決するだけで、複数回呼び出すと思います。
Cuong Vo 2018

45

この問題は、layout_widthとlayout_heightの両方をmatch_parentに変更したときに解消されました(layout_heightのみを変更しても効果がありませんでした)。


ネストされたアイテムがある場合は、注意してください。「最高」のものをmatch_parentに変更する必要があります。それが誰かを助けることを願っています。


1つの単語のバディ「素晴らしい」が、wrap_contentが問題を引き起こしている理由がわかりません。これで私の問題は解決しました。
Android Killer

@AndroidKiller使用する場合wrap_content、そしてListViewなぜthatsの、リストの内容になることがありますどのくらいのリスト項目を知らないListView、それはディスプレイに適していると考えるよう試みが多くの行として作成するには、あなたが使用している場合fill_parentmatch_parentListView私の高さ、大丈夫、と考えてであるxと私は必要なnショーに行数を。
Adil Soomro 2014年

どうもありがとうございます !この動作により、複数の呼び出しのために画像がランダムに変化しました...これは最初から問題ありません。
Chostakovitch、2015年

7

「なぜ」の質問には答えられませんが、「リストビューアイテムの繰り返し」という苛立たしい問題の解決策は確かにあります(画面の高さを超えるアイテムがurコレクションにある場合)。

上記の多くの人が述べたように、ListVewタグのandroid:layout_heightプロパティはfill_parentのままにします。

そしてgetView()関数に関しては、解決策はViewHolderと呼ばれる静的クラスを使用することですこの例を確認してください。これは、配列またはArrayCollection内のすべてのアイテムを追加するタスクを正常に実行します。

これが友達に役立つことを願っています!!

よろしく、Siddhant


初期バージョンのAndroid(ICS以前)でViewHolderパターンを使用する場合は注意が必要です。MemoryLeak例外が発生する可能性があるためです。ICS +バージョンでお気軽にご利用ください。
Vahid Ghadiri、2015

@Siddhantおかげで私は自分で画像を繰り返すの理由から日TTOの姿を過ごすGridViewと変更android:layout_heightし、android:layout_width私のために動作しません。しかし、使用してViewHolder、私はこのチュートリアルを行ってきました私のために固定繰り返し画像android-vogue.blogspot.com/2011/06/...
ニコライPodolnyy

4

質問:アダプターがgetView()を何度も呼び出すのはなぜですか?回答:Listviewがスクロール時にレンダリングされると、ビューは次の次のビューで更新されるため、アダプターはgetView()を呼び出してビューを取得する必要があります。

質問:リストビューの幅と高さがfill_parentに設定されていると、呼び出しが少なくなるのはなぜですか?回答:インフレータにはリストの画面領域の固定サイズがあるため、画面にビューをレンダリングするために一度計算されます。

それがあなたのクエリを解決することを願っています。


素晴らしい説明。しかし、match_parentの方が適している場合があります。
Fattie

はい、@ JoeBlow、API 2.4 / 3.0以降、fill_parentではなくmatch_parentを使用することをお勧めします
jitain sharma

4

AutoCompleteTextViewのドロップダウンで同じ問題が発生していました。私がここに到着し、あなたが私に解決策を示すまで、私は2日間問題と闘っていました。

dropDownHeight = "match_parent"と書けば問題は解決します。現在、問題はUIに関連しています(1つの項目がある場合、ドロップダウンが大きすぎます)が、複数の呼び出し(はるかに重要)の問題が修正されました。

ありがとうございました!!


2

「なぜ行ごとにgetviewが3回呼び出されるのですか?」getViewは、リストビューをスクロールしたときに呼び出され、さらに言えば、リストのビューの位置が変更されたときに呼び出されるためです!


わかりましたが、ビューは変更されていません。アクティビティが開始すると、画面に4
つの行

この答えは間違っています。正解は、** wrap_content **を使用すると、getViewが大量に呼び出されることです。
Fattie

2

同じ問題が発生しています。高さをfill_parentに設定すると、「通常」行ごとに2回の呼び出しが行われます。しかし、ListViewの高さを正確な値に設定した場合、たとえば300dpに設定すると、行ごとに1つのGetView呼び出ししか取得できません。

したがって、最初に画面の高さを決定してから、プログラムでlistvilewの高さをその値に設定するのが唯一の方法であるように思えます。嫌いです。もっと良い方法があるといいのですが。


1
それをありがとう。おかしいです-この質問は数ヶ月間休眠状態になっており、過去数週間にわたっていくつかのコメントが表示されています。私はこのプロジェクトをもうやっていませんが、時間があるので、試してから確認するためにここに戻ってきます。再度、感謝します。
エジリオン2011年

ここでも同じで、行ごとに2つの呼び出しが行われます。行0、1、2、3、次に100ms後、別の0、1、2、3-これは、どの行が表示されるかについての統計を収集するときにお尻の痛みです
Someone Somewhere

2

(設定した後、誰まだあなたのすべてのためheightListViewへのmatch_parent(私がしたように))立ち往生しています。

またheight、親レイアウトのをに設定する必要がありますmatch_parent

以下の例を参照してください。LinearLayoutここでは、親であります:

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/something" />

        <ListView
            android:id="@+id/friendsList"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

1

これはおそらく遅くなるかもしれませんが、使用しlayout_weightている場合は常に設定することを忘れないでくださいlayout_width="0dp"


0

私はこの解決策を作りました、おそらく最高のものではありませんが、うまくいきます...

//initialize control string
private String control_input = " ";

次に=

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

    View gridview = convertView;

    // change input_array for the array you use
    if (!control_input.equals(input_array[position])) {
        control_input = input_array[position];

        //do your magic

    } 

    return gridview;
}

それが役に立てば幸い!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.