Android 使用 SQLite 光标显示下一项或上一项
Posted
技术标签:
【中文标题】Android 使用 SQLite 光标显示下一项或上一项【英文标题】:Android using SQLite cursor to display next item or previous item 【发布时间】:2016-05-16 19:22:05 【问题描述】:一个常见的 android 应用程序功能是在每个详细项目上滑动以获取下一个项目或上一个项目。
数据库游标包含在 ListActivity 的 onCreate 中显示的项目列表:
if (cursor.moveToFirst())
listThings.setAdapter(new ResourceCursorAdapter(this, R.layout.my_simple_expandable_list_item_2, cursor)
@Override
public void bindView(View view, Context context, Cursor cursor)
TextView tvFirst = (TextView)view.findViewById(android.R.id.text1);
TextView tvSecond = (TextView)view.findViewById(android.R.id.text2);
tvFirst.setText(cursor.getString(1) + " - " + getPctString(cursor.getString(2)));
tvSecond.setText(cursor.getString(3));
);
else
....
效果很好。内置布局资源R.layout.my_simple_expandable_list_item_2
告诉适配器在单个文本视图中显示光标中的每个项目。点击后,我可以在后续活动中显示该项目的详细信息:
AdapterView.OnItemClickListener itemClickListener = new AdapterView.OnItemClickListener()
public void onItemClick(AdapterView<?> listView, View v, int position, long id)
Intent intent = new Intent(ThingListActivity.this, ThingActivity.class);
intent.putExtra(FollowOnActivity.EXTRA_ID, (int) id);
startActivity(intent);
;
在FollowOnActivity
中,我可以查找详细信息并填充视图。我还可以收听滑动并做出反应。
问题:我无法访问列表中的下一个和上一个项目。到目前为止,我还没有提出我认为的干净的解决方案。由于这是一个常见的要求,因此可能有一个很好的模式。我想知道那是什么。
我能够让这个screen slide example 工作,但该示例中的列表固定为五个项目,并且这些项目是 xml 文件中的文本而不是数据库项目。我基于他们的ScreenSlidePagerActivity
创建了ThingSlideActivity
,基于他们的ScreenSlidePageAdapter
和ThingSlideFragment
基于他们的ScreenSlidePageFragment
创建了ThingSlidePageAdapter
。但我不知道如何将其连接到我来自的列表视图。它可能有一个很大的列表,而我尽量不提供所有这些的详细信息。
我正坐在一个已填充光标的列表视图中(此问题顶部的第一个代码块)。用户单击列表中的随机一个,onListItemClick 运行。应该怎么做才能左右滑动查看上一个和下一个项目?
【问题讨论】:
看看接受的答案here。 这个答案相当简陋;我不明白。它说“使用适配器的getItem(int position)方法,它返回给你指定位置的列表项”,但是在FollowOnActivity的OnTouchListener中,我看不到如何获取早期ListView的适配器。 【参考方案1】:您运行了一个查询,并为您的ListActivity
获得了一个Cursor
。您将 Cursor
附加到了正在显示您的列表的 CursorAdapter
。
如果用户选择第三个项目(项目 2),那么在您的 OnItemClickListener
中,position
参数将为 2。
那么,如果您将位置 (2) 传递给后续活动,在那里运行相同的查询并从光标第 2 行开始呢?使用光标,您会知道上一个、下一个……您将拥有列表中所有内容的数据!
显示大型细节视图并水平左右滑动它们的方法是使用一个名为ViewPager
的小部件。 ViewPager
是由 PagerAdapter
驱动的,它有一些相似之处,但绝对不同于 ListAdapter
。
您要做的是创建一个具有您的Cursor
的PagerAdapter
,因此当您创建一个页面时,您可以将来自Cursor
的数据提供给它。当适配器被要求提供第 3 页时,您创建一个详细视图,从光标读取第三条记录并将该数据放入详细视图中。
真的就这么简单。 ResourceCursorAdapter
在幕后做这件事。当适配器被要求提供第三项的视图时,会创建/回收一个视图,将光标定位在第三条记录上,最后调用您的 bindView
方法将数据放入视图中。
这是PagerAdapter
的粗略示例:
public class CursorPagerAdapter extends PagerAdapter
/** Note that this class does not handle closing the cursor. */
private Cursor mCursor;
public CursorPagerAdapter(Cursor mCursor)
this.mCursor = mCursor;
@Override
public int getCount()
return mCursor == null ? 0 : mCursor.getCount();
@Override
public Object instantiateItem(ViewGroup container, int position)
mCursor.moveToPosition(position);
String data1 = mCursor.getString(1);
String data2 = mCursor.getString(2);
String data3 = mCursor.getString(3);
View view = LayoutInflater.from(container.getContext()).inflate(R.layout.detail_view, container, false);
// TODO fill in the view with the cursor data
container.addView(view);
return view;
@Override
public boolean isViewFromObject(View view, Object object)
return view == object;
ViewPager
是一个狡猾的小家伙,但作为一名 Android 开发人员,你迟早会需要它,所以现在就开始学习如何使用它们是件好事。我建议您深入研究并查看任何您可以获得的 ViewPager
教程。
【讨论】:
ViewPager 可能是我正在寻找的“好模式”! 很多滑动视图教程都在更改选项卡,这当然不是我想要的。搜索“viewpager cursor swipe”,我找到了***.com/questions/22162589/…,我现在正在解决这个问题。【参考方案2】:这就是最终的工作。它使用来自 developer.android.com/training 的screen-slide example 中的模式,但有一个区别:在ThingSlideActivity.getItem()
中,我使用了ThingSlideFragment.onCreate(pos)
,而不是运行ThingSlideFragment.onCreate(pos)
。此外,我添加了static Cursor getCursor()
,它提供了最初填充ListActivity
的原始Cursor
。这允许我从列表中的位置转换为数据库键。如果这个模式有什么问题,请指教。
初始活动此活动有一个来自数据库的列表和一个光标保持打开状态直到列表被销毁:
public class ThingListActivity extends ListActivity
private SQLiteDatabase db;
private static Cursor cursor;
static Cursor getCursor()
return cursor;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
ListView listThings = getListView();
int position = getIntent().getIntExtra("POSITION", 0);
try
SQLiteOpenHelper tableDatabaseHelper = new TableDatabaseHelper(this);
db = tableDatabaseHelper.getReadableDatabase();
cursor = db.query("TABLE", pullFields, selectionFields, selectionArgs, null, null, null); // you define your own query
if (cursor.moveToFirst())
listThings.setAdapter(new ResourceCursorAdapter(this, R.layout.my_simple_expandable_list_item_2, cursor) //built-in layout
@Override
public void bindView(View view, Context context, Cursor cursor)
TextView tvFirst = (TextView)view.findViewById(android.R.id.text1);
TextView tvSecond = (TextView)view.findViewById(android.R.id.text2);
tvFirst.setText(cursor.getString(1) + " - " + getPctString(cursor.getString(2)));
tvSecond.setText(cursor.getString(3));
);
else
Toast toast = Toast.makeText(this, "The list was empty.", Toast.LENGTH_SHORT);
toast.show();
catch (SQLiteException e)
Toast toast = Toast.makeText(this, "Database Unavailable", Toast.LENGTH_SHORT);
toast.show();
finally
//Not closing cursor. Will do in onDestroy()
@Override
public void onDestroy()
super.onDestroy();
if (cursor != null) cursor.close();
if (db != null) db.close();
@Override
protected void onListItemClick(ListView listView, View view, int position, long id)
Intent intent = new Intent(ThingListActivity.this, ThingSlideActivity.class);
intent.putExtra(ThingSlideActivity.EXTRA_POSITION, (int) position);
startActivity(intent);
后续FragmentActivity
。此活动有一个内部类ThingSlidePageAdapter
。注意setCurrentItem
,它将您放在列表中的正确位置。 :
public class ThingSlideActivity extends FragmentActivity
public static final String EXTRA_POSITION = "extra_position";
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_slide);
ViewPager mPager = (ViewPager)findViewById(R.id.pager);
PagerAdapter mPagerAdapter = new ThingSlidePageAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setCurrentItem((Integer)getIntent().getExtras().get(EXTRA_POSITION));
private static class ThingSlidePageAdapter extends FragmentStatePagerAdapter
int count;
public ThingSlidePageAdapter(FragmentManager fm)
super(fm);
this.count = ThingListActivity.getCursor().getCount();
@Override
public int getCount()
return this.count;
@Override
public Fragment getItem(int position)
return ThingSlideFragment.newInstance(position); // onCreate() doesn't work well.
**我们正在翻页的Fragment
。这是我们使用原始ListView
中的Cursor
来获取数据库密钥(_id
)的地方。然后执行一个新的查询,只提取一个项目的详细信息。但在幕后,上一个和下一个项目也被拉出来了。
public class ThingSlideFragment extends Fragment
private static final String ARG_POSITION = "position";
public static ThingSlideFragment create(int position)
ThingSlideFragment fragment = new ThingSlideFragment();
Bundle args = new Bundle();
args.putInt(ARG_POSITION, position);
fragment.setArguments(args);
return fragment;
public static ThingSlideFragment newInstance(int position)
ThingSlideFragment fragment = new ThingSlideFragment();
Bundle args = new Bundle();
args.putInt(ARG_POSITION, position);
fragment.setArguments(args);
return fragment;
public ThingSlideFragment()
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.activity_thing, container, false);
TextView tv = (TextView)rootView.findViewById(R.id.thingname);
Cursor mCursor = ThingListActivity.getCursor();
if (mCursor != null)
mCursor.moveToPosition(getArguments().getInt(ARG_POSITION));
int id = Integer.parseInt(mCursor.getString(0));
populateView(id, rootView);
return rootView;
private void populateView(int id, View rootView)
Cursor cursor = null;
SQLiteDatabase db = null;
try
SQLiteOpenHelper tableDatabaseHelper = new TableDatabaseHelper(this.getContext()) ;
db = tableDatabaseHelper.getReadableDatabase();
cursor = db.query("TABLE", new String[] "NAME", "DESCRIPTION", "DETAIL1", "DETAIL2", "DETAIL3", "DETAIL4", "_id = ?", new String[] Integer.toString(id), null, null, null);
//Move to first record in the cursor (should be just one since our query used database key "CREATE TABLE TABLE (_id INTEGER PRIMARY KEY AUTOINCREMENT, ...."
if (cursor.moveToFirst())
// Get thing details from the cursor
String nameText = cursor.getString(0);
String descriptionText = cursor.getString(1);
// ........ continue with other fields
// Populate TextView items
((TextView)rootView.findViewById(R.id.thingname)).setText(nameText);
((TextView)rootView.findViewById(R.id.description)).setText(descriptionText);
// ........ continue with other fields
catch (SQLiteException e)
Toast toast = Toast.makeText(this.getContext(), "Database unavailable. "+ e.getMessage(), Toast.LENGTH_LONG) ;
finally
try cursor.close(); catch (Throwable t)
try db.close(); catch (Throwable t)
而且,这里的许多示例都省略了支持 xml 文件的内容!
<!-- R.layout.activity_screen_slide.xml containing R.id.pager -->
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_
android:layout_ />
<!-- R.layout.activity_thing.xml containing R.id.thingname and R.id.description -->
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:id="@+id/thingRelativeLayout"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.someones.package.ThingActivity"
tools:showIn="@layout/activity_thing">
<TextView
android:id="@+id/thingname"
android:layout_
android:layout_
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:paddingTop="40dp"
android:textSize="40dp"
android:gravity="center"
tools:text="Name Of Thing"
/>
<TextView
android:id="@+id/description"
android:layout_
android:layout_
android:layout_alignParentLeft="true"
android:textSize="20dp"
android:layout_below="@id/thingname"
android:paddingTop="10dp"
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris et magna ut erat elementum cursus in quis ipsum. Nam faucibus ultrices eros, vel tempor leo semper sit amet."
/>
</RelativeLayout>
</ScrollView>
我希望这对您有用,并希望很多人能够找到它并从中受益,因为我花了几天时间摆弄它,直到我满意为止。对于这里经验丰富的人来说可能一个简单的,但对具有一定经验的人有帮助。
【讨论】:
以上是关于Android 使用 SQLite 光标显示下一项或上一项的主要内容,如果未能解决你的问题,请参考以下文章
Android - 关闭数据库后可以使用 SQLite 光标吗?
如何使用光标和循环显示来自 sqlite 的片段的 recyclerview