Android ResourceCursorAdapter: ListView 中只显示一项
Android ResourceCursorAdapter: Only one item displayed in ListView
我正在开发一个适配器,它应该显示从 SQLite 数据库派生的项目列表。 ListView
嵌入在 Fragment
中,填充在自定义适配器中,从 ResourceCursorAdapter
子class 编辑。遍历光标并打印其内容显示它包含许多条目。但是,bindView
仅在第一个条目时被调用,这是 ListView
中显示的唯一条目。我做错了什么?
这是(精简的)代码:
片段XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/network_settings"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:baselineAligned="false">
<ListView
android:id="@+id/addresses_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
适配器列表项 XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/addresses_list_item"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/remote_ip_address"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="0.45"/>
<TextView
android:id="@+id/remote_port"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="0.25"/>
<TextView
android:id="@+id/address_protocol"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="0.2"/>
<ImageButton
android:id="@+id/delete_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/delete_address"
android:src="@drawable/close"/>
</LinearLayout>
片段class(简化,只包含onCreateView
,因为那是适配器被实例化的地方。片段本身工作正常)
public class NetworkSettingsFragment extends Fragment {
private View mView;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.network_settings, container, false);
final SQLiteDatabase db = mActivity.getDatabase();
final ListView addressesList = mView.findViewById(R.id.addresses_list);
final String[] addrFields = new String[]{
SettingsContract.AddressSettingsEntry._ID,
SettingsContract.AddressSettingsEntry.IP_ADDRESS,
SettingsContract.AddressSettingsEntry.PORT,
SettingsContract.AddressSettingsEntry.PROTOCOL
};
final String sortOrder = SettingsContract.AddressSettingsEntry.IP_ADDRESS + " DESC";
final Cursor addressesCursor = db.query(
SettingsContract.AddressSettingsEntry.TABLE_NAME,
addrFields,
null,
null,
null,
null,
sortOrder
);
final AddressesListAdapter addressesListAdapter = new AddressesListAdapter(
getActivity(), R.layout.address_list_item, addressesCursor, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER
);
addressesList.setAdapter(addressesListAdapter);
}
}
适配器
public class AddressesListAdapter extends ResourceCursorAdapter {
final private static String TAG = "AddressesListAdapter";
private int mLayout;
public AddressesListAdapter(Context context, int layout, Cursor c, int flags) {
super(context, layout, c, flags);
mLayout = layout;
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(mLayout, parent, false);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
Log.d(TAG, "the view: " + view + "\ncursor: " + cursor.getPosition() + "\nnum items: " + cursor.getCount());
TextView ipText = view.findViewById(R.id.remote_ip_address);
TextView portText = view.findViewById(R.id.remote_port);
TextView protocolText = view.findViewById(R.id.address_protocol);
final long id = cursor.getLong(cursor.getColumnIndexOrThrow(SettingsContract.AddressSettingsEntry._ID));
final String ip = cursor.getString(cursor.getColumnIndexOrThrow(SettingsContract.AddressSettingsEntry.IP_ADDRESS));
final int port = cursor.getInt(cursor.getColumnIndexOrThrow(SettingsContract.AddressSettingsEntry.PORT));
final String protocol = cursor.getString(cursor.getColumnIndexOrThrow(SettingsContract.AddressSettingsEntry.PROTOCOL));
ipText.setText(ip);
portText.setText(String.valueOf(port));
protocolText.setText(protocol);
}
}
回答我自己的问题:最后证明是布局问题。我没有考虑到的是我的 Fragment
其中我的 ListView
是在 ScrollView
中创建的(这不是我在问题中发布的布局 xml 的一部分. 在 ScrollView
中,选项列表(指向各种设置的链接)被我的 Fragment
替换,其中包含 ListView
。但是,原始的 ScrollView
不一定填写屏幕的全高,所以我只需要将属性 android:fillViewport
设置为 ScrollView
的 XML 并将其设置为 true
。这允许 ListView
拉伸到屏幕底部,我最初认为它们没有被我的适配器考虑的项目突然变得可见。
这是父级 ScrollView
的简化来源(在 FrameLayout
内)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/settings_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="@color/colorDarkTransparentBackground">
<ScrollView
android:id="@+id/settings_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingStart="20dp"
android:paddingLeft="20dp"
android:paddingTop="5dp"
android:paddingEnd="20dp"
android:paddingRight="20dp"
android:paddingBottom="20dp"
android:fillViewport="true"
android:visibility="visible" />
</FrameLayout>
我正在开发一个适配器,它应该显示从 SQLite 数据库派生的项目列表。 ListView
嵌入在 Fragment
中,填充在自定义适配器中,从 ResourceCursorAdapter
子class 编辑。遍历光标并打印其内容显示它包含许多条目。但是,bindView
仅在第一个条目时被调用,这是 ListView
中显示的唯一条目。我做错了什么?
这是(精简的)代码:
片段XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/network_settings"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:baselineAligned="false">
<ListView
android:id="@+id/addresses_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
适配器列表项 XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/addresses_list_item"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/remote_ip_address"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="0.45"/>
<TextView
android:id="@+id/remote_port"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="0.25"/>
<TextView
android:id="@+id/address_protocol"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="0.2"/>
<ImageButton
android:id="@+id/delete_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/delete_address"
android:src="@drawable/close"/>
</LinearLayout>
片段class(简化,只包含onCreateView
,因为那是适配器被实例化的地方。片段本身工作正常)
public class NetworkSettingsFragment extends Fragment {
private View mView;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.network_settings, container, false);
final SQLiteDatabase db = mActivity.getDatabase();
final ListView addressesList = mView.findViewById(R.id.addresses_list);
final String[] addrFields = new String[]{
SettingsContract.AddressSettingsEntry._ID,
SettingsContract.AddressSettingsEntry.IP_ADDRESS,
SettingsContract.AddressSettingsEntry.PORT,
SettingsContract.AddressSettingsEntry.PROTOCOL
};
final String sortOrder = SettingsContract.AddressSettingsEntry.IP_ADDRESS + " DESC";
final Cursor addressesCursor = db.query(
SettingsContract.AddressSettingsEntry.TABLE_NAME,
addrFields,
null,
null,
null,
null,
sortOrder
);
final AddressesListAdapter addressesListAdapter = new AddressesListAdapter(
getActivity(), R.layout.address_list_item, addressesCursor, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER
);
addressesList.setAdapter(addressesListAdapter);
}
}
适配器
public class AddressesListAdapter extends ResourceCursorAdapter {
final private static String TAG = "AddressesListAdapter";
private int mLayout;
public AddressesListAdapter(Context context, int layout, Cursor c, int flags) {
super(context, layout, c, flags);
mLayout = layout;
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(mLayout, parent, false);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
Log.d(TAG, "the view: " + view + "\ncursor: " + cursor.getPosition() + "\nnum items: " + cursor.getCount());
TextView ipText = view.findViewById(R.id.remote_ip_address);
TextView portText = view.findViewById(R.id.remote_port);
TextView protocolText = view.findViewById(R.id.address_protocol);
final long id = cursor.getLong(cursor.getColumnIndexOrThrow(SettingsContract.AddressSettingsEntry._ID));
final String ip = cursor.getString(cursor.getColumnIndexOrThrow(SettingsContract.AddressSettingsEntry.IP_ADDRESS));
final int port = cursor.getInt(cursor.getColumnIndexOrThrow(SettingsContract.AddressSettingsEntry.PORT));
final String protocol = cursor.getString(cursor.getColumnIndexOrThrow(SettingsContract.AddressSettingsEntry.PROTOCOL));
ipText.setText(ip);
portText.setText(String.valueOf(port));
protocolText.setText(protocol);
}
}
回答我自己的问题:最后证明是布局问题。我没有考虑到的是我的 Fragment
其中我的 ListView
是在 ScrollView
中创建的(这不是我在问题中发布的布局 xml 的一部分. 在 ScrollView
中,选项列表(指向各种设置的链接)被我的 Fragment
替换,其中包含 ListView
。但是,原始的 ScrollView
不一定填写屏幕的全高,所以我只需要将属性 android:fillViewport
设置为 ScrollView
的 XML 并将其设置为 true
。这允许 ListView
拉伸到屏幕底部,我最初认为它们没有被我的适配器考虑的项目突然变得可见。
这是父级 ScrollView
的简化来源(在 FrameLayout
内)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/settings_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="@color/colorDarkTransparentBackground">
<ScrollView
android:id="@+id/settings_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingStart="20dp"
android:paddingLeft="20dp"
android:paddingTop="5dp"
android:paddingEnd="20dp"
android:paddingRight="20dp"
android:paddingBottom="20dp"
android:fillViewport="true"
android:visibility="visible" />
</FrameLayout>