Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why notifyItemRemoved(getAdapterPosition()); is not working

I'm using RecyclerView to show the list of mp3 songs. Now the problem is with when I try to delete the song. The song is deleted successfully but the item remains in RecyclerView and I think it recreate itself actually I don't understand what it is. Here is the screen shot what happens. enter image description here

As you can see in the above screen shot. I try to delete a song but the song remains in the list and another list is also creates behind it. I don't know what happens. here is my code SongFragment:-

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        activityView = inflater.inflate(R.layout.fragment_song, container, false);
//        SongsLibrary songsLibrary = new SongsLibrary();
//        songsLibrary.getSongThumnail(getActivity(), songArt);
        swipeRefreshLayout = activityView.findViewById(R.id.swiperefresh);
        if(arrayList == null){
            SongsLibrary songsLibrary = new SongsLibrary();
            songsLibrary.getSongs(getActivity());
        }
        mIntentFilter = new IntentFilter();
        mIntentFilter.addAction(deteleSong);
        setUpMusic();
        return activityView;
    }

    private void setUpMusic() {

//        todo when there is no activity and no song player than arraylist.size on null object
        RecyclerView songRecyclerView = activityView.findViewById(R.id.song_list);
        songRecyclerView.setNestedScrollingEnabled(false);
        songRecyclerView.setHasFixedSize(true);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
        songRecyclerView.setLayoutManager(linearLayoutManager);
        songRecyclerView.setHasFixedSize(true);
        SongAdapter mAdapter = new SongAdapter(getActivity(), getMusic());
        songRecyclerView.setAdapter(mAdapter);
    }

    public List<SongObject> getMusic() {
        List<SongObject> recentSongs = new ArrayList<>();
        names = new String[arrayList.size()];
        names = arrayList.toArray(names);

        singer = new String[artistName.size()];
        singer = artistName.toArray(singer);

        art = new String[songThumb.size()];
        art = songThumb.toArray(art);

        for(int i = 0; i < arrayList.size(); i++){
            recentSongs.add(new SongObject(names[i], singer[i], art[i]));
        }
        return recentSongs;
    }

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

    BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            switch (action)
            {
                case deteleSong:
                    int postion = intent.getIntExtra("position",0); //todo remove item by position
                    break;
            }
        }
    };

    @Override
    public void onDestroy() {
        super.onDestroy();

    }

    @Override
    public void onPause() {
        super.onPause();
       if(broadcastReceiver != null)
           getActivity().unregisterReceiver(broadcastReceiver);
    }

SongAdapter.java

public class SongAdapter extends RecyclerView.Adapter<SongViewHolder>{
    private Context context;
    private List<SongObject> allSongs;
    MyEditText options;
    SongViewHolder songViewHolder;
    public SongAdapter(Context context, List<SongObject> allSongs) {
        this.context = context;
        this.allSongs = allSongs;
    }
    @Override
    public SongViewHolder onCreateViewHolder(ViewGroup parent, final int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.song_list_layout, parent, false);
        options = view.findViewById(R.id.options);
        return new SongViewHolder(view);
    }
    @Override
    public void onBindViewHolder(SongViewHolder holder, final int position) {
        songViewHolder = holder;
        holder.setIsRecyclable(false);
        options.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                showOptions(view, position);
            }
        });
        SongObject songs = allSongs.get(position);
        holder.songTitle.setText(songs.getSongTitle());
        holder.songAuthor.setText(songs.getSongAuthor());
        Glide.with(context)
                .load(songs.getSongCover())
                .asBitmap()
                .placeholder(R.drawable.player)
                .error(R.drawable.player)
                .override(200,200)
                .fitCenter()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(holder.songImage);
    }
    private void showOptions(final View v, final int pos) {
        PopupMenu popup = new PopupMenu(context, v);
        MenuInflater inflater = popup.getMenuInflater();
        inflater.inflate(R.menu.song_options, popup.getMenu());
        popup.show();

        popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem menuItem) {
                int id = menuItem.getItemId();
                switch (id) {
                    case R.id.optionPlay:
                        play(context, pos);
//                        songFragment.play(context, pos);
                        break;
                    case R.id.optionDelete:
                        showAlert(context, pos);
                        break;
                    case R.id.optionDetails:
//                        getSongDetails(context, pos);
                        break;
                }
                return true;
            }
        });
    }

    public void play(Context context, int pos){
        //                Start Service when User Select a song :)
        Intent serviceIntent = new Intent(context, NotificationService.class);
        serviceIntent.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
        serviceIntent.putExtra("pos", pos);
        serviceIntent.putExtra("search","");
//        Log.d("SendingData","Sended :"+ songIndex);
        context.startService(serviceIntent);
        //send broadcast for showing slideup panel
        //send Broadcast
        Intent broadcastIntent = new Intent();
        broadcastIntent.setAction(MusicActivity.mMediaStart);
        broadcastIntent.putExtra("isStart", 1);
        context.sendBroadcast(broadcastIntent);
    }
    private void showAlert(final Context context, final int position){
        AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.Theme_AppCompat_Light_Dialog_Alert);
        builder.setMessage("Do you want to delete this song?")
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                    deleteSong(context, position);
                    }
                })
                .setNegativeButton("No", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {

                    }
                });
        // Create the AlertDialog object and return it
        builder.show();
    }
    public void deleteSong(Context ctx, int pos){
        ArrayList<String> songList = songPath;
        final String songName = songList.get(pos);
        final int songPos = pos;
        new android.os.Handler().postDelayed(new Runnable(){
            @Override
            public void run() {
                // Set up the projection (we only need the ID)
                String[] projection = { MediaStore.Audio.Media._ID };

                // Match on the file path
                String selection = MediaStore.Audio.Media.DATA + " = ?";
                String[] selectionArgs = new String[] { songName };

                // Query for the ID of the media matching the file path
                Uri queryUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                ContentResolver contentResolver = context.getContentResolver();
                Cursor c = contentResolver.query(queryUri, projection, selection, selectionArgs, null);
                if (c.moveToFirst()) {
                    // We found the ID. Deleting the item via the content provider will also remove the file
                    long id = c.getLong(c.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
                    Uri deleteUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);
                    contentResolver.delete(deleteUri, null, null);
                } else {
                    // File not found in media store DB
                    Toast.makeText(context, "No Song Found", Toast.LENGTH_SHORT).show();
                }
                c.close();
            }
        }, 0);

        File delete = new File(songName);
        if(delete.exists()){
            if(delete.delete()) {
                //send broadcast to SongFragment to remove item from reycler View
                arrayList.remove(pos);
                songPath.remove(pos);
                songThumb.remove(pos);
                artistName.remove(pos);
                songArt.remove(pos);
                notifyItemRemoved(pos);  //Remove item from the list
                notifyItemRangeChanged(pos, arrayList.size());
//                songViewHolder.itemView.setVisibility(View.GONE);  //tried it but not working
                //Optional
                Intent intent = new Intent();
                intent.setAction(SongFragment.deteleSong);
                intent.putExtra("position",pos);
                context.sendBroadcast(intent);
            }
            else
                Toast.makeText(context, "Error while deleting File.", Toast.LENGTH_SHORT).show();
        }

    }
    @Override
    public int getItemCount() {
        return allSongs.size();
    }
}
like image 417
Sunny Bhadana Avatar asked Nov 21 '17 14:11

Sunny Bhadana


Video Answer


1 Answers

This is is really confusing code. Why do you have all these lists of simple objects (arrayList, songPath, songThumb, artistName, songArt) and where are they defined and why are some of these lists copied to arrays, while you also have a list with complex SongObject objects with title, author, cover members?

I believe that the confusing handling of data is at the core of your problem.

What is the list or array your adapter is serving? From the way the constructor of the adapter is designed and definitely from the getItemCount(), it is clear that you want allSongs to play the central role in your adapter. However, in the constructor you make a shallow copy of allSongs. And what is worse and immediately causes the symptoms you are describing is the fact that in your deleteSong method you do not remove items from allSongs, but from all other lists. However, your ViewHolders hold members of the SongObject objects in allSongs ...

What is to be done?

  1. Clean up your data. Make an even more complex SongObject class (with all members necessary) and put your data into a single List of SongObjects.

  2. Pass this list to the constructor of the adapter (as you do now) and make a deep copy of the list (as you don't do now).

  3. In your deleteSong method, delete the selected SongObject by removing it from the list, like so:

    allSongs.remove(pos);
    

    Then call:

    notifyDataSetChanged();
    
like image 133
kalabalik Avatar answered Oct 11 '22 10:10

kalabalik