2

CursorAdapterデータベースから構築されたを持っています。最初の項目のaが入力されていないCursor場合View、最初の項目のに、が設定された最初の後続のリスト項目のViewデータに表示されるデータが入力されます。さらに、リストアイテムごとに3回トリガーされることがわかりましたが、これは奇妙に思えます。これは最初のリストアイテムに対してのみ行われ、nullが含まれるすべてのアイテムに対しては行われません。外観は次のとおりです。ViewViewonBindViewView

例

「ジュリアン」のアドレスが「アリス」にコピーされていることに注意してください。onBindViewメソッドでブレークポイントを設定すると、customerNameが "Alice Martin"の場合、if(billingAddressCursor!=null && billingAddressCursor.getCount()>0)への3つの呼び出しすべてで常にfalseと評価されるためonBindView、課金条件に入ることがないことがわかります。

最初の位置に間違った値が描画されるのはなぜですか?どうすれば停止できますか?コード:

private class CustomerAdapter extends CursorAdapter {
    /*** DEBUG CODE, TO BE REMOVED ***/
    int aliceBindCount = 0;
    int blakeBindCount = 0;
    int cscBindCount = 0;
    int julianBindCount = 0;
    /*** ^^^^^^^^^^^^^^^^^^^^^^^^^ ***/
    public CustomerAdapter(Context context, Cursor cursor) {
        super(context, cursor);
    }

    public void bindView(View convertView, Context context, Cursor cursor) {
        if(convertView!=null) {
            String customerName = cursor.getString(cursor.getColumnIndex(CustomerSchema.NAME));
            ((TextView)convertView.findViewById(R.id.cli_customer_name)).setText(customerName);
            /*** DEBUG CODE, TO BE REMOVED ***/
            if(customerName.equals("Alice Martin")) {
                aliceBindCount += 1;
            } else if(customerName.equals("Blake Slappey")) {
                blakeBindCount += 1;
            } else if(customerName.equals("Conceptual Systems")) {
                cscBindCount += 1;
            } else if(customerName.equals("Julian")) {
                julianBindCount += 1;
            }
            /*** ^^^^^^^^^^^^^^^^^^^^^^^^^ ***/
        }
        final Long billingAddressID = cursor.getLong(cursor.getColumnIndex(CustomerSchema.BILLING_ADDRESS_ID));
        Cursor billingAddressCursor = DbDesc.getInstance().getDatabase(getActivity()).query(
                LocationSchema.TABLE_NAME,
                null,
                LocationSchema._ID+"=?",
                new String[]{ String.valueOf(billingAddressID) },
                null,
                null,
                null
        );
        if(billingAddressCursor!=null && billingAddressCursor.getCount()>0) {
            billingAddressCursor.moveToFirst();
            String street = billingAddressCursor.getString(billingAddressCursor.getColumnIndex(LocationSchema.STREET));
            String city = billingAddressCursor.getString(billingAddressCursor.getColumnIndex(LocationSchema.CITY));
            String state = billingAddressCursor.getString(billingAddressCursor.getColumnIndex(LocationSchema.STATE));
            String zip = billingAddressCursor.getString(billingAddressCursor.getColumnIndex(LocationSchema.ZIP));
            if(zip==null || zip.equals("")) {
                zip = "[NO ZIP]";
            }
            if(street==null || street.equals("")) {
                street = "[NO STREET]";
            }
            if(city==null || city.equals("")) {
                city = "[NO CITY]";
            }
            if(state==null || state.equals("")) {
                state = "[NO STATE]";
            }
            ((TextView)convertView.findViewById(R.id.cli_street)).setText(street);
            ((TextView)convertView.findViewById(R.id.cli_city_state_zip)).setText(city+", "+state+" "+zip);
        }
    }

    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        LayoutInflater inflater = LayoutInflater.from(context);
        View v = inflater.inflate(R.layout.customer_list_item, parent, false);
        return v;
    }
}

そして、私はアリスがそのレコードに関連付けられた請求先住所を持つべきではないと確信しています。これがsqlite3からのテーブルクエリです。ご覧のとおり、請求先住所IDを持つ唯一のレコードはJulianのレコードです。

sqlite> .tables
.tables
android_metadata  contract          location
contact           customer          phone
sqlite> select * from customer;
select * from customer;
2|Conceptual Systems|||||||
3|Blake Slappey|||||||
4|Julian|1||||||
5|Alice Martin|||||||
4

2 に答える 2

5

コードを見ると(最初は少し混乱していました)、そのアダプターの内部にカスタムCursorAdapterがあり、その人のの二次クエリ(つまり、Join from to )を実行しているようです。UIスレッドで、顧客ごとに2次クエリを実行していることを考えると、これはパフォーマンスが低下します。customerbindView()locationcustomerlocation

SimpleCursorAdapterととの間の結合クエリを使用するcustomerと、これをより簡単に解決できますかlocation。(カスタムアダプタの唯一の目的は、非常に非効率的な方法でcustomerとの「結合」を行うことであるように思われます)location

このように、クエリはLoadersおそらくを使用してバックグラウンドで発生し、バインディングはかなり効率的であり、代替クエリを実行する必要はありません。

最初のクエリは次のようになります。

select customer.name, location.address1, location.address2 from customer, location where customer.location_id = location._id

(あなたのフィールド名が何であるかはわかりませんが、うまくいけば、それが基本的な構造を伝えています)

于 2012-06-22T19:00:49.367 に答える
3

ListView行ビューをリサイクルするため、明示的に設定されていない古い値は、その後の使用でハングします。コードでは、バインダー内のクエリが行を返さない場合、以前の使用からのビューの値が残ります。あなたが望むものではありません。

問題を修正する必要がある再コーディングは次のとおりです。

   String street = "[NO STREET]";
   String city = "[NO CITY]";
   String state = "[NO STATE]";
   String zip = "[NO ZIP]";
   if(billingAddressCursor!=null && billingAddressCursor.getCount()>0) {
        billingAddressCursor.moveToFirst();
        String tmp = billingAddressCursor.getString(billingAddressCursor.getColumnIndex(LocationSchema.STREET));
        if (tmp != null) street = tmp;
        tmp = billingAddressCursor.getString(billingAddressCursor.getColumnIndex(LocationSchema.CITY));
        if (tmp != null) city = tmp;
        tmp = billingAddressCursor.getString(billingAddressCursor.getColumnIndex(LocationSchema.STATE));
        if (tmp != null) state = tmp;
        tmp = billingAddressCursor.getString(billingAddressCursor.getColumnIndex(LocationSchema.ZIP));
        if (tmp != null) zip = tmp;

    }
    ((TextView)convertView.findViewById(R.id.cli_street)).setText(street);
    ((TextView)convertView.findViewById(R.id.cli_city_state_zip)).setText(city+", "+state+" "+zip);

そうは言っても、これはこのリストを埋める正しい方法ではありません。リストアイテムごとに1つのDBクエリを実行すると、パフォーマンスドッグが生成されます。INNER JOIN最も簡単な修正は、1つのクエリで両方のテーブルからすべての情報を取得するために単一を使用することです。UIスレッドで実行すると、クエリに時間がかかりすぎる可能性があります。推奨される修正方法は、 LoaderAndroidのバックグラウンド機能を使用して、UIスレッドを拘束せずにそれを実行することです。

于 2012-06-28T12:18:41.593 に答える