我正在开发一个应用程序,该应用程序扫描您的手机中的MP3,然后将它们全部放入列表中,并由recyclerview
处理,以便您滚动浏览并播放它们。
在设法获得recyclerview
之前,我设法使所有这些功能都起作用,但是每次打开该应用程序时,加载许多歌曲(在我的手机700+上)花费了大约30秒。当然这是不能接受的。因此,现在所有内容都由recyclerview
控制,但我只是不知道如何填充重载适配器,因此它不会一次重载,而是一步一步地重载。这就是ATM的外观:
重新加载适配器:
public class MySimpleItemLoader
{
public List<MP3object> mP3Objects { get; private set; }
public bool IsBusy { get; set; }
public int CurrentPageValue { get; set; }
public bool CanLoadMoreItems { get; private set; }
public MySimpleItemLoader(List<MP3object> mp3)
{
this.mP3Objects = mp3;
}
public void LoadMoreItems(int itemsPerPage)
{
IsBusy = true;
for (int i = CurrentPageValue; i < CurrentPageValue + itemsPerPage; i++)
{
mP3Objects.Add(new MP3object() { AlbumName = string.Format("This is item {0:0000}", i) });
}
CanLoadMoreItems = true;
CurrentPageValue = mP3Objects.Count;
IsBusy = false;
}
}
我的主要活动,我在其中加载了所有mp3的列表(需要很长的时间):
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;
}
我将如何转换它,以便加载不会发生在主要活动中,而是需要在回收视图重新加载适配器中的何处进行?
我真的需要你的帮助。
非常感谢:)
答案 0 :(得分:2)
我认为您没有正确理解RecyclerView
的用法。 RecyclerView
的职责是在屏幕上显示您的项目,仅此而已。
RecyclerView
内部加载的任何数据大多会导致UI延迟和滚动。
要正确处理,您需要在RecyclerView
的适配器之外加载数据,然后通知它来投影更改。而且,如果您有很多数据需要花费很多时间来加载,则可以以较小的步骤进行操作,并在每个步骤之后更新RecyclerView
。假设您以每步100首的速度加载700首歌曲。
这是一些示例伪代码,可为您提供一些思路。因此,不要指望它真正起作用。
val audioFiles = mutableListOf<String>()
Observable.create{ e ->
for{
val offset = audioFiles.size
// load your files here
if(audioFiles.size % 100){
e.onNext(offset)
}
}
e.onComplete()
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe{ offset ->
mAdapter.notifyItemRangeInserted(offset, offset+100)
}