ViewPager PagerAdapter with cursor - CursorLoader.onLoadFinished doesnt get called with different query
Asked Answered
D

1

8

I am doing like a quote application that pulls the quotes from the database and I need to display quotes in a ViewPager.

I have created my CursorPagerAdapter which seems to work well.

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;
}

}

I am also using CursorLoader to async-load the database

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);
}   

}

With ContentProvider

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;
}

}

Everything works well, it loads all quotes nicely, but now I need to perform search. So I make a method that queries the database

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);

}

The query is good, I can see ContentProvider.query() getting called and prints out cursor.getCount(),

HOWEVER now the onLoadFinished in MainActivity doesnt get called even though the cursor.setNotificationUri() is set, and I presume its working because it works the first time when the application starts.

I actually tried to insert some data with content provider and calling getContext().getContentResolver().notifyChange(uri, null); and it HAS triggered the OnLoadFinished so I have no idea why this different query doesnt fire the OnLoadFinished.

Thank you very much who will make sense of this.

Drab answered 6/10, 2012 at 14:24 Comment(0)
P
4

MainActivity - add/modify:

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);
}

Once the method search is fired, call getLoaderManager().restartLoader() on your Loader. Your old data will be discarded and restartLoader will trigger onCreateLoader to be called again.


Do not forget close old cursor after it is swapped

Plum answered 6/10, 2012 at 21:51 Comment(7)
thank you, it has worked...but..this cant be expected behaviour, or is it?Drab
it is common practice, you can look to android sources to learn how it works. Do not forget close old cursor after it is swappedPlum
could you show me those sources where cursorloader works with 2 queries, I am having hard time finding those. ThanksDrab
I have mean LoaderManager, here you are grepcode.com/file/repository.grepcode.com/java/ext/…Plum
>>sources where cursorloader works with 2 queries<br>It is easy to catch a such idea each restart - new cursor why do not change query between calls and keep the same projectionPlum
I get your answer, it works, but I just dont see it as a good practise, Ideally I think you should just call contentResolver.query(URI), ten switch that URI in contentProvider.query and do appropriate query on database and return the cursor with that notification and cursorLoader will reload it and than I can swap it on the adapter. That would be nice. This just creates new objects each time etc etc, but I will accept your answer. Thanks for your timeDrab
Your idea how it should work is wrong. Look why you have to use loader if you can just query data ? and look here for more #7183420Plum

© 2022 - 2024 — McMap. All rights reserved.