OK so I have a rather annoying issue. I am simply attempting to list all the songs on the device using a CursorLoader and LoaderCallbacks. My problem is simply that nothing is being displayed. I am using EXACTLY the same method as I am to load all albums, artists and playlists on the device. Using some debugging I have discovered that the problem is that newView() is only being called once within the CursorAdapter
Here is my CursorAdapter:
private class SongItemAdapter extends CursorAdapter
{
public SongItemAdapter(Context context)
{
super(context, null, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor)
{
final int albumId = cursor.getInt(cursor
.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
final String songName = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
final String artistName = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
final String duration =
Utilities.milliSecondsToTimer(
cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION)));
final ImageView albumCover = (ImageView) view.findViewById(R.id.all_songs_album_cover);
final TextView songNameTextView = (TextView) view.findViewById(R.id.all_songs_song_name);
final TextView artistNameTextView = (TextView) view.findViewById(R.id.all_songs_artist_name);
final TextView durationTextView = (TextView) view.findViewById(R.id.all_songs_song_duration);
ImageLoader.getInstance().displayImage(
ContentUris.withAppendedId(
sArtworkUri, albumId).toString(), albumCover);
songNameTextView.setText(songName);
artistNameTextView.setText(artistName);
durationTextView.setText(duration);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent)
{
return LayoutInflater.from(context).inflate(R.layout.song_list_item, parent, false);
}
}
Here is my LoaderCallbacks:
private final LoaderCallbacks<Cursor> mCursorCallbacks = new LoaderCallbacks<Cursor>()
{
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args)
{
return new CursorLoader(getActivity(),
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, Song.FILLED_PROJECTION, MediaStore.Audio.Media.IS_MUSIC + "!=0", null,
MediaStore.Audio.Media.TITLE + " ASC");
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data)
{
mAdapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader)
{
mAdapter.swapCursor(null);
}
};
And here is the initialisation of my adapter and listview and whatnot:
mAdapter = new SongItemAdapter(this.getActivity());
mListView = (ListView) rootView.findViewById(R.id.all_songs_list);
mListView.setOnItemClickListener(this);
mListView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), false, false));
mListView.setAdapter(mAdapter);
mListView.setFastScrollEnabled(true);
mListView.setFastScrollAlwaysVisible(true);
mListView.setRecyclerListener(new RecyclerListener()
{
#Override
public void onMovedToScrapHeap(View view)
{
// Release strong reference when a view is recycled
final ImageView imageView = (ImageView) view.findViewById(R.id.all_songs_album_cover);
imageView.setImageBitmap(null);
}
});
getLoaderManager().initLoader(LOADER_CURSOR, null, mCursorCallbacks);
As I stated previously, this is exactly the method I use for loading albums, artists and playlists and those are working fine.
Related
Right now I am trying to use recyclerview with a cursorloader. I included the cursorloader within my recyclerview adapter based on my research. I do not have the desire to put my SQLite database data into an arraylist. Right now it looks like my code is correct but when I load the app I get a blank screen. Can anyone help me see my mistake in my code?
Here is my adapter:
public class PrescriptionRecyclerAdapter extends RecyclerView.Adapter<PrescriptionRecyclerAdapter.ViewHolder> {
private CursorAdapter mCursorAdapter;
private Context mContext;
private ViewHolder holder;
Cursor prescriptionCursor;
public PrescriptionRecyclerAdapter(Context context, Cursor c) {
mContext = context;
prescriptionCursor = c;
mCursorAdapter = new CursorAdapter(mContext, c, 0) {
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Inflate the view here
View v = LayoutInflater.from(context)
.inflate(R.layout.recycle_item, parent, false);
return v;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// Extract data from the current store row and column
int nameColumnIndex = cursor.getColumnIndex(PrescriptionContract.PrescriptionEntry.COLUMN_PRESCRIPTION_NAME);
int amountColumnIndex = cursor.getColumnIndex(PrescriptionContract.PrescriptionEntry.COLUMN_PRESCRIPTION_AMOUNT);
int durationColumnIndex = cursor.getColumnIndex(PrescriptionContract.PrescriptionEntry.COLUMN_PRESCRIPTION_FREQUENCY_DURATION);
final int columnIdIndex = cursor.getColumnIndex(PrescriptionContract.PrescriptionEntry._ID);
//Read the store attritubes from the Cursor for the current stores
String name = cursor.getString(nameColumnIndex);
String amount = cursor.getString(amountColumnIndex);
String duration = cursor.getString(durationColumnIndex);
String col = cursor.getString(columnIdIndex);
// Populate fields with extracted properties
holder.prescriptionName.setText(name);
holder.prescriptionAmount.setText(amount);
holder.prescriptionDays.setText(duration);
}
};
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView prescriptionName;
public TextView prescriptionAmount;
public TextView prescriptionDays;
final public Button prescriptionButton;
public ViewHolder(View itemView) {
super(itemView);
// Find fields to populate in inflated template
prescriptionName = (TextView) itemView.findViewById(R.id.name);
prescriptionAmount = (TextView) itemView.findViewById(R.id.amountlist);
prescriptionDays = (TextView) itemView.findViewById(R.id.daysList);
prescriptionButton = itemView.findViewById(R.id.scheduleButton);
}
}
#Override
public int getItemCount() {
return mCursorAdapter.getCount();
}
public Cursor swapCursor(Cursor cursor) {
if (prescriptionCursor == cursor) {
return null;
}
Cursor oldCursor = prescriptionCursor;
this.prescriptionCursor = cursor;
if (cursor != null) {
this.notifyDataSetChanged();
}
return oldCursor;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Passing the binding operation to cursor loader
mCursorAdapter.getCursor().moveToPosition(position);
mCursorAdapter.bindView(holder.itemView, mContext, mCursorAdapter.getCursor());
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Passing the inflater job to the cursor-adapter
View v = mCursorAdapter.newView(mContext, mCursorAdapter.getCursor(), parent);
holder = new ViewHolder(v);
return holder;
}
}
Here is my display activity.
public class DisplayActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>{
private static final int PRESCRIPTION_LOADER = 0;
PrescriptionRecyclerAdapter mCursorAdapter;
private RecyclerView.LayoutManager mLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(DisplayActivity.this, EditorActivity.class);
startActivity(intent);
}
});
RecyclerView prescriptionRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mLayoutManager = new LinearLayoutManager(getApplicationContext());
prescriptionRecyclerView.setLayoutManager(mLayoutManager);
mCursorAdapter = new PrescriptionRecyclerAdapter(this, null);
prescriptionRecyclerView.setAdapter(mCursorAdapter);
//Kick off the loader
getLoaderManager().initLoader(PRESCRIPTION_LOADER,null,this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_display, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// User clicked on a menu option in the app bar overflow menu
switch (item.getItemId()) {
// Respond to a click on the "Delete all entries" menu option
case R.id.action_delete_all_entries:
deleteAllPrescriptions();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Helper method to delete all items in the database.
*/
private void deleteAllPrescriptions() {
int rowsDeleted = getContentResolver().delete(PrescriptionEntry.CONTENT_URI, null, null);
Log.v("CatalogActivity", rowsDeleted + " rows deleted from prescription database");
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
// Since the editor shows all store attributes, define a projection that contains
// all columns from the store table
String[] projection = {
PrescriptionEntry._ID,
PrescriptionEntry.COLUMN_PRESCRIPTION_NAME,
PrescriptionEntry.COLUMN_PRESCRIPTION_AMOUNT,
PrescriptionEntry.COLUMN_PRESCRIPTION_FREQUENCY_HOURS,
PrescriptionEntry.COLUMN_PRESCRIPTION_FREQUENCY_TIMES,
PrescriptionEntry.COLUMN_PRESCRIPTION_FREQUENCY_DURATION,
PrescriptionEntry.COLUMN_PRESCRIPTION_REFILL,
PrescriptionEntry.COLUMN_PRESCRIPTION_EXPIRATION,
PrescriptionEntry.COLUMN_PRESCRIPTION_PHARMACIST_NAME,
PrescriptionEntry.COLUMN_PRESCRIPTION_PHARMACIST_NUMBER,
PrescriptionEntry.COLUMN_PRESCRIPTION_PHYSICIAN_NAME,
PrescriptionEntry.COLUMN_PRESCRIPTION_PHYSICIAN_NUMBER};
// This loader will execute the ContentProvider's query method on a background thread
return new CursorLoader(this, // Parent activity context
PrescriptionEntry.CONTENT_URI, // Query the content URI for the current store
projection, // Columns to include in the resulting Cursor
null, // No selection clause
null, // No selection arguments
null); // Default sort order
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mCursorAdapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
mCursorAdapter.swapCursor(null);
}
}
I think i got your problem. After getting new Cursor in onLoadFinished method you are calling PrescriptionRecyclerAdapter's swapCursor() method this method is updating prescriptionCursor Cursor reference. Thats OK. But updating prescriptionCursor will not effect your CursorAdapter. You are actually dependent on CursorAdapter. So you have to update theCursor of your CursorAdapter. Because your mCursorAdapter still holding the old reference of the Cursor you have provided in constructor.
So use this method to update Cursor reference mCursorAdapter.swapCursor(prescriptionCursor).
public Cursor swapCursor(Cursor cursor) {
if (prescriptionCursor == cursor) {
return null;
}
Cursor oldCursor = prescriptionCursor;
this.prescriptionCursor = cursor;
if (cursor != null) {
this.notifyDataSetChanged();
// update your Cursor for CursorAdapter
mCursorAdapter.swapCursor(prescriptionCursor);
}
return oldCursor;
}
I think you have made it complex by maintaining two Adapter. You can use RecyclerView.Adapter with List or Cursor. There is not need to make it complex.
Hope it will help you. Let me know it solve your problem.
I'm trying to populate a recyclerview with a loader but the adapter will only bind the first five items on the database and then repeat for every other item in the database.
To make it clear, it looks like this:
item 1
item 2
item 3
item 4
item 5
item 1
item 2
...
The number of items still matches the number of items on the database though. I've also tested the cursor and it prints every item correctly so I'm assuming the problem is the adapter. This is what I'm using:
class LibraryAdapter extends RecyclerView.Adapter<LibraryAdapter.LibraryViewHolder> {
private Context mContext;
private Cursor mCursor;
LibraryAdapter(Context context, Cursor cursor){
this.mContext = context;
this.mCursor = cursor;
setHasStableIds(true);
}
static class LibraryViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView titleText;
private TextView numText;
LibraryViewHolder(View itemView) {
super(itemView);
titleText = (TextView) itemView.findViewById(R.id.titleText);
numText = (TextView) itemView.findViewById(R.id.numText);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
....
}
}
#Override
public LibraryAdapter.LibraryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
return new LibraryViewHolder(view);
}
#Override
public void onBindViewHolder(LibraryAdapter.LibraryViewHolder holder, int position) {
LibraryModel item = getData(position);
holder.titleText.setText(item.getTitle());
holder.numText.setText(item.getNum() + " items");
}
#Override
public int getItemCount() {
return (mCursor != null) ? mCursor.getCount() : 0;
}
private Cursor swapCursor(Cursor cursor){
if(mCursor == cursor){
return null;
}
Cursor oldCursor = mCursor;
this.mCursor = cursor;
if(cursor != null){
this.notifyDataSetChanged();
}
return oldCursor;
}
void changeCursor(Cursor cursor){
Cursor oldCursor = swapCursor(cursor);
if (oldCursor != null){
oldCursor.close();
}
}
private LibraryModel getData(int position){
mCursor.moveToPosition(position);
String title = mCursor.getString(mCursor.getColumnIndex(DatabaseContract.LibraryEntry.COLUMN_TITLE));
int num = mCursor.getInt(mCursor.getColumnIndex(DatabaseContract.LibraryEntry.COLUMN_NUMBER));
LibraryModel item = new LibraryModel();
item.setTitle(title);
item.setNum(num);
return item;
}
}
And on the fragment:
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_alltracks, container, false);
libraryRecyclerview = (RecyclerView) root.findViewById(R.id.list);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getContext());
libraryRecyclerview.setLayoutManager(mLayoutManager);
mAdapter = new LibraryAdapter(getContext(), null, allTracks);
libraryRecyclerview.setAdapter(mAdapter);
return root;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(1, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri uri = DatabaseContract.LibraryEntry.CONTENT_URI;
String[] projection = {
DatabaseContract.LibraryEntry.TABLE_NAME + "." + DatabaseContract.LibraryEntry._ID,
DatabaseContract.LibraryEntry.COLUMN_TITLE,
DatabaseContract.LibraryEntry.COLUMN_NUM
};
return new CursorLoader(getContext(), uri, projection, null, null, null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.changeCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.changeCursor(null);
}
For anyone still stumbling into this question:
I had the same problem, repeating the same 5 entries in my recycler view.
What fixed my problem was simply to remove
adapter.setHasStableIds(true)
Granted, this got me up to other problems, but I managed to display all my entries with this.
I have a ChatActivity, which loads its data via a CursorLoader. The CursorLoader return a cursor with two registers, but the newView and bindView methods in adapter is never called.
My activity
public class ChatActivity extends BaseActivity implements LoaderManager.LoaderCallbacks<Cursor> {
public static final String EXTRA_AMANTEID = "amanteId";
private EditText messageET;
private ListView messagesContainer;
private Button sendBtn;
private ChatAdapter adapter;
private Long amanteId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
amanteId = getIntent().getLongExtra(ChatActivity.EXTRA_AMANTEID, 0L);
messagesContainer = (ListView) findViewById(R.id.messagesContainer);
messageET = (EditText) findViewById(R.id.messageEdit);
sendBtn = (Button) findViewById(R.id.chatSendButton);
RelativeLayout container = (RelativeLayout) findViewById(R.id.container);
adapter = new ChatAdapter(this);
getLoaderManager().initLoader(0, null, this);
messagesContainer.setAdapter(adapter);
}
private void scroll() {
messagesContainer.setSelection(messagesContainer.getCount() - 1);
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new CursorLoader(ChatActivity.this, MensagemProvider.CONTENT_URI_CONVERSA, null, null, new String[]{Long.toString(amanteId), Long.toString(amanteId)}, null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
}
My adapter
public class ChatAdapter extends CursorAdapter {
private Cursor cursor;
private int dataEnvioColumnIndex;
private int idMensagemColumnIndex;
private int idRemetenteColumnIndex;
private int idDestinatarioColumnIndex;
private int apelidoRemetenteColumnIndex;
private int apelidoDestinatarioColumnIndex;
private int textoMensagemColumnIndex;
private long idColaboradorLogado;
public ChatAdapter(Context context) {
super(context, null, false);
}
public ChatMessage getItem() {
ChatMessage message = new ChatMessage();
SimpleDateFormat dt = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Date dataEnvio = new Date(cursor.getLong(dataEnvioColumnIndex));
message.setDate(dt.format(dataEnvio));
message.setId(cursor.getLong(idMensagemColumnIndex));
Long de = cursor.getLong(idRemetenteColumnIndex);
Long logado = BaseApp.getCredentials().getId();
message.setMe(de.equals(logado));
message.setMessage(cursor.getString(textoMensagemColumnIndex));
return message;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View retView = vi.inflate(R.layout.list_item_chat_message, null);
return retView;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder = createViewHolder(view);;
view.setTag(holder);
ChatMessage chatMessage = getItem();
boolean myMsg = chatMessage.getIsme() ;//Just a dummy check
holder.txtMessage.setText(chatMessage.getMessage());
holder.txtInfo.setText(chatMessage.getDate());
}
private ViewHolder createViewHolder(View v) {
ViewHolder holder = new ViewHolder();
holder.txtMessage = (TextView) v.findViewById(R.id.txtMessage);
holder.content = (LinearLayout) v.findViewById(R.id.content);
holder.contentWithBG = (LinearLayout) v.findViewById(R.id.contentWithBackground);
holder.txtInfo = (TextView) v.findViewById(R.id.txtInfo);
return holder;
}
private static class ViewHolder {
public TextView txtMessage;
public TextView txtInfo;
public LinearLayout content;
public LinearLayout contentWithBG;
}
#Override
public Cursor swapCursor(Cursor cursor) {
if(cursor!=null) {
cursor.moveToFirst();
idMensagemColumnIndex = cursor.getColumnIndex(MensagemProvider.COLUMN_MENSAGEMID);
idRemetenteColumnIndex = cursor.getColumnIndex(MensagemProvider.COLUMN_DE);
idDestinatarioColumnIndex = cursor.getColumnIndex(MensagemProvider.COLUMN_PARA);
apelidoRemetenteColumnIndex = cursor.getColumnIndex(MensagemProvider.COLUMN_APELIDO_REMETENTE);
apelidoDestinatarioColumnIndex = cursor.getColumnIndex(MensagemProvider.COLUMN_APELIDO_DESTINATARIO);
textoMensagemColumnIndex = cursor.getColumnIndex(MensagemProvider.COLUMN_MENSAGEM);
}
notifyDataSetChanged();
return cursor;
}
}
what I'm doing wrong ? Can anybody help me ?
Thanks!
Overriding swapCursor() is asking for trouble. The cursor won't be positioned where the adapter expects it to be positioned (before first). And you don't call super.swapCursor() so the adapter never really hears about the new cursor.
I bet you're trying to "optimize" by getting the column indexes only once each time a new cursor is swapped.
First just try getting rid of the swapCursor() override and making the getColumnIndex() calls in your getItem() method. If that works and you still really want to have getColumnIndex() called only once per cursor, you could try something like setting all your cursor indexes to -1 when you swap the cursor, then calling getColumnIndex() inside getItem() only when the index is -1.
But don't mess with swapCursor(), especially without calling super.swapCursor() and returning its result.
I want to display a list of songs on clicking the album in a grid.
Here's my code for DisplayAlbum extends AppCompatActivity implements LoaderManager.LoaderCallbacks
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.album_detail);
Intent i = getIntent();
b = i.getExtras();
String str;
// if((str =(String) b.getCharSequence("album_name"))!= null)
// Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT).show();
val = new String[]{(String) b.getCharSequence("album_name")};
ListView lv = (ListView) findViewById(R.id.al_songs);
mAdapter = new DisplaySongsAdapter(this, null);
lv.setAdapter(mAdapter);
}
static final String[] ALBUM_DETAIL_PROJECTION = { MediaStore.Audio.Media._ID,MediaStore.Audio.Media.ALBUM_ID,MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.DURATION};
String where = MediaStore.Audio.Media.ALBUM + "=?";
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String orderby = MediaStore.Audio.Media.TITLE;
return new CursorLoader(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,ALBUM_DETAIL_PROJECTION, where, val, orderby);
}
And this is the code for DisplaySongsAdapter extends CursorAdapter
public DisplaySongsAdapter(Context context, Cursor c) {
super(context, c);
mcontext=context;
nInflater = LayoutInflater.from(context);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView songTitle = (TextView) view.findViewById(R.id.songTitle);
songTitle.setText(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE)));
TextView alname = (TextView) view.findViewById(R.id.al_name);
alname.setText(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM)));
TextView artist = (TextView) view.findViewById(R.id.songArtist);
artist.setText(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST)));
ImageView albumArt = (ImageView) view.findViewById(R.id.list_image);
albumArt.setScaleType(ImageView.ScaleType.FIT_XY);
ImageView albumimg = (ImageView) view.findViewById(R.id.al_art);
albumimg.setScaleType(ImageView.ScaleType.FIT_XY);
ImageButton listmenu = (ImageButton) view.findViewById(R.id.expanded_menu);
listmenu.setOnClickListener(overflowClickListener);
Long albumId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
Bitmap img = getAlbumart(context,albumId);
if(img != null) {
albumArt.setImageBitmap(img);
albumimg.setImageBitmap(img);
}
else{
Bitmap def = getDefaultAlbumArt(context);
albumArt.setImageBitmap(def);
albumimg.setImageBitmap(img);
}
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final View view = nInflater.inflate(R.layout.song_item, parent, false);
return view;
}
But the activity doesnt populate the listview. It simply shows a blank inflated layout. Why is that the case? Where did I go wrong?
It might be related to the fact that you don't actually feed any items in the adapter :-)
mAdapter = new DisplaySongsAdapter(this, null);
I solved it using a SimpleCursorAdapter. However I would still like to know a way around with LoaderManager
Good day all, please been having this trouble and i can't seem to see why. Basically what am trying to do is pick a contact via the contact api, save in database, and then display in a listview. but for some reason, after i get the contacts details, my custom adapter is not called anymore, its only called on when the activity is first created, and hence empty. Please what could i have missed. Thank you.
heres my code:
public class GroupDetails extends FragmentActivity implements OnClickListener, LoaderCallbacks<Cursor> {
//variable for debugging the application
public static final String TAG = "MyApp.Debug";
//request code for using with action pick intent
static final int PICK_CONTACT = 1;
//initial variables
Button add_button;
TextView label;
ListView list;
ResponderDB dbadapter;
DueCustomCursorAdapter cursoradapter;
//DueCustomCursorLoader loader;
//cursor to retrieve contact details
private Cursor contactsCursor;
String groupname;
long rowId;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.group_detail_list);
//only intialize here. database will be open in custom cursor loader
dbadapter = new ResponderDB(this);
getSupportLoaderManager().initLoader(0, null, this);
/*Read intent and the extras passed*/
Bundle extra = getIntent().getExtras();
if(!extra.isEmpty() || extra.equals(null)){
groupname = extra.getString("group_name");
rowId = extra.getLong("rowId");
}
list = (ListView)findViewById(android.R.id.list);
add_button = (Button)findViewById(R.id.add_button_id);
label = (TextView)findViewById(R.id.group_label_id);
Log.d(TAG, "calling custom adapter here now");
cursoradapter = new DueCustomCursorAdapter(GroupDetails.this, null, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER );
list.setAdapter(cursoradapter);
add_button.setOnClickListener(this);
}
#Override
public void onClick(View view) {
int selection = view.getId();
if(selection == R.id.add_button_id){
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, PICK_CONTACT);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode == PICK_CONTACT){
getContactInfo(data);
}
}
private void getContactInfo(Intent intent) {
String number = null;
String name = null;
String[] projection = {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER};
CursorLoader loader = new CursorLoader(this,intent.getData(),
null,null,null,null);
contactsCursor = loader.loadInBackground();
if(contactsCursor.moveToFirst()){
String id = contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.Contacts._ID));
name = contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
//get the Phone Number
Cursor numberCursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI
, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] {id}, null);
while(numberCursor.moveToNext()){
number = numberCursor.getString(numberCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
}
}
Log.d(TAG, "Successfully added contacts for group");
//dbadapter.updateGroup(rowId, values);
dbadapter.saveContacts(name, number, String.valueOf(rowId));
cursoradapter.notifyDataSetChanged();
getSupportLoaderManager().getLoader(0).onContentChanged();
}
public static final class DueCustomCursorLoader extends SimpleCursorLoader {
public static final String TAG = "MyApp.Debug";
public static int RETRIEVE_CODE = 1;
ResponderDB dbadapter1;
int retrieveCode;
public DueCustomCursorLoader(Context context, ResponderDB dbadapter) {
super(context);
this.dbadapter1= dbadapter;
}
public DueCustomCursorLoader(Context context, ResponderDB dbadapter, int retrieveCode){
super(context);
this.dbadapter1 = dbadapter;
this.retrieveCode = retrieveCode;
}
#Override
public Cursor loadInBackground() {
Cursor cursor = null;
dbadapter1.open();
cursor = dbadapter1.readContact(retrieveCode);
return cursor;
}
}
public class DueCustomCursorAdapter extends CursorAdapter {
public static final String TAG = "SmsResponder.Debug";
private Context myContext;
public DueCustomCursorAdapter(Context context,Cursor c, int flags) {
super(context, c, flags);
myContext = context;
}
//never seem to get here
#Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder = (ViewHolder)view.getTag();
String contactName = cursor.getString(cursor.getColumnIndexOrThrow(ResponderDB.NAME));
String contactNumber = cursor.getString(cursor.getColumnIndex(ResponderDB.NUMBER));
Log.d(TAG, "contact name is " + contactName);
Log.d(TAG, "contact number is " + contactNumber);
holder.contact_name.setText(contactName);
holder.contact_number.setText(contactNumber);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
ViewHolder holder = new ViewHolder();
View view = LayoutInflater.from(myContext).inflate(R.layout.group_detail_item, parent,false);
holder.contact_name = (TextView)view.findViewById(R.id.group_item_id);
holder.contact_number = (TextView)view.findViewById(R.id.group_subitem_id);
view.setTag(holder);
return view;
}
}
static class ViewHolder {
TextView text;
TextView contact_name;
TextView contact_number;
CheckBox checkbox;
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle arg1) {
return new DueCustomCursorLoader(GroupDetails.this, dbadapter, (int)rowId);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
cursoradapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> arg0) {
cursoradapter.swapCursor(null);
}
}
Am not getting any issue from the database, so code not added here.
After saving contact to the database You need to restartLoader() to get yours database requery and let onLoadFinished to be called again to allow adapter work with new data.
I would try reversing these two lines (it looks to me like your telling the list to update itself before you update the cursor):
cursoradapter.notifyDataSetChanged();
getSupportLoaderManager().getLoader(0).onContentChanged();
To this:
getSupportLoaderManager().getLoader(0).onContentChanged();
cursoradapter.notifyDataSetChanged();