2

Я работаю над музыкальным приложением и новичком в приложениях для Android. Я использую ListView, чтобы показать контент, который является музыкальным файлом на устройстве. Вот то, что я делаю в ListView:Оптимизация ListView с помощью Asynctask для Smoother Scroll

  1. Отображение заголовка музыкального файла, исполнителя и длительность
  2. обложки альбома музыкального файла, если таковая имеется

Так

Первая точка из того, что я делаю, легко сделать и достаточно эффективно при действительно гладком прокрутке, проблема начинается со второй точки, т.е. загрузка обложки альбома музыкального файла, которую я делаю с AsyncTask , Я получаю AsyncTask, но это не самый умный AsyncTask. Например, я хочу, чтобы эти два поведения от моего ListView и AsyncTask:

  1. начать делать AsyncTask только тогда, когда пользователь прекращает прокрутку - Я хочу, чтобы сохранить важные циклы процессора, когда пользователь пытается броситься через представление (прокручивается быстрее всего в поперечнике). Прямо сейчас с моим подходом, когда происходит всплытие, все AsyncTask начинает загрузку сразу. Я внедрил функцию cancelPotentialTask(), и она отменяет задачу сразу, если мне это не нужно, но что, если я могу контролировать запуск задачи, тогда это было бы более эффективно, чем отменить ее. Например, когда пользователь останавливает прокрутку ListView Я получаю триггер, чтобы начать AsyncTask.
  2. Если AsyncTask один раз вернет результат, если нет обложки альбомов, тогда вам не нужно снова входить в задание, если я его снова назову - это легко понять на картинке ниже (извините за плохое редактирование). enter image description here

В первой части я позволяю представлениям загружаться вместе с AsyncTask. В следующем, я прокручиваю вверх и получаю другое представление и позволяю одному ряду идти к recycler. В третий раз я прокручиваю вниз, я получаю обратный просмотр назад, но Asynctask загружается, но мне не нужен AsyncTask, так как это действительно очевидный результат будет нулевым, как это было в первый раз. Я знаю, что код не знает этого, пока мы этого не скажем. Но как я могу сказать. У меня есть ключ в getView(), где я вижу, convertView == null.

Спасибо за чтение до сих пор, я ценю ваше терпение. Вот сыр для вас -

public Bitmap getAlbumart(Long album_id) { 
     Bitmap bm = null; 
     try { 
      final Uri sArtworkUri = Uri 
        .parse("content://media/external/audio/albumart"); 

      Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id); 

      ParcelFileDescriptor pfd = activity.getContentResolver() 
        .openFileDescriptor(uri, "r"); 

      if (pfd != null) { 
       FileDescriptor fd = pfd.getFileDescriptor(); 
       bm = BitmapFactory.decodeFileDescriptor(fd); 
      } 
     } catch (Exception ignored) { 
     } 
     return bm; 
    } 

    // This is what I call to get image in getView() 
    public void loadBitmap(String resId, ImageView imageView) { 
     if (cancelPotentialWork(resId, imageView)) { 
      String imageKey = String.valueOf(resId); 
      LoadRows task = new LoadRows(imageView); 
      SoftReference<Bitmap> bitmap1; 
      try { 
       bitmap1 = new SoftReference<>(Bitmap.createScaledBitmap(getBitmapFromMemCache(imageKey), 80, 80, true)); 
       imageView.setImageBitmap(bitmap1.get()); 
      } catch (Exception e) { 
       SoftReference<AsyncDrawable> asyncDrawable = new SoftReference<>(new AsyncDrawable(resId, null, 
         task)); 
       imageView.setImageDrawable(asyncDrawable.get()); 
       task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, resId); 
      } 
     } 
    } 

    public class LoadRows extends AsyncTask<String, Void, Bitmap> { 

     String data = null; 
     private final WeakReference<ImageView> imageViewReference; 

     public LoadRows(ImageView imageView) { 
      // Use a WeakReference to ensure the ImageView can be garbage 
      // collected 
      imageViewReference = new WeakReference<ImageView>(imageView); 
     } 

     @Override 
     protected Bitmap doInBackground(String... params) { 
      data = params[0]; 

      Bitmap imageResult; 
      imageResult = getAlbumart(Long.parseLong(data)); 

      if (imageResult != null) { 
       imageResult = Bitmap.createScaledBitmap(imageResult, 300, 300, true); 
       addBitmapToMemoryCache(data, imageResult); 
       imageResult = Bitmap.createScaledBitmap(imageResult, 80, 80, true); 
      } 
      return imageResult; 
     } 


     @Override 
     protected void onPostExecute(Bitmap bitmap) { 
      super.onPostExecute(bitmap); 

      if (isCancelled()) { 
       bitmap = null; 
      } 

      if (bitmap != null) { 
       ImageView imageView = imageViewReference.get(); 
       LoadRows bitmapWorkerTask = getLoadRows(imageView); 
       if (this == bitmapWorkerTask) { 
        imageView.setImageBitmap(bitmap); 
       } 
      } 

     } 

    } 



    static class AsyncDrawable extends BitmapDrawable { 
     private final WeakReference<LoadRows> LoadRowsReference; 

     @SuppressWarnings("deprecation") 
     public AsyncDrawable(String res, Bitmap bitmap, LoadRows LoadRows) { 
      super(bitmap); 
      LoadRowsReference = new WeakReference<LoadRows>(LoadRows); 
     } 

     public LoadRows getLoadRows() { 
      return LoadRowsReference.get(); 
     } 
    } 

    public static boolean cancelPotentialWork(String data, ImageView imageView) { 
     final LoadRows LoadRows = getLoadRows(imageView); 

     if (LoadRows != null) { 
      final String bitmapData = LoadRows.data; 
      // If bitmapData is not yet set or it differs from the new data 
      if (bitmapData == "0" || bitmapData != data) { 
       // Cancel previous task 
       LoadRows.cancel(true); 
      } else { 
       // The same work is already in progress 
       return false; 
      } 
     } 
     // No task associated with the ImageView, or an existing task was 
     // cancelled 
     return true; 
    } 

    private static LoadRows getLoadRows(ImageView imageView) { 
     if (imageView != null) { 
      final Drawable drawable = imageView.getDrawable(); 
      if (drawable instanceof AsyncDrawable) { 
       final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; 
       return asyncDrawable.getLoadRows(); 
      } 
     } 

     return null; 
    } 

Пожалуйста, ребята, не торопитесь, я не спешит принять любой ответ очень скоро. Надеюсь, что кто-то может сыграть с кодом или если ничего, кроме как объяснить мне, каким должен быть мой подход.

Если вам, ребята, нужно что-то еще знать, просто дайте мне знать. Спасибо!

Редактировать

GetView() метод -

@SuppressWarnings("deprecation") 
    @SuppressLint("SimpleDateFormat") 
    public View getView(final int position, View convertView, ViewGroup parent) { 
     View vi = convertView; 
     final ViewHolder holder; 

     if (convertView == null) { 

      /****** Inflate tabitem.xml file for each row (Defined below) *******/ 
      vi = inflater.inflate(R.layout.row, null); 

      /****** View Holder Object to contain tabitem.xml file elements ******/ 

      holder = new ViewHolder(); 
      holder.text = (TextView) vi.findViewById(R.id.text); 
      holder.text1 = (TextView) vi.findViewById(R.id.text1); 
      holder.duration = (TextView) vi.findViewById(R.id.textTime); 
      holder.image = (ImageView) vi.findViewById(R.id.image); 
      holder.btn = (Button) vi.findViewById(R.id.button1); 

      /************ Set holder with LayoutInflater ************/ 
      vi.setTag(holder); 

     } else { 
      holder = (ViewHolder) vi.getTag(); 
     } 


     if (data.size() > 0) { 

      /***** Get each Model object from Arraylist ********/ 
      tempValues = null; 
      tempValues = (ListModel) data.get(position); 
      final String duration = tempValues.getDuration(); 
      final String artist = tempValues.getArtist(); 
      final String songName = tempValues.getName(); 
      final String title = tempValues.getTitle(); 
      final String albumid = tempValues.getAlbumID(); 

      String finalTitle; 
      if (title != null) { 
       finalTitle = title; 
      } else { 
       finalTitle = songName; 
      } 
      loadBitmap(albumid, holder.image); // HERE I GET IMAGE *********** 

      holder.text.setText(finalTitle); 
      holder.text1.setText(artist); 
      holder.duration.setText(duration); 

      vi.setOnClickListener(new OnClickListener() { 
       @Override 
       public void onClick(View v) { 
        MusicUtils.play(position, listModelToArrayList(), activity, songsManager); 
       } 
      }); 
      final PopupMenu pop = new PopupMenu(activity, holder.btn); 
      int[] j = new int[6]; 
      j[0] = MusicUtils.PLAY; 
      j[1] = MusicUtils.PLAY_NEXT; 
      j[2] = MusicUtils.ADD_TO_QUEUE; 
      j[3] = MusicUtils.ADD_TO_PLAYLIST; 
      j[4] = MusicUtils.SHUFFLE_PLAY; 
      j[5] = MusicUtils.DELETE; 
      MusicUtils.generateMenu(pop, j); 
      pop.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { 
       public boolean onMenuItemClick(MenuItem item) { 
        switch (item.getItemId()) { 
         case MusicUtils.PLAY: 
          MusicUtils.play(position, listModelToArrayList(), activity, songsManager); 
          return true; 
         case MusicUtils.DELETE: 
          return true; 
         case MusicUtils.PLAY_NEXT: 
          MusicUtils.playNext(listModelToArrayList().get(position)); 
          return true; 
         case MusicUtils.ADD_TO_QUEUE: 
          MusicUtils.addToQueue(listModelToArrayList().get(position), songsManager); 
          return true; 
         case MusicUtils.ADD_TO_PLAYLIST: 
          MusicUtils.addToPlaylist(position, listModelToArrayList().get(position), activity, songsManager); 
          return true; 
         case MusicUtils.SHUFFLE_PLAY: 
          MusicUtils.shufflePlay(position, listModelToArrayList(), activity, songsManager); 
          return true; 
         default: 
          return false; 
        } 
       } 
      }); 


      holder.btn.setOnClickListener(new View.OnClickListener() { 

       @Override 
       public void onClick(View v) { 
        pop.show(); 
       } 
      }); 

      tempValues = null; 
      vi.setVisibility(View.VISIBLE); 
     } else { 
      vi.setVisibility(View.INVISIBLE); 
     } 
     return vi; 
    } 

Обновление

С помощью UIL, то результат будет почти такой же, как код, который я до предусмотренного т.е.лаг. Но Picasso действительно стоит попробовать, я бы сказал, что отставание почти исчезло. Это почти то, что я хотел реализовать.

+3

Почему вы не используете библиотеку для загрузки изображений? например, UIL (универсальный загрузчик изображений) или Picasso или ...? –

+0

Я не уверен, но это работает только для загрузки изображений. Если это может сработать, то как я могу это сделать с альбомами музыкальных файлов? – Gavin

+0

Я попробовал UIL, и нет никакой разницы. Лаг все еще такой же. Пожалуйста помоги. – Gavin

ответ

0

Протянутый прокрутки исчез с использованием библиотеки Picasso. Я до сих пор не уверен, что может быть точной причиной этого, но просто заменив мою AsyncTask на работу Picasso, как прелесть. Это гораздо более плавное и эффективное, так как кеширование выполняется самой библиотекой.

Адрес: https://github.com/square/picasso.