1

I am developing a music app and my app takes a lot of time to generate the list of music files(because it has to generate the bitmaps) so I searched the net and came to know about the asynctask, I was able to implement it successfully in one another problem I had (so I think I understand the logic behind it) but in this case I just cant figure a way how to do it,(

Custom Adapter is confusing me a bit,i am wondering where should i do the tasks a- synchronously ,while i am generating the list or whether in the custom adapter where i am displaying the list i have generated )

so please I need help. here is the logic behind the program

I have a class "SongDetails" which has the following elements

Bitmap icon;
String song;
String Artist;
String Album;
String Path;

I have created an arraylist of SongDetails now I have another class called getSongsFromDirectory which searches for music files, fetches album and artist info from it, and adds the each item to the ArrayList and when the list is generated it returns the list to the onCreate method.Now onCreate method sorts the list by name of the songs and then gives the list to the custom adapter which displays the result,I can't understand where I should put this async task thing...........here is the code I have used

public class FragmentSongs extends  Fragment implements Serializable  {

    
    


    AdapterView.AdapterContextMenuInfo info;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) 
    {
              
       
       
       
       
        View view = inflater.inflate(R.layout.fragment_song, container, false);
                ListView SngList = (ListView) view.findViewById(R.id.SongList);
        registerForContextMenu(SngList);
        //File f=new File(Environment.getExternalStorageDirectory()+"Music");
        //File f=new File("/sdcard/Music");
        File f=new File(Environment.getExternalStorageDirectory()+"musicz");
        //File f=new File("/storage/extSdCard/My Music/");
        int j=0;int i=0;
        
        getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

         final ArrayList<SongDetails> Songinfo = getSongsFromDirectory(f);
         FragmentSongs dv=new  FragmentSongs ();
         if (Songinfo.size()>0)
        {
         Bundle bundle = new Bundle();
        
         bundle.putParcelableArrayList("Fragdata",Songinfo);
         dv.setArguments(bundle);
         
        }
         
         
         
        
        
        if (Songinfo.size()>0)
        {
            
            for( j=0; j<Songinfo.size();j++)
            {
                for ( i=j+1 ; i<Songinfo.size(); i++)
                { 
                    SongDetails a=Songinfo.get(i);
                    SongDetails b=Songinfo.get(j);
                    if(a.getSong().toLowerCase().compareTo(b.getSong().toLowerCase())<0)
                    {   
                
                        Songinfo.set(i,b );
                        Songinfo.set(j,a);
                    }
                }
                
            }

            SngList.setOnItemClickListener(new OnItemClickListener() {
                 public void onItemClick(AdapterView a, View v, int position, long id) {
                                
                
                       Intent intent = new Intent(getActivity(), NowPlaying.class);
                       
                       intent.putParcelableArrayListExtra("Data1",Songinfo);
                       
                       intent.putExtra("Data2",position);
                       startActivity(intent);
                 
                             }
                     });
            
        
           SngList.setAdapter(new CustomAdapter(Songinfo));
           return view;
        }
        else return null;
              
    }
    public ArrayList<SongDetails> getSongsFromDirectory(File f)
        {MediaMetadataRetriever mmr = new MediaMetadataRetriever();
        
            ArrayList<SongDetails> songs = new ArrayList<SongDetails>();
            Bitmap bitmap2; 
            Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ab);

            float ht_px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics());
            float wt_px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics());
            
            Bitmap bitmap3 = Bitmap.createScaledBitmap(bmp, (int) ht_px, (int) wt_px, true);
            byte[] rawArt = null;
            Bitmap art;
            BitmapFactory.Options bfo=new BitmapFactory.Options();
            if (!f.exists() || !f.isDirectory()) 
            {    
                return songs;
            }
            File[] files = f.listFiles(new Mp3Filter());
            for(int i=0; i<files.length; i++) 
            { 
                if (files[i].isFile())
                { 
                 mmr.setDataSource(files[i].getPath());
                 rawArt = mmr.getEmbeddedPicture();
                    SongDetails detail=new SongDetails(); 
                if ( rawArt != null) 
                    {   
                    bitmap2=BitmapFactory.decodeByteArray(rawArt, 0, rawArt.length, bfo);
                    bitmap2 = Bitmap.createScaledBitmap(bitmap2, (int) ht_px, (int) wt_px, true);
                     
                    detail.setIcon(bitmap2);
                }else 
            {   
                    detail.setIcon(bitmap3);
                }   
           
                    detail.setSong(files[i].getName()); 
           detail.setArtist(files[i].getName());
           detail.setArtist(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST)); 
           if (mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST)==null||(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST)==""))
           {  detail.setArtist("Unknow Artist");   }
           detail.setAlbum(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM)); 
           if (mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM)==null||mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM)=="")
           {  detail.setAlbum("Unknow Album");   }
           detail.setPath2( files[i].getPath()) ;
           songs.add(detail); 
                }
                else if (files[i].isDirectory())
                { 
                songs.addAll(getSongsFromDirectory(files[i])); 
                } 
         
            }       return songs;
    }
        @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) 
        {
                        super.onCreateContextMenu(menu, v, menuInfo);      
                       info = (AdapterContextMenuInfo) menuInfo;
                       menu.add(Menu.NONE, v.getId(), 0, "Play");
                       menu.add(Menu.NONE, v.getId(), 0, "Delete");
                       menu.add(Menu.NONE, v.getId(), 0, "Queue Item");                  
               }
                
        @Override
        public boolean onContextItemSelected(MenuItem item) {
                if (item.getTitle() == "Play") {
                  
                       }
                 else if (item.getTitle() == "Delete") {
                  
                       }
                      
                 else if (item.getTitle() == "Queue Item") {
                   
                       }
                 else     {
                       return false;
                       }
               return true;
               }}
    
    
        class Mp3Filter implements FileFilter
        {
            public boolean accept(File file)
            {
            return (file.isDirectory()||file.getName().endsWith(".mp3")|| file.getName().endsWith(".Mp3")||file.getName().endsWith(".wma")||file.getName().endsWith(".Wma")||file.getName().endsWith(".WMA")||file.getName().endsWith(".mp4"));
            }
        }
    

now here is the code for the adapter

public class CustomAdapter extends BaseAdapter {

    private ArrayList<SongDetails> _data;

    CustomAdapter (ArrayList<SongDetails> data){
        _data = data;
    }

    public int getCount() {

        return _data.size();
    }

    public Object getItem(int position) {

        return _data.get(position);
    }

    public long getItemId(int position) {

        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {

        Context context = parent.getContext();
        View v = convertView;

        if (v == null) {
           v = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
        }
        SongDetails sng = _data.get(position);
        ImageView image = (ImageView) v.findViewById(R.id.icon);
        ImageView image2 = (ImageView) v.findViewById(R.id.icon);
        TextView SongView = (TextView)v.findViewById(R.id.Song);
        TextView AlbumView = (TextView)v.findViewById(R.id.Album);
        TextView ArtistView = (TextView)v.findViewById(R.id.Artist);
       /*ImageLoaderConfiguration config=new ImageLoaderConfiguration.Builder(context).build();
        ImageLoader imageloader=ImageLoader.getInstance();  
        imageloader.init(config);
        imageloader.displayImage( null, image2);
       */

        image.setImageBitmap(sng.icon);
        image2.setBackgroundResource(sng.icLauncher);
        SongView.setText(sng.song);
        AlbumView.setText(sng.Album);
        ArtistView.setText(sng.Artist);

        return v;
    }
}
Community
  • 1
  • 1
Ankit Srivastava
  • 280
  • 2
  • 7
  • 24

1 Answers1

2

i can't understand where i should put this async task thing.

The AsyncTask should be used when you need your application to perform a long-running, and/or potentially blocking (e.g., file read) operation. The way you have it structured now, your application will seem to hang and be unresponsive because you're performing all these file reads on the main UI thread. This is where the AsyncTask comes in. When you use this class, your "work" is done on a separate thread, so that the UI can still respond while the work is going on.

You can find plenty of examples on how to properly use this class on this site, or by searching Google, or by checking the official documentation here.

You can write a custom AsyncTask class, instantiate it, and call its execute() method inside your activity's onCreate() method.

You will perform your file scans in the doInBackground() method of your AsyncTask and then deliver the final ArrayList back to the adapter (e.g., by calling adapter.addAll(yourSongListArray)) in the postExecute() method.

Hope that helps.

Eugene S
  • 3,092
  • 18
  • 34
  • thanx for telling me that file searching takes a long time....+1 for that but i was thinking that i should perform the generation of bitmaps, a-synchronously, is that a good idea? – Ankit Srivastava Aug 26 '13 at 19:00
  • i can shift the code for generating the bitmaps from my main activity to the adapter itself(adapter was previously just setting the bitmap,now it will generate it too) – Ankit Srivastava Aug 26 '13 at 19:02
  • also i was thinking of taking this to a whole new level,avoid searching of the files again and again and instead why not store the object into a file and fetch the results from there ??will i have to write too much code for that?(i am yet to try file handling but i have tried async task once)which will be the better option according to you? – Ankit Srivastava Aug 26 '13 at 19:05
  • It's not so much a matter of where the code live, which has more to do with design, than it is a matter of where the code exeuctes, which has to do with performance. Any CPU-intensive task (e.g., reading/decoding bitmaps) should not be done on the UI thread, but on a separate thread like by using an `AsyncTask`. You're also better off storing this data in an SQLite database rather than a flat file. What happens if you want to implement a song search feature? – Eugene S Aug 26 '13 at 19:12
  • yeah,what i meant was after shifting the code to the adapter i can implement the async task only once. i won't have to do the async thing twice(once while generating and the other while displaying) right now i am not storing this data anywhere .... – Ankit Srivastava Aug 26 '13 at 19:21
  • i still cant think of a away how to implement the async on file-searching,because it will really complicate things for me... – Ankit Srivastava Aug 26 '13 at 19:22
  • You don't need an an AsyncTask to display the data, that's your adapter's job and it does this on the UI thread. Your AsyncTask should only be responsible for loading the data (into a List in your example) and then handing this list to the adapter for display. The adapter should do just this: adapt. Leave loading the data to the AsyncTask, which you can create and execute inside your Activity. – Eugene S Aug 26 '13 at 19:40
  • yeah but i think the structure of my code is too poor and that will take alot of time to do this...thats why i was thinking of doing it in the adapter(tried just now,and the app crashes) – Ankit Srivastava Aug 26 '13 at 19:43
  • how can we continue this discussion in the chat? – Ankit Srivastava Aug 26 '13 at 19:50
  • i have a few questions to ask – Ankit Srivastava Aug 26 '13 at 19:51
  • i am not sure why should i use ArrayAdapter? – Ankit Srivastava Aug 26 '13 at 19:55
  • I take back the `ArrayAdapter` part, and have edited my response to reflect that. I think I may have mis-read your original question. And sorry, can't do chat. – Eugene S Aug 26 '13 at 20:15
  • ok no problem, and you said perform your file scans in the doInBackground() method of your AsyncTask and then deliver the final ArrayList back to the adapter – Ankit Srivastava Aug 26 '13 at 20:16
  • whats the point??, (i think i still don't understand how async task works...) should i not deliver the Arraylist in parts?i mean as soon as a new file is generated(and not wait for the whole result),transfer it in the post execute so that it is displayed ??or will async task handle this on its own? – Ankit Srivastava Aug 26 '13 at 20:19
  • You can use the `AsyncTask`'s `onProgressUpdate()` method to publish interim results. – Eugene S Aug 26 '13 at 20:43