Можно ли получить образ песни быстрее? - PullRequest
1 голос
/ 25 октября 2019

Я работаю над музыкальным проигрывателем, который отображает все песни и изображения соответствующих песен с локального устройства на фрагменте.

Когда я запускаю приложение, его загрузка занимает много времени, я заметил, что это было getImagesForSongs () , который медленно обрабатывался

почему он медленный? и есть ли лучший способ и как я могу это сделать?

My All Song фрагмент класса



import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.mikeinvents.musicbaze.R;
import com.mikeinvents.musicbaze.adapters.SongAdapter;
import com.mikeinvents.musicbaze.data_model.SongModel;
import com.mikeinvents.musicbaze.ui.MainActivity;

import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.TimeUnit;


/**
 * A simple {@link Fragment} subclass.
 */
public class AllSongsFragment extends Fragment {
    RecyclerView recyclerView;
    ArrayList<SongModel> song;
    ArrayList<Bitmap> bitmaps;
    MediaMetadataRetriever mediaMetadataRetriever;
    static byte[] rawArt;
   static Bitmap art;
   static BitmapFactory.Options bfo;

    public AllSongsFragment() {
        // Required empty public constructor
    }

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

    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View rootView =  inflater.inflate(R.layout.fragment_all_songs, container, false);
       // setRetainInstance(true);
        recyclerView = rootView.findViewById(R.id.song_recycler_view);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        new MyAsyncTask().execute();

        return rootView;
    }

    private void loadSongList() {
        ContentResolver contentResolver = Objects.requireNonNull(getActivity()).getContentResolver();


        Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        String selection = MediaStore.Audio.Media.IS_MUSIC;
        String sortOrder = MediaStore.Audio.Media.TITLE + " ASC";

        Cursor cursor = contentResolver.query(uri,null,selection,null,sortOrder);

        if(cursor != null && cursor.moveToFirst()){
            song = new ArrayList<>();

            //get columns
            do {
                String data = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
                String title = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
                String album = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM));
                String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
                String timeDuration = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION));

                //convert time
                int duration = Integer.parseInt(timeDuration);
                @SuppressLint("DefaultLocale") String time = String.format("%02d:%02d",
                        TimeUnit.MILLISECONDS.toMinutes(duration),
                                TimeUnit.MILLISECONDS.toSeconds(duration) -
                                        TimeUnit.MILLISECONDS
                                                .toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)));
                //save to list
                song.add(new SongModel(data, title, artist, album, time));

                Log.i(MainActivity.TAG, " Added: "+"data = "+data+" title = "+title+
                        " album = "+album+" artist: "+artist+" duration = "+time);

            }while (cursor.moveToNext());

        }

        if(cursor !=null){
            cursor.close();
        }

    }

    private void getImagesForSongs(){
        ContentResolver contentResolver = Objects.requireNonNull(getActivity()).getContentResolver();


        Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        String selection = MediaStore.Audio.Media.IS_MUSIC;
        String sortOrder = MediaStore.Audio.Media.TITLE + " ASC";

        Cursor cursor = contentResolver.query(uri,null,selection,null,sortOrder);

        if(cursor != null && cursor.moveToFirst()){
            bitmaps = new ArrayList<>();
            do{
                String data = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));


                //get song image
                mediaMetadataRetriever = new MediaMetadataRetriever();

                mediaMetadataRetriever.setDataSource(data);
                Log.i(MainActivity.TAG, "Data source has been set");

                rawArt = mediaMetadataRetriever.getEmbeddedPicture();
                Log.i(MainActivity.TAG, "Raw art has been gotten");

                bfo = new BitmapFactory.Options();
                art = decodeSampledBitmapFromResource(100,100);


                //save to list
                bitmaps.add(art);

            }while (cursor.moveToNext());
        }

        if (cursor != null) {
            cursor.close();
        }

    }

    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 4;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.

            while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }
        Log.i(MainActivity.TAG,"Calculated in sample size");

        return inSampleSize;
    }


    public static Bitmap decodeSampledBitmapFromResource(int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        bfo.inJustDecodeBounds = true;

        if(rawArt != null){
            BitmapFactory.decodeByteArray(rawArt,0,rawArt.length,bfo);
            Log.i(MainActivity.TAG, "Gotten embedded picture");
            // Calculate inSampleSize
            calculateInSampleSize(bfo,reqWidth,reqHeight);

            // Decode bitmap with inSampleSize set
            bfo.inJustDecodeBounds = false;


            return BitmapFactory.decodeByteArray(rawArt,0,rawArt.length,bfo);
        }

        Log.i(MainActivity.TAG, "Gotten null embedded picture");

        return null;

    }

    private class MyAsyncTask extends AsyncTask<Void, Void, Void>{
        ProgressDialog pd;
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            pd = new ProgressDialog(getContext());
            pd.setTitle("Please wait...");
            pd.setMessage("Fetching songs");
            pd.setCancelable(false);
            pd.show();
        }

        @Override
        protected Void doInBackground(Void... voids) {
            getImagesForSongs();
            loadSongList();
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            pd.dismiss();
            SongAdapter songAdapter = new SongAdapter(getContext(), song, bitmaps);
            Log.i(MainActivity.TAG,"Initialized adapter");
            recyclerView.setAdapter(songAdapter);
            Log.i(MainActivity.TAG,"Adapter has been set");

        }
    }

}

My SongAdapter class


import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.mikeinvents.musicbaze.R;
import com.mikeinvents.musicbaze.data_model.SongModel;
import com.mikeinvents.musicbaze.ui.MainActivity;

import java.util.ArrayList;

public class SongAdapter extends RecyclerView.Adapter<SongAdapter.ViewHolder> {
    private Context ctx;
    private ArrayList<SongModel> mSong;
    private ArrayList<Bitmap> mBitmap;

    public SongAdapter(Context ct, ArrayList<SongModel> song, ArrayList<Bitmap> bitmap){
        ctx = ct;
        mSong = song;
        mBitmap = bitmap;
    }

    @NonNull
    @Override
    public SongAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        LayoutInflater inflater = LayoutInflater.from(ctx);
        View view = inflater.inflate(R.layout.song_row,viewGroup,false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull SongAdapter.ViewHolder viewHolder, int i) {
        SongModel song = mSong.get(i);
        viewHolder.songTitle.setText(song.getTitle());
        viewHolder.songArtist.setText(song.getArtist());
        viewHolder.songAlbum.setText(song.getAlbum());
        viewHolder.songTime.setText(song.getSongTime());
       // Glide.with(ctx).load(mBitmap.get(i)).fallback(R.drawable.mojo_logo).into(viewHolder.songImage);

        if(mBitmap.get(i) == null){
            viewHolder.songImage.setImageResource(R.drawable.mojo_logo);
        }else if(mBitmap.get(i) !=null){
            viewHolder.songImage.setImageBitmap(mBitmap.get(i));
        }




        viewHolder.moreOptions.setOnClickListener(v -> {
            PopupMenu popupMenu = new PopupMenu(ctx,v);
            popupMenu.setOnMenuItemClickListener(item -> {
                switch (item.getItemId()){
                    case R.id.more_options_action_share:
                        Toast.makeText(ctx,"Implement Share Option", Toast.LENGTH_SHORT).show();
                        return true;
                    case R.id.more_options_action_add_fav:
                        Toast.makeText(ctx,"Implement Favorite Option", Toast.LENGTH_SHORT).show();
                        return true;
                    case R.id.more_options_action_delete:
                        Toast.makeText(ctx,"Implement Delete Option", Toast.LENGTH_SHORT).show();
                        return true;
                    default:
                        return false;
                }

            });

            popupMenu.inflate(R.menu.more_options_popup);
            popupMenu.show();
        });
    }

    @Override
    public int getItemCount() {
        return mSong.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        ImageView songImage, moreOptions;
        TextView songTitle, songArtist, songAlbum, songTime;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            songImage = itemView.findViewById(R.id.song_row_song_image);
            moreOptions = itemView.findViewById(R.id.song_row_more_options);
            songTitle = itemView.findViewById(R.id.song_row_name_of_song);
            songArtist = itemView.findViewById(R.id.song_row_artist_name);
            songAlbum = itemView.findViewById(R.id.song_row_album_name);
            songTime = itemView.findViewById(R.id.song_row_song_time);

            Log.i(MainActivity.TAG,"Views in song_row layout initialized");
        }

    }


}

Спасибо.

1 Ответ

0 голосов
/ 25 октября 2019

Не уверен, что есть конкретное исправление, но есть некоторые вещи, которые можно сделать, чтобы ускорить загрузку.

Растровое изображение может быть медленным, поэтому, если вместо этого можно получить изображения PNG, этоускорить процесс. в методе decodeSampledBitmapFromResource вы дважды запускаете

BitmapFactory.decodeByteArray(rawArt,0,rawArt.length,bfo);

, что кажется ненужным, но, возможно, я что-то упускаю.

Кроме того, вы можете лениво загружать изображения вместо загрузки всех изображений для каждой песни сразу,Вы можете получить изображение в onBindViewHolder. таким образом, каждое изображение также будет асинхронно получаться в параллельном режиме.

...