1

RecyclerView adapter doesn't load data on first launch after Permission check. I have to re-tap the tab to get the data.

I have already visited/tried these links -

-- RecyclerView doesn't load data in first launch using FirebaseRecyclerAdapter

-- RecyclerView doesn't load items on first start of activity

-- recyclerview not loading adapter values in a fragment

But nothing works yet. Tried to set global adapter, So I can call notifyDataSetChanged() from onResume(). Still It didn't worked.

Here's code -

onCreateView() -

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_third, container, false);

    recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);

    if (checkAndRequestPermissions()) {
        loadSongList();
    }

    return view;
}

onRequestPermissionResult -

loadSongList();  // method

loadSongList() -

private void loadSongList() {
    loadAudio();
    initRecyclerView();
}

loadAudio() -

loadAudio() // accessing data from content resolver

initRecyclerView()-

private void initRecyclerView() {
    if (mAudioList != null && mAudioList.size() > 0) {
        AudioAdapter adapter = new AudioAdapter(mAudioList, getActivity());
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
        recyclerView.setLayoutManager(linearLayoutManager);
        DIviderItemDecoration dividerItemDecoration = new DIviderItemDecoration(getContext(), linearLayoutManager.getOrientation());
        recyclerView.addItemDecoration(dividerItemDecoration);
        recyclerView.setAdapter(adapter);

        RecyclerViewItemClick.addTo(recyclerView).setOnItemClickListener(new RecyclerViewItemClick.OnItemClickListener() {
            @Override
            public void onItemClicked(RecyclerView recyclerView, int position, View v) {
                // life sucks
            }
        });
    }
}

EDIT :

loadAudio() -

private void loadAudio() {
    ContentResolver contentResolver = getActivity().getContentResolver();
    Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
    String selection = MediaStore.Audio.Media.IS_MUSIC + "!= 0";
    String sortOrder = MediaStore.Audio.Media.TITLE + " ASC";
    Cursor cursor = contentResolver.query(uri, null, selection, null, sortOrder);

    if (cursor != null && cursor.getCount() > 0) {
        mAudioList = new ArrayList<>();
        while (cursor.moveToNext()) {
            String data = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
            String title = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
            String album = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM));
            String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));

            Long albumId = cursor.getLong(cursor
                    .getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
            Long artWorkId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));

            int duration = cursor.getInt(cursor
                    .getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));

            Uri sArtworkUri = Uri
                    .parse("content://media/external/audio/albumart");
            Uri albumArtUri = ContentUris.withAppendedId(sArtworkUri, artWorkId);

            // Save to audioList
            mAudioList.add(new Audio(albumId, data, title, album, artist, albumArtUri, duration));
        }
    }
    if (cursor != null) {
        cursor.close();
    }

}

AudioAdapter -

public class AudioAdapter extends RecyclerView.Adapter<AudioAdapter.CustomViewHolder> {

List<Audio> mList = Collections.emptyList();
Context mContext;

public AudioAdapter(List<Audio> list, Context context) {
    mList = list;
    mContext = context;
}


@Override
public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.custom_row, parent, false);
    return new CustomViewHolder(v);
}

@Override
public void onBindViewHolder(CustomViewHolder holder, int position) {
    Audio audio = mList.get(position);

    holder.title.setText(audio.getTitle());
    holder.description.setText(audio.getArtist());

    Glide.with(mContext).load(audio.imageId).asBitmap()
            .centerCrop()
            .diskCacheStrategy(DiskCacheStrategy.RESULT)
            .skipMemoryCache(true)
            .placeholder(R.drawable.headset_2)
            .into(holder.imageView);

}

@Override
public int getItemCount() {
    return mList.size();
}

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
}

public void insert(int position, Audio list) {
    mList.add(position, list);
    notifyItemChanged(position);
}

public void remove(Audio list) {
    int position = mList.indexOf(list);
    mList.remove(position);
    notifyItemRemoved(position);
}


static class CustomViewHolder extends RecyclerView.ViewHolder {

    CardView cv;
    TextView title;
    TextView description;
    ImageView imageView;

    public CustomViewHolder(View itemView) {
        super(itemView);

        cv = (CardView) itemView.findViewById(R.id.cardView);
        title = (TextView) itemView.findViewById(R.id.playList_name);
        description = (TextView) itemView.findViewById(R.id.album_artist);
        imageView = (ImageView) itemView.findViewById(R.id.imageView1);
    }
}}

UDPATE : checkAndRequestPermission -

private boolean checkAndRequestPermissions() {
    if (SDK_INT >= Build.VERSION_CODES.M) {
        int permissionReadPhoneState = ContextCompat.checkSelfPermission(getContext(), (Manifest.permission.READ_PHONE_STATE));
        int permissionStorage = ContextCompat.checkSelfPermission(getContext(), Manifest.permission.READ_EXTERNAL_STORAGE);
        List<String> listPermissionsNeeded = new ArrayList<>();

        if (permissionReadPhoneState != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.READ_PHONE_STATE);
        }

        if (permissionStorage != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
        }

        if (!listPermissionsNeeded.isEmpty()) {
            requestPermissions(listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
            return false;
        } else {
            return true;
        }
    }
    return false;
}

After removing ActivityCompat and just calling requestPermission, the fragment is receiving callback, But now I'm getting error. logcat below -

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.util.ArrayList.get(int)' on a null object reference
                                                                                          at com.example.ansh.sharedpreferencessimple.service.MusicService.playSong(MusicService.java:167)
                                                                                          at com.example.ansh.sharedpreferencessimple.ThirdFragment$2.onItemClicked(ThirdFragment.java:196)
                                                                                          at com.example.ansh.sharedpreferencessimple.helper.RecyclerViewItemClick$1.onClick(RecyclerViewItemClick.java:21)
                                                                                          at android.view.View.performClick(View.java:6205)
                                                                                          at android.view.View$PerformClick.run(View.java:23653)
                                                                                          at android.os.Handler.handleCallback(Handler.java:751)
                                                                                          at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                                          at android.os.Looper.loop(Looper.java:154)
                                                                                          at android.app.ActivityThread.main(ActivityThread.java:6682)
                                                                                          at java.lang.reflect.Method.invoke(Native Method)
                                                                                          at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
                                                                                          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

Any help would be appreciated, Thanks.

Ansh
  • 365
  • 6
  • 19
  • I guess your loadAudio() method get the mAudioList right? – Andy Developer Jun 07 '17 at 11:47
  • Maybe mAudioList is null in initRecyclerView() ? Or incorrect view.xml? Show your adapter and loadAudio(). – Gogi Bobina Jun 07 '17 at 11:55
  • @AndyDeveloper Yeah! It's all working fine. But after accepting permission it doesn't load. To make it load one have to click on tab again or came back from another fragment. – Ansh Jun 07 '17 at 11:55
  • @OvechkinPavel Okay Sure! – Ansh Jun 07 '17 at 11:55
  • @Anshyadav see my answer this will resolve your problem – Andy Developer Jun 07 '17 at 11:57
  • See my answer as I said call your initRecyclerview after if (cursor != null) { cursor.close(); } – Andy Developer Jun 07 '17 at 11:59
  • @OvechkinPavel I am agree with you mAudioList is null inside initRecyclerView(). – Andy Developer Jun 07 '17 at 12:04
  • i can say only this: check mAudioList for null or empty in initRecyclerView. – Gogi Bobina Jun 07 '17 at 12:04
  • What I think is something wrong with my fragment lifecycle method! After permission check onResume will be called and I should notifySetDataChange(). But than I have to make 'Global Adapter' and then there's another problem as adapter will not be initialized at first. @OvechkinPavel Any help on this? – Ansh Jun 07 '17 at 12:04
  • @Anshyadav ok, show onActivityResult – Gogi Bobina Jun 07 '17 at 12:11
  • @OvechkinPavel I didn't implemented onActivityResult! – Ansh Jun 07 '17 at 12:14
  • @Anshyadav After recyclerView.setAdapter(adapter); ,, do a adapter.notifyDataSetChanged(); and see if it works on first launch after permission – Sreehari Jun 07 '17 at 12:23
  • @Stallion nothing works! With the help of Andy it seems mAudioList is not empty. The problem is that initRecyclerView is not getting called on first tab click. – Ansh Jun 07 '17 at 12:25
  • @Anshyadav that's the problem with your business logic. Its cracked somewhere. May be loadAudio(); is blocking or conditions in initRecyclerView(); is not satisfying – Sreehari Jun 08 '17 at 06:12
  • @Stallion code is up there. I guess the problem is that i'm not receiving callback from permission.! Can you check the permission code ( written inside fragment ). – Ansh Jun 08 '17 at 06:14
  • Your code says you just calls checkAndRequestPermissions() . Where is the functionality – Sreehari Jun 08 '17 at 07:15
  • @Stallion check the updated code. I added checkResultPermission(). Though I solved the, actually the problem is I'm not receiving callback from the permission. But after solving that now I'm getting null object error.. Posted logcat. – Ansh Jun 08 '17 at 07:25
  • @Anshyadav Pls go through this https://stackoverflow.com/questions/34342816/android-6-0-multiple-permissions. And i'm out of this league – Sreehari Jun 08 '17 at 07:38

1 Answers1

1

Here is the answer of your problem.

Your loadAudio() method fill up your mAudioList which is your arraylist or list whatever it was.

So, main problem is that when you call loadAudio() and then initRecyclerView() inside your initRecyclerView() the mAudioList is still null because at that time your mAudioList is not fill up inside your loadAudio().

So, the problem of your answer is to call initRecyclerView() at the end of loadAudio() function and this will resolve your issue.

For E.g.

private void loadAudio()
{
     // Get your arraylist of audio and all the stuff
     if (cursor != null)
     {
         cursor.close();
     }
    // Call init function here.
       initRecyclerView();
}
Andy Developer
  • 3,071
  • 1
  • 19
  • 39
  • It didn't worked! and btw I added adapter and loadAudio() code. – Ansh Jun 07 '17 at 12:01
  • @Anshyadav as I see in your code this is the problem.If you trace with log before if (mAudioList != null && mAudioList.size() > 0) {//} this you will found that your mAudioList is null. – Andy Developer Jun 07 '17 at 12:03
  • Any solution @Andy Developer? – Ansh Jun 07 '17 at 12:06
  • @Anshyadav try to log trace out you got your answer as I said on above comment. – Andy Developer Jun 07 '17 at 12:09
  • Well by log I can see that initRecyclerView() is not getting called! (first time) – Ansh Jun 07 '17 at 12:12
  • Okay So i can see that initRecyclerView not getting called during first click tab click. – Ansh Jun 07 '17 at 12:15
  • @Anshyadav I know it will not call first. I said when loadAudio function call so at that time your system trace the line by line all the code once your loadaudio code complete its tracing before that your initRecycler function call so inside initRecycler function you don't get the list of mAudio because your loadAudio function is still Processing that is the issue.My solution is perfect bro. – Andy Developer Jun 07 '17 at 12:16
  • Thanks! @Andy Developer. But actually I did what you said but still It's not getting called. – Ansh Jun 07 '17 at 12:18
  • System.out.println("==== mAudioList ==="+mAudioList+"::"); System.out.println("==== mAudioList Size ==="+mAudioList.size()+"::"); call this two line before if (mAudioList != null && mAudioList.size() > 0) { // } and see what is print in AndroidMonitor Log and you will get your answer – Andy Developer Jun 07 '17 at 12:20
  • Still It's getting called on Second tab click ( same as before ). Seems the mAudioList is not empty! – Ansh Jun 07 '17 at 12:22
  • Post your onResume() – Andy Developer Jun 07 '17 at 12:29
  • Are you calling initRecycler function inside loadAudio and outSide loadAudio() if yes then remove out side function. – Andy Developer Jun 07 '17 at 12:31
  • Yes I'm calling initRecyclerView inside loadAudio() function. And I added onResume code. Though I'm not doing anything there. – Ansh Jun 07 '17 at 12:34
  • Why are you calling the same stuff twice you are calling the checkpermission in onCreate and then you do the same thing try remove from the onCreate and use only onResume.You are calling loadAudio from resume so as I said put initRecycler function end of this function just do this.May be this help you. – Andy Developer Jun 07 '17 at 12:40
  • My bad.! I deleted it. Yes I'm calling initRecyclerView() function as you said. It's not working bro. – Ansh Jun 07 '17 at 12:43
  • As you suggested - This is loadAudio() { ... .... if (cursor != null) { cursor.close(); } initRecyclerView(); } – Ansh Jun 07 '17 at 12:45
  • Any Help @Andy? – Ansh Jun 07 '17 at 12:51
  • Try to debug line at onRequestPermissionResult and loadData is you getting arraylist null. – Vindhya Pratap Singh Jun 07 '17 at 17:02