线程——如何提高App的性能
Threading - how to improve the performance of App
我正在制作一个应用程序,它可以扫描 phone 存储中的歌曲列表并将它们存储在 ListView
中。所以,我创建了 class 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
。所以,我决定提高应用程序的性能。我修改了 class 如下
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;
}
}
考虑使用 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
看起来像这样
public class Tab1 扩展 ListFragment 实现 GetSongsAsyncTask.SongsReceivedListener{
私有ListView lv;
// 歌曲列表
public ArrayList> songsList = new ArrayList>();
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);
}
}
我正在制作一个应用程序,它可以扫描 phone 存储中的歌曲列表并将它们存储在 ListView
中。所以,我创建了 class 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
。所以,我决定提高应用程序的性能。我修改了 class 如下
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;
}
}
考虑使用 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
看起来像这样
public class Tab1 扩展 ListFragment 实现 GetSongsAsyncTask.SongsReceivedListener{
私有ListView lv; // 歌曲列表 public ArrayList> songsList = new ArrayList>(); 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);
}
}