ViewPager PagerAdapter with cursor - CursorLoader.onLoadFinished 不会被不同的查询调用

Posted

技术标签:

【中文标题】ViewPager PagerAdapter with cursor - CursorLoader.onLoadFinished 不会被不同的查询调用【英文标题】:ViewPager PagerAdapter with cursor - CursorLoader.onLoadFinished doesnt get called with different query 【发布时间】:2012-09-27 11:01:48 【问题描述】:

我正在做一个从数据库中提取报价的报价应用程序,我需要在 ViewPager 中显示报价。

我创建了我的 CursorPagerAdapter,它似乎运行良好。

public class MyCursorPagerAdapter extends PagerAdapter 

    private Cursor cursor;
    private LayoutInflater inflater;

public MyCursorPagerAdapter(Context context, Cursor cursor) 

    Log.d(MainActivity.TAG, "MyCursorPagerAdapter.onCreate()");

    this.cursor = cursor;
    this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);


public void swapCursor(Cursor cursor) 
    //if(cursor != null) 

        Log.d(MainActivity.TAG, "swapCursor().");

        this.cursor = cursor;
        //notifyDataSetChanged();
    //


/**
 * Metóda destroyItem
 */
@Override
public void destroyItem(View view, int position, Object object) 

    //cursor.moveToPosition(position);
    ((ViewPager) view).removeView((LinearLayout) object);


/**
 * Vráti počet prvkov
 */
@Override
public int getCount() 
    if(cursor == null) 
        return 0;
     else 
        //return cursor.getCount();
        return 1000;
    



@Override
public Object instantiateItem(View view, int position) 

    position = position % cursor.getCount();

    cursor.moveToPosition(position);

    LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.pager_item, null);

    TextView messageTextView = (TextView) layout.findViewById(R.id.message_textview);
    TextView authorTextView = (TextView) layout.findViewById(R.id.author_textview);

    messageTextView.setText(cursor.getString(cursor.getColumnIndex(QuoteDatabaseHelper.COLUMN_MESSAGE)));
    authorTextView.setText(cursor.getString(cursor.getColumnIndex(QuoteDatabaseHelper.COLUMN_AUTHOR)));

    ((ViewPager) view).addView(layout);
    return layout;


/**
 * Metóda isViewFromObject
 */
@Override
public boolean isViewFromObject(View view, Object object) 
    return view == object;

我也在使用 CursorLoader 异步加载数据库

public class MainActivity extends FragmentActivity 

@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);

    myCursorPagerAdapter = new MyCursorPagerAdapter(this, null);

    pager = (ViewPager) findViewById(R.id.viewPager);
    pager.setAdapter(myCursorPagerAdapter);

    getSupportLoaderManager().initLoader(-1, null, this);



@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) 
    return new CursorLoader(this, QuoteContentProvider.CONTENT_URI, null, null, null, null);


@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) 

    Log.d(MainActivity.TAG, "onLoadFinished()");

    myCursorPagerAdapter.swapCursor(cursor);
    this.cursor = cursor;

    pager.setCurrentItem((int) (myCursorPagerAdapter.getCount() / 2), false);
    pager.startAnimation(animation);


@Override
public void onLoaderReset(Loader<Cursor> arg0) 
    myCursorPagerAdapter.swapCursor(null);
   


使用内容提供者

public class QuoteContentProvider extends ContentProvider 

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 
    Cursor cursor = db.query(TABLE_NAME, projection, selection, selectionArgs, null, null, "RANDOM()");
    cursor.setNotificationUri(getContext().getContentResolver(), uri);

    Log.d(MainActivity.TAG, "QuoteContentProvider.query() - cursor.getCount(): " + cursor.getCount());
    // getContext().getContentResolver().notifyChange(uri, null);
    return cursor;



一切正常,它可以很好地加载所有引号,但现在我需要执行搜索。所以我做了一个查询数据库的方法

public void search(String keyword) 

    Log.d(MainActivity.TAG, "Search keyword: " + keyword);
    getContentResolver().query(QuoteContentProvider.CONTENT_URI, null, QuoteContentProvider.COLUMN_AUTHOR + " LIKE '%" + keyword + "%' OR " + QuoteContentProvider.COLUMN_MESSAGE + " LIKE '%" + keyword + "%'", null, null);


查询很好,我可以看到 ContentProvider.query() 被调用并打印出 cursor.getCount(),

但是现在即使 cursor.setNotificationUri() 已设置,MainActivity 中的 onLoadFinished 也不会被调用,我认为它可以工作,因为它在应用程序启动时第一次工作。

我实际上尝试使用内容提供程序插入一些数据并调用 getContext().getContentResolver().notifyChange(uri, null);它已经触发了 OnLoadFinished,所以我不知道为什么这个不同的查询不会触发 OnLoadFinished。

非常感谢能理解这一点的人。

【问题讨论】:

【参考方案1】:

MainActivity - 添加/修改:

String getSelection()
    if(null != mSearchKeyword && mSearchKeyword.getLength()>0) 
        return QuoteContentProvider.COLUMN_AUTHOR + " LIKE '%" + mSearchKeyword + "%' OR " +    
            QuoteContentProvider.COLUMN_MESSAGE + " LIKE '%" + mSearchKeyword + "%'";
     else 
        return null;
           


String mSearchKeyword = null;

public void search(String keyword) 
    mSearchKeyword = keyword;
    Log.d(MainActivity.TAG, "Search keyword: " + keyword);
    getLoaderManager().restartLoader(-1, null, this);


@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) 
    return new CursorLoader(this, QuoteContentProvider.CONTENT_URI, null, getSelection(), null, null);

一旦方法搜索被触发,请在您的加载器上调用 getLoaderManager().restartLoader()。您的旧数据将被丢弃,restartLoader 将触发 onCreateLoader 再次被调用。

不要忘记在交换后关闭旧光标

【讨论】:

谢谢,它已经奏效了......但是..这不是预期的行为,或者是吗? 这是一种常见的做法,您可以查看 android 资源以了解其工作原理。交换后不要忘记关闭旧光标 你能告诉我那些 cursorloader 与 2 个查询一起工作的来源吗,我很难找到那些。谢谢 我的意思是LoaderManager,你是grepcode.com/file/repository.grepcode.com/java/ext/… >>cursorloader 与 2 个查询一起工作的来源每次重启都很容易捕捉到这样的想法 - 新光标为什么不在调用之间更改查询并保持相同的投影

以上是关于ViewPager PagerAdapter with cursor - CursorLoader.onLoadFinished 不会被不同的查询调用的主要内容,如果未能解决你的问题,请参考以下文章

在使用 PagerAdapter 和 ViewPager 中的选项卡之间滑动时出现问题

Android ViewPager/PagerAdapter ImageView OutOfMemoryError

Android开发技巧——ViewPager加View情况封装PagerAdapter的实现类

PagerAdapter 总是在 ViewPager 中被调用两次

有关ViewPager使用及解决ViewPager和PagerAdapter中调用notifyDataSetChanged失效问题

转载---ViewPager,PagerAdapter,FragmentPagerAdapter和FragmentStatePagerAdapter的分析对比