码字辛苦!转载请注明出处!
我们知道,在安卓上运行JAVA有严格的内存限制,不能像PC上那样肆无忌惮的使用递归和多线程,否则~
OOM,经典不~
那么,如何在安卓上优雅搜索文件呢?
关键点就在于:
1、取代递归
2、适时终止上一个搜索线程
3、在主线程中更新List和View
4、避免线程中Activity对象造成的内存泄漏
——那我们把需要搜索的文件目录记录下来循环遍历,在回调时检测Activity生命周期,并进行线程切换,问题不就解决了嘛~
话不多说,上代码:
//搜索文件线程
private Thread t_searchFile;
public interface SearchFileListener {
void gotOne(File file);
void onFinished(List<File> searchedFiles);
}
//搜索文件
public List<File> searchFile(final Activity activity, final String filePath,
final String fileName, final SearchFileListener searchFileListener) {
//终止上一个搜索线程(如果有)
stopSearching();
final List<File> searchedFiles = new ArrayList<>();
if (TextUtils.isEmpty(fileName) || TextUtils.isEmpty(filePath)) {
return searchedFiles;
}
t_searchFile = new Thread() {
@Override
public void run() {
super.run();
//不使用递归,而是将需要扫描的文件目录记录下来
List<File> waitForSearchFilePath = new ArrayList<>();
waitForSearchFilePath.add(new File(filePath));
while (waitForSearchFilePath.size() > 0 && !isInterrupted() &&
//所有循环均检测Activity生命周期,以防内存泄漏
!activityIsDestroyed(activity)) {
File[] files = waitForSearchFilePath.get(0).listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (isInterrupted() && activityIsDestroyed(activity)) {
break;
}
final File temp = files[i];
//过滤掉没有读写权限的文件,以防权限异常崩溃
if (temp.canRead() && temp.canWrite()) {
//全部转换为小写再匹配,以使搜索结果不区分大小写
if (temp.getName().toLowerCase().contains(fileName.toLowerCase())) {
//当Activity生命周期已经结束时,终止搜索
if (activityIsDestroyed(activity)) {
break;
}
//将符合条件的项目添加到链表,并在主线程回调以便刷新页面
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
searchedFiles.add(temp);
if (searchFileListener != null) {
searchFileListener.gotOne(temp);
}
}
});
}
if (temp.isDirectory()) {
//将子目录添加到待扫描链表,替代递归
waitForSearchFilePath.add(temp);
}
}
}
}
//完成当前目录扫描,移除链表
waitForSearchFilePath.remove(0);
}
if (!activityIsDestroyed(activity) && !isInterrupted()) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (searchFileListener != null) {
searchFileListener.onFinished(searchedFiles);
}
}
});
}
}
};
t_searchFile.start();
return searchedFiles;
}
//终止搜索线程
public void stopSearching() {
if (t_searchFile != null) {
t_searchFile.interrupt();
}
}
//检测Activity生命周期
private boolean activityIsDestroyed(Activity activity) {
return activity == null || activity.isFinishing() || activity.isDestroyed();
}
使用上述方法,实测该线程的内存(不含已检出的文件List)只有不到3K,OOM问题完美解决~
网友评论