2014-01-25 5 views
3

Я занимаюсь разработкой музыкального проигрывателя. поэтому мне нужно загрузить список композиций в пользовательском ListView, который имеет один ImageView и два textView. Производительность слишком медленная, поэтому я искал в google, и я нашел решение, в котором говорится: «Использовать AsyncTasks и загрузить listView в фоновом режиме». Но все же производительность listview слишком медленная. Пожалуйста, помогите мне повысить производительность списка. вот мой код:Производительность ListView слишком медленная, хотя внутри AsyncTask

Этот код загружает пользовательский ArrayList, получая значения из song_database и находится внутри класса Activity.

private ArrayList getListData() { 
    ArrayList results = new ArrayList(); 
    Song Data = new Song(); 
    Database_Song db = new Database_Song(this); 
    String data = db.getData(); 
     StringTokenizer token = new StringTokenizer(data,";"); 

     while(token.hasMoreTokens()) 
     { 
      String dataPart = token.nextToken(); 
      StringTokenizer tokenPart = new StringTokenizer(dataPart,"|"); 
      Data = new Song(); 
      Data.setSongTitle(tokenPart.nextToken()); 
      mediaInfo.setDataSource(tokenPart.nextToken()); 

      if (mediaInfo.getEmbeddedPicture() != null){ 
       byte[] img = mediaInfo.getEmbeddedPicture(); 
       Data.setImage((BitmapFactory.decodeByteArray(img, 0,img.length))); 
      } 
      else 
       Data.setImage(BitmapFactory.decodeResource(this.getResources(), R.drawable.album_art)); 

      Data.setAlbumName(tokenPart.nextToken()); 
      results.add(Data); 
     } 

     return results; 
} 

Это мой класс AsyncTasks, который является внутренним классом класса Activity.

private class LoadListTask extends AsyncTask<String, Void, Integer> { 
    ArrayList Song_details; 
    protected void onPreExecute() { 

    } 

    protected Integer doInBackground(String... params) { 
     Song_details = getListData(); 
     return 0; 
    } 

    protected void onPostExecute(Integer result) { 
     adapter = new CustomListAdapter_Song(cont, Song_details); 
     lv_song.setAdapter(adapter); 

     if (result == 0) { 
      adapter.notifyDataSetChanged(); 
     } 
    } 
} 

это мой адаптер класса

public class CustomListAdapter_Song extends BaseAdapter{ 

private ArrayList<Song> listData; 
private LayoutInflater layoutInflater; 
private ArrayList<Song> arraylist; 
private int lastPosition = -1; 

public CustomListAdapter_Song(Context context, ArrayList<Song> listData) { 
    this.listData = listData; 
    layoutInflater = LayoutInflater.from(context); 
    this.arraylist = new ArrayList<Song>(); 
    this.arraylist.addAll(listData); 
} 

@Override 
public int getCount() { 
    return listData.size(); 
} 

@Override 
public Object getItem(int position) { 
    return listData.get(position); 
} 

@Override 
public long getItemId(int position) { 
    return position; 
} 

public View getView(int position, View convertView, ViewGroup parent) { 
    ViewHolder holder; 
    if (convertView == null) { 
     convertView = layoutInflater.inflate(R.layout.listview_item_row_for_data, null); 
     holder = new ViewHolder(); 
     holder.songName = (TextView) convertView.findViewById(R.id.Song_songTitle); 
     holder.albumName = (TextView) convertView.findViewById(R.id.Song_AlbumName); 
     holder.songImage = (ImageView) convertView.findViewById(R.id.Song_AlbumImage); 
     convertView.setTag(holder); 

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

    holder.songName.setText(listData.get(position).getSongTitle()); 
    holder.albumName.setText(listData.get(position).getAlbumName()); 
    holder.songImage.setImageBitmap((listData.get(position).getImage())); 
    View view = convertView; 
    Animation animation = AnimationUtils.loadAnimation(view.getContext(), (position > lastPosition) ? R.anim.up_from_bottom : R.anim.down_from_top); 
    view.startAnimation(animation); 
    lastPosition = position; 

    return convertView; 
} 

static class ViewHolder { 
    TextView songName; 
    TextView albumName; 
    ImageView songImage; 
} 

}

+0

сообщить свой код адаптера – Raghunandan

+0

Что значит «производительность медленная»? Запугивает ли он, когда вы прокручиваете список, или занимает много времени, чтобы элементы отображались? –

+2

Используйте Traceview, 'StrictMode' и аналогичные инструменты, чтобы определить, где ваша проблема. – CommonsWare

ответ

1

Не используйте AsyncTask, но вам нужно CursorLoader

public class SongsFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> 
{ 
    SongAdapter adapter; 

    @Override 
    public View onCreateView(LayoutInflater inflater , ViewGroup container , Bundle savedInstanceState) 
    { 
     return inflater.inflate(R.layout.fragment_songs, container, false); 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     adapter = new SongAdapter(getActivity(), null); 
     setListAdapter(adapter); 
     getLoaderManager().initLoader(0, null, this); 

    } 

    private class SongAdapter extends CursorAdapter 
    { 
     Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart"); 

     public SongAdapter(Context context , Cursor c) 
     { 
      super(context , c , true); 
     } 

     @Override 
     public View getView(int position , View convertView , ViewGroup parent) 
     { 
      View v; 
      Cursor cursor = (Cursor) getItem(position); 
      if (convertView == null) 
      { 
       v = newView(mContext, cursor, parent); 
      } 
      else 
      { 
       v = convertView; 
      } 
      bindView(v, mContext, cursor); 
      return v; 
     } 

     @Override 
     public void bindView(View view , Context context , Cursor cursor) 
     { 
      ViewHolder holder = (ViewHolder) view.getTag(); 
      holder.songNameTextView.setText(cursor.getString(2)); 
      holder.artistTextView.setText(cursor.getString(1)); 
      Uri albumArtUri = ContentUris.withAppendedId(sArtworkUri, cursor.getLong(3)); 
      Picasso.with(getActivity()).load(albumArtUri).error(R.drawable.placeholder).placeholder(R.drawable.placeholder).into(holder.albumImageView); 
     } 

     @Override 
     public View newView(Context context , Cursor cursor , ViewGroup parent) 
     { 
      View view = LayoutInflater.from(context).inflate(R.layout.row_song, parent, false); 
      ViewHolder holder = new ViewHolder(); 
      holder.albumImageView = (ImageView) view.findViewById(R.id.albumImg); 
      holder.songNameTextView = (TextView) view.findViewById(R.id.songNameTxtView); 
      holder.artistTextView = (TextView) view.findViewById(R.id.artistNameTxtView); 
      view.setTag(holder); 
      return view; 
     } 
    } 

    private static class ViewHolder 
    { 
     public ImageView albumImageView; 
     public TextView  artistTextView; 
     public TextView  songNameTextView; 
    } 

    @Override 
    public Loader<Cursor> onCreateLoader(int arg0 , Bundle arg1) 
    { 
     String[] projection = { MediaStore.Audio.Media._ID, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ALBUM_ID }; 
     String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0"; 
     return new CursorLoader(getActivity(), MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, null, null); 
    } 

    @Override 
    public void onLoadFinished(Loader<Cursor> arg0 , Cursor data) 
    { 
     adapter.swapCursor(data); 
    } 

    @Override 
    public void onLoaderReset(Loader<Cursor> arg0) 
    { 
     adapter.swapCursor(null); 
    } 
} 
0

Идея использовать AsyncTask для загрузки данных для списка view означает загрузку данных ТОЛЬКО для определенных предметов. Как известно, ListView запрашивает у него адаптер только для элементов, которые видны на экране (плюс пара выше и ниже видимой области). Как только ваш адаптер не обязательно будет предоставлять все данные одновременно, вы можете загрузить его по требованию.
Ниже просто sckeleton возможной реализации:

// We need a queue to run only one AsyncTask 
    // How to deal with queue you may find here 
    // http://developer.android.com/reference/java/util/concurrent/BlockingQueue.html 
    BlockingQueue loadViewQueue; 


    @Override 
    public int getCount() { 
     return countOfYourData; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     if(convertView == null) { 
      convertView = LayoutInflater.from(getContext()).inflace(yourresId, parent, false); 
     } 

     // if you don't use ViewHolder patter you may store position as shown below 
     // otherwise create appropriate field in ViewHolder class and store position there 
     convertView.setTag(position); 
     loadViewQueue.put(convertView); 
    } 

    class LoadingAsyncTask extends AsyncTask< View, Object, Void > { 
     Integer position; 
     @Override 
     protected Void doInBackground(View... params) { 

      while(true) { 
       View view = loadViewQueue.take(); 
       position = (Integer)view.getTag(); 
       Data data = loadDataFromDb(position); 
       publishProgress(position, data); 
      } 
      return null; 
     } 

     @Override 
     protected void onProgressUpdate(Object result) { 
      applyDataToListItem((Integer)result[0], (Data)result[1]); 
     } 
    } 

очереди, конечно, должен быть синхронизирован и ошибка проверки добавлена.

Смежные вопросы