获取RecyclerView重新加载项目

时间:2018-10-05 09:13:35

标签: android android-recyclerview xamarin.android

我目前正在开发一个应用,该应用可以在用户手机上找到所有MP3,然后将其放入列表中。即使有很多歌曲,它也可以很好地运行并且非常快。现在,我为列表的每个项目填充了一个带有对象的新列表,然后将其显示在我的recyclerview中。问题是,我的手机上有700多首歌曲,这在相当长的一段时间内阻塞了UI线程。

现在,我想使用recyclerview而不是一次将列表中的所有项目全部加载到对象中,而是仅在它们将要显示时才加载-但我不知道如何执行此操作。现在,所有对象都已构建,然后在UI线程被阻塞30秒钟之后,从recyclerview中以非常长的滚动视图显示。可以请任何人帮我吗?这是我的代码:

namespace Media_Player
{
    [Activity(Label = "Media_Player", MainLauncher = true)]
    public class MainActivity : Activity
    {
        static public MediaPlayer mediaPlayer;
        List<MP3object> mp3;
        MediaMetadataRetriever reader;
        public static Button btn_StartOrPause, btn_Stop;
        public static TextView txt_CurrentSong;
        public static bool stopIsActive = false, firstStart = true;
        public static Android.Net.Uri CurrentActiveSongUri;

        RecyclerView mRecyclerView;
        RecyclerView.LayoutManager mLayoutManager;
        PhotoAlbumAdapter mAdapter;


        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            SetContentView(Resource.Layout.test);

            reader = new MediaMetadataRetriever();
            PopulateMP3List(ReturnPlayableMp3(true));
            mediaPlayer = new MediaPlayer();

            InitRecView();
        }

        private void InitRecView()
        {

            // Instantiate the adapter and pass in its data source:
            mAdapter = new PhotoAlbumAdapter(mp3);

            // Get our RecyclerView layout:
            mRecyclerView = FindViewById<RecyclerView>(Resource.Id.recyclerView);

            // Plug the adapter into the RecyclerView:
            mRecyclerView.SetAdapter(mAdapter);

            mLayoutManager = new LinearLayoutManager(this);
            mRecyclerView.SetLayoutManager(mLayoutManager);
        }


        private void PopulateMP3List(List<string> content)
        {
           mp3 = new List<MP3object>();        
           foreach (string obj in content)
           {
               WriteMetaDataToFileList(obj);        
           }
        }

        void WriteMetaDataToFileList(string obj)
        {
            reader.SetDataSource(obj);

            //Write Mp3 as object to global list
            MP3object ob = new MP3object();
            {
                if(reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyTitle) != "" && reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyTitle) != null)
                {
                    ob.SongName = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyTitle);
                }
                else
                {
                    ob.SongName = Resources.GetString(Resource.String.Unknown);
                }

                if (reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyArtist) != "" && reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyArtist) != null)
                {
                    ob.ArtistName = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyArtist);
                }
                else
                {
                    ob.ArtistName = Resources.GetString(Resource.String.Unknown);
                }

                if (reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyAlbum) != "" && reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyAlbum) != null)
                {
                    ob.AlbumName = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyAlbum);
                }
                else
                {
                    ob.AlbumName = Resources.GetString(Resource.String.Unknown);
                }

                if (reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyYear) != "" && reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyYear) != null)
                {
                    ob.Year = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyYear);
                }
                else
                {
                    ob.Year = Resources.GetString(Resource.String.Unknown);
                }

                if (reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyYear) != "" && reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyYear) != null)
                {
                    ob.Year = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyYear);
                }
                else
                {
                    ob.Year = Resources.GetString(Resource.String.Unknown);
                }

                ob.Mp3Uri = obj; // can never be unknown!

                ob.DurationInSec = int.Parse(reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyDuration)) / 1000; // can never be unknown, div by 1000 to get sec not millis
            }
            mp3.Add(ob);

        }

        public List<string> ReturnPlayableMp3(bool sdCard)
        {
            List<string> res = new List<string>();
            string phyle;
            string path1 = null;

            if(sdCard) // get mp3 from SD card
            {
                string baseFolderPath = "";

                try
                {
                    bool getSDPath = true;

                    Context context = Application.Context;
                    Java.IO.File[] dirs = context.GetExternalFilesDirs(null);

                    foreach (Java.IO.File folder in dirs)
                    {
                        bool IsRemovable = Android.OS.Environment.InvokeIsExternalStorageRemovable(folder);
                        bool IsEmulated = Android.OS.Environment.InvokeIsExternalStorageEmulated(folder);

                        if (getSDPath ? IsRemovable && !IsEmulated : !IsRemovable && IsEmulated)
                            baseFolderPath = folder.Path;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("GetBaseFolderPath caused the following exception: {0}", ex);
                }

                string xy = baseFolderPath.Remove(18); // This is result after this, but this hard coded solution could be a problem on different phones.: "/storage/05B6-2226/Android/data/Media_Player.Media_Player/files"

                path1 = xy;
                // path to SD card and MUSIC "/storage/05B6-2226/"
            }
            else // get Mp3 from internal storage
            {
                    path1 = Android.OS.Environment.ExternalStorageDirectory.ToString();
            }

            var mp3Files = Directory.EnumerateFiles(path1, "*.mp3", SearchOption.AllDirectories);

            foreach (string currentFile in mp3Files)
            {
                phyle = currentFile;
                res.Add(phyle);
            }

            return res;
        }


    }

    public class PhotoViewHolder : RecyclerView.ViewHolder
    {
        public ImageView Image { get; private set; }
        public TextView Caption { get; private set; }

        public PhotoViewHolder(View itemView) : base(itemView)
        {
            // Locate and cache view references:
            Image = itemView.FindViewById<ImageView>(Resource.Id.imageView);
            Caption = itemView.FindViewById<TextView>(Resource.Id.textView);
        }
    }

    public class PhotoAlbumAdapter : RecyclerView.Adapter
    {
        public List<MP3object> mp3;
        public PhotoAlbumAdapter(List<MP3object> mp3)
        {
            this.mp3 = mp3;
        }

        public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
        {
            View itemView = LayoutInflater.From(parent.Context).
                        Inflate(Resource.Layout.lay, parent, false);
            PhotoViewHolder vh = new PhotoViewHolder(itemView);
            return vh;
        }

        public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
        {
            PhotoViewHolder vh = holder as PhotoViewHolder;
            vh.Caption.Text = mp3[position].SongName;
        }

        public override int ItemCount
        {
            get { return mp3.Count(); }
        }
    }



}

因此,获取带有Mp3位置的字符串列表的工作非常迅速,但是随后出现了“ WriteMetaDataToFileList(obj)”(来自“ PopulateMP3List(列表内容)”),这花费了很长时间。我认为我需要的是recyclerview只构建前20个对象,并且当用户开始滚动时,构建下20个对象并将它们附加到列表中,以便它们也可以滚动。请在这里帮助我:)

1 个答案:

答案 0 :(得分:1)

这是一个抽象类:

public abstract class PaginationScrollListener extends RecyclerView.OnScrollListener {
private LinearLayoutManager linearLayoutManager;

protected PaginationScrollListener(LinearLayoutManager linearLayoutManager) {
    this.linearLayoutManager = linearLayoutManager;
}

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);
    int visibleItemCount = linearLayoutManager.getChildCount();
    int totalItemCount = linearLayoutManager.getItemCount();
    int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
    if (!isLoading() && !isLastPage()) {
        if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount && firstVisibleItemPosition >= 0) {
            loadMoreItems();
        }
    }
}

protected abstract void loadMoreItems();

public abstract boolean isLastPage();

public abstract boolean isLoading();
}

并且在适配器中,您必须遵循以下模式:

public class ConsultancyAdapter extends      RecyclerView.Adapter<ConsultancyAdapter.ConsultancyVH> {
private static final int ITEM = 0;
private static final int LOADING = 1;
private boolean isLoadingAdded = false;

public ConsultancyAdapter(List<Consultancy> consultancies, ConsultancyAdapterListener listener) {
}

@NonNull
@Override
public ConsultancyVH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    RecyclerView.ViewHolder viewHolder = null;
    LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
    switch (viewType) {
        case ITEM:
            viewHolder = getViewHolder(parent, layoutInflater);
            break;
        case LOADING:
            View v2 = layoutInflater.inflate(R.layout.item_progress, parent, false);
            viewHolder = new ConsultancyVH(v2);
            break;
    }
    return (ConsultancyVH) viewHolder;
}
@NonNull
private RecyclerView.ViewHolder getViewHolder(ViewGroup parent, LayoutInflater inflater) {
    RecyclerView.ViewHolder viewHolder;
    View v1 = inflater.inflate(R.layout.item_consultancy, parent, false);
    viewHolder = new ConsultancyVH(v1);
    return viewHolder;
}

@Override

public void onBindViewHolder(@NonNull ConsultancyVH holder, int position) {
    Consultancy consultancy = consultancies.get(position);
    switch (getItemViewType(position)) {
        case ITEM:
            ConsultancyVH mySingeCounseller = holder;
            holder.title.setText(consultancy.getTitle());  // set cardTitle
            holder.fieldArea.setText(consultancy.getField_filedoctorskills());               

            break;
        case LOADING:
            break;
    }
}    


@Override
public int getItemCount() {
    return consultancies.size();
}
@Override
public int getItemViewType(int position) {
    return (position == consultancies.size() - 1 && isLoadingAdded) ? LOADING : ITEM;
}

public void add(Consultancy mc) {
    consultancies.add(mc);
    notifyItemInserted(consultancies.size() - 1);
}

public void addAll(List<Consultancy> mcList) {
    for (Consultancy mc : mcList) {
        add(mc);
    }
}

public void remove(Consultancy city) {
    int position = consultancies.indexOf(city);
    if (position > -1) {
        consultancies.remove(position);
        notifyItemRemoved(position);
    }
}

public Consultancy getItem(int position) {
    return consultancies.get(position);
}

public void clear() {
    isLoadingAdded = false;
    while (getItemCount() > 0) {
        remove(getItem(0));
    }
}

public boolean isEmpty() {
    return getItemCount() == 0;
}

public void addLoadingFooter() {
    isLoadingAdded = true;
    add(new Consultancy());
}

public void removeLoadingFooter() {
    isLoadingAdded = false;

    int position = consultancies.size() - 1;
    Consultancy item = getItem(position);


    if (item != null) {
        consultancies.remove(position);
        notifyItemRemoved(position);
    }
}

public interface ConsultancyAdapterListener {
    void onCaseClicked(int position, String nid, String fieldArea, String title);
}

protected class ConsultancyVH extends RecyclerView.ViewHolder {
    private TextView title, fieldArea;
    private CircleImageView iconProfile;
    private MaterialRippleLayout caseButtonRipple;

    public ConsultancyVH(View itemView) {
        super(itemView);
        caseButtonRipple = itemView.findViewById(R.id.case_button_ripple);
        this.title = itemView.findViewById(R.id.docName);
        this.fieldArea = itemView.findViewById(R.id.fieldArea);
        this.iconProfile = itemView.findViewById(R.id.icon_profile);
    }

}
}

以及您的活动:

    private void setScrollListener() {
    recyclerView.addOnScrollListener(new PaginationScrollListener(linearLayoutManager) {
        @Override
        protected void loadMoreItems() {
            isLoading = true;
            currentPage += 1;
                    loadNextPage();
        }

        @Override
        public boolean isLastPage() {
            return isLastPage;
        }

        @Override
        public boolean isLoading() {
            return isLoading;
        }
    });
                    loadFirstPage();

}

在我的loadFirstPage中,我与一个API对话,您需要一些代码:

private void loadFirstPage() {
    CallData().enqueue(new DefaultRetrofitCallback<List<Consultancy>>() {
        @Override
        protected void onFailure(Throwable t) {
            super.onFailure(t);
        }

        @Override
        protected void onSuccess(List<Consultancy> response) {
            swipeRefreshLayout.setRefreshing(false);
            dataList = response;
            adapter.addAll(dataList);
            recyclerView.setAdapter(adapter);
            if (!checkLast(response)) adapter.addLoadingFooter();
            else isLastPage = true;
        }

        @Override
        protected void onOtherStatus(Response<List<Consultancy>> response) {
            super.onOtherStatus(response);
        }

        @Override
        protected void always() {
            super.always();
        }
    });
}

和loadNextPage:

private void loadNextPage() {
    CallData().enqueue(new DefaultRetrofitCallback<List<Consultancy>>() {
        @Override
        protected void onFailure(Throwable t) {
            super.onFailure(t);
        }

        @Override
        protected void onSuccess(List<Consultancy> response) {
            swipeRefreshLayout.setRefreshing(false);
            adapter.removeLoadingFooter();
            isLoading = false;
            swipeRefreshLayout.setRefreshing(false);
            adapter.addAll(response);
            if (!checkLast(response)) adapter.addLoadingFooter();
            else isLastPage = true;
        }

        @Override
        protected void onOtherStatus(Response<List<Consultancy>> response) {
            super.onOtherStatus(response);
        }

        @Override
        protected void always() {
            super.always();
        }
    });
}