线程 - 如何提高App的性能

时间:2016-07-03 11:52:08

标签: android multithreading runnable

我正在创建一个应用程序,用于扫描手机存储中的歌曲列表并将其存储在ListView中。所以,我创建了一个类SongsManager,它扫描SD卡中的歌曲并将它们存储在Array中。代码如下所示。

public class SongsManager {
final String MEDIA_PATH = Environment.getExternalStorageDirectory() .getPath() + "/";
private ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>();
private String mp3Pattern = ".mp3";
private File directory;

// Constructor
 public SongsManager() {
 }

/** * Function to read all mp3 files and store the details in * ArrayList * */

public ArrayList<HashMap<String, String>> getPlayList() {
            System.out.println(MEDIA_PATH);
            if (MEDIA_PATH != null) {
                File home = new File(MEDIA_PATH);
                File[] listFiles = home.listFiles();
                if (listFiles != null && listFiles.length > 0) {
                    for (File file : listFiles) {
                        System.out.println(file.getAbsolutePath());
                        if (file.isDirectory()) {
                            scanDirectory(file);
                        } else {
                            addSongToList(file);
                        }
                    }
                }
            }
    return songsList;
}


private void scanDirectory(final File directory) {
            if (directory != null) {
                File[] listFiles = directory.listFiles();
                if (listFiles != null && listFiles.length > 0) {
                    for (File file : listFiles) {
                        if (file.isDirectory()) {
                            scanDirectory(file);
                        } else {
                            addSongToList(file);
                        }
                    }
                }
            }
    }


private void addSongToList(File song) {
    if (song.getName().endsWith(mp3Pattern)) {
        HashMap<String, String> songMap = new HashMap<String, String>();
        songMap.put("songTitle", song.getName().substring(0, (song.getName().length() - 4)));
        songMap.put("songPath", song.getPath());

        // Adding each song to SongList
        songsList.add(songMap);
    }
}
 }

当我运行该应用程序时,由于从SD卡获取歌曲,应用程序会冻结2或3秒。当我打开logcat时,它会显示错误 The application may be doing too much work on its main thread 。所以,我决定提高应用程序的性能。我修改了类如下

 public class SongsManager {

final String MEDIA_PATH = Environment.getExternalStorageDirectory() .getPath() + "/";
private ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>();
private String mp3Pattern = ".mp3";
private File directory;

// Constructor
 public SongsManager() {
 }

/** * Function to read all mp3 files and store the details in * ArrayList * */

public ArrayList<HashMap<String, String>> getPlayList() {
            System.out.println(MEDIA_PATH);
            if (MEDIA_PATH != null) {
                File home = new File(MEDIA_PATH);
                File[] listFiles = home.listFiles();
                if (listFiles != null && listFiles.length > 0) {
                    for (File file : listFiles) {
                        System.out.println(file.getAbsolutePath());
                        if (file.isDirectory()) {
                            scanDirectory(file);
                        } else {
                            addSongToList(file);
                        }
                    }
                }
            }
    return songsList;
}


private void scanDirectory(final File directory) {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            if (directory != null) {
                File[] listFiles = directory.listFiles();
                if (listFiles != null && listFiles.length > 0) {
                    for (File file : listFiles) {
                        if (file.isDirectory()) {
                            scanDirectory(file);
                        } else {
                            addSongToList(file);
                        }
                    }
                }
            }
        }
    };
    Thread thread = new Thread(r);
    thread.start();
}


private void addSongToList(File song) {
    if (song.getName().endsWith(mp3Pattern)) {
        HashMap<String, String> songMap = new HashMap<String, String>();
        songMap.put("songTitle", song.getName().substring(0, (song.getName().length() - 4)));
        songMap.put("songPath", song.getPath());

        // Adding each song to SongList
        songsList.add(songMap);
    }
}
} 

修改代码后,冻结问题解决了但是提取的歌曲无法正常工作。当我打开应用程序时,会加载一些歌曲,而某些歌曲则不会。当我重新打开应用程序时,会加载更多歌曲。这个问题正在发生。 这是我的Tab1 Class代码

public class Tab1 extends ListFragment {

private ListView lv;
// Songs list
public ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>();


public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View V = inflater.inflate(R.layout.tab1, container, false);

    ArrayList<HashMap<String, String>> songsListData = new ArrayList<HashMap<String, String>>();
    SongsManager plm = new SongsManager();
    // get all songs from sdcard
    this.songsList = plm.getPlayList();

    // looping through playlist
    for (int i = 0; i < songsList.size(); i++) {
        // creating new HashMap
        HashMap<String, String> song = songsList.get(i);
        // adding HashList to ArrayList
        songsListData.add(song);
    }

    // Adding menuItems to ListView
    ListAdapter adapter = new SimpleAdapter(getContext(), songsListData,
            R.layout.playlist_item, new String[]{"songTitle"}, new int[]{
            R.id.songTitle});
    setListAdapter(adapter);
    return V;
}

}

1 个答案:

答案 0 :(得分:0)

考虑使用AsyncTask代替上述实现..在您的实现中,无法保证在plm.getPlaylist()完成之后扫描所有歌曲,因为它是在几个不同的线程上完成的。这就是为什么你没有看到所有歌曲的原因。

public class GetSongsAsyncTask extends AsyncTask<Void, Void, List<Hashmap<String, String>>> {
private final SongsManager mSongsManager;

public interface SongsReceivedListener {
    void onSongsReceived(List<HashMap<String, String>> songs);
}

private SongsReceivedListener mSongsReceivedListener;

public GetSongsAsyncTask(SongsReceivedListener mSongsReceivedListener) {
    this.mSongsReceivedListener = mSongsReceivedListener;
    mSongsManager = new SongsManager();
}

@Override
protected List<HashMap<String, String>> doInBackground(Void.. voids) {
    return mSongsManager.getPLayList();
}

@Override
protected void onPostExecute(List<HashMap<String, String>> v) {
    if(mSongsReceivedListener != null) {
        mSongsReceivedListener.onSongsReceived(v);
    }
}
}

你的列表片段将实现SongsReceivedListener并像这样调用这个AsyncTask

new GetSongsAsyncTask(this).execute(); 

您的ListFragment将如下所示

公共类Tab1扩展ListFragment实现GetSongsAsyncTask.SongsReceivedListener {

私人ListView lv; //歌曲列表 public ArrayList&gt; songsList = new ArrayList&gt;();     public void onCreate(Bundle savedInstanceState){         super.onCreate(savedInstanceState);     }

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View V = inflater.inflate(R.layout.tab1, container, false);
    new GetSongsAsyncTask(this).execute(); 
    return V;
}

@Override
void onSongsReceived(List<Hashmap<String, String>> songs) {
  if(getContext() == null)
   return;
  // looping through playlist
  for (int i = 0; i < songsList.size(); i++) {
      // creating new HashMap
      HashMap<String, String> song = songs.get(i);
      // adding HashList to ArrayList
      songsListData.add(song);
  }

  // Adding menuItems to ListView
  ListAdapter adapter = new SimpleAdapter(getContext(), songsListData,
          R.layout.playlist_item, new String[]{"songTitle"}, new int[]{
          R.id.songTitle});
  setListAdapter(adapter);
}

}