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

时间:2017-11-21 14:12:49

标签: android android-recyclerview

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

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

1 个答案:

答案 0 :(得分:4)

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

我认为数据的混乱处理是您问题的核心。

适配器所使用的列表或阵列是什么?从设计适配器的构造函数的方式来看,肯定来自getItemCount(),显然您希望allSongs在适配器中扮演核心角色。但是,在构造函数中,您创建了allSongs的浅表副本。更糟糕的是,并且会立即导致您所描述的症状是,在deleteSong方法中,您不会从allSongs中删除项目,而是从所有其他列表中删除项目。但是,您的ViewHolder成为SongObjectallSongs个对象的成员......

该怎么办?

  1. 清理您的数据。制作一个更复杂的SongObject课程(必要时包含所有成员),并将您的数据放入List SongObjectdeleteSong

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

  3. 在您的SongObject方法中,通过从列表中删除选定的allSongs.remove(pos); 来删除它,如下所示:

    notifyDataSetChanged();
    

    然后致电:

    int i = (int)(Math.random() * greetings.length);
    System.out.println(greetings[i]);