为什么notifyItemRemoved(getAdapterPosition()); 不管用

Sun*_*ana 5 android android-recyclerview

我正在使用 RecyclerView 来显示 mp3 歌曲列表。现在的问题是当我尝试删除这首歌时。这首歌已成功删除,但该项目仍保留在 RecyclerView 中,我认为它实际上重新创建了自己,我不明白它是什么。这是发生了什么的屏幕截图。 在此处输入图片说明

正如您在上面的屏幕截图中看到的那样。我尝试删除一首歌曲,但该歌曲仍保留在列表中,并且在其后面还创建了另一个列表。我不知道会发生什么。这是我的代码 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);
    }
Run Code Online (Sandbox Code Playgroud)

歌曲适配器.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();
    }
}
Run Code Online (Sandbox Code Playgroud)

kal*_*lik 5

这真是令人困惑的代码。为什么你有所有这些简单对象的列表(arrayList、songPath、songThumb、artistName、songArt)以及它们在哪里定义以及为什么这些列表中的一些被复制到数组,同时你还有一个SongObject包含标题、作者的复杂对象的列表,盖成员?

我相信数据的混乱处理是您问题的核心。

您的适配器服务的列表或阵列是什么?从适配器的构造函数的设计方式来看getItemCount(),显然您想allSongs在适配器中扮演核心角色。但是,在构造函数中,您对allSongs. 更糟糕的是并立即导致您所描述的症状的事实是,在您的deleteSong方法中,您不会从 中删除项目allSongs,而是从所有其他列表中删除项目。但是,您的ViewHolders 持有SongObject对象的成员allSongs...

什么是要做?

  1. 清理你的数据。做一个更复杂的SongObject类(提供必要的所有成员),并把你的数据到一个单一ListSongObject秒。

  2. 将此列表传递给适配器的构造函数(就像您现在所做的那样)并制作该列表的深层副本(因为您现在不这样做)。

  3. 在您的deleteSong方法中,SongObject通过从列表中删除所选内容来删除它,如下所示:

    allSongs.remove(pos);
    
    Run Code Online (Sandbox Code Playgroud)

    然后调用:

    notifyDataSetChanged();
    
    Run Code Online (Sandbox Code Playgroud)