我已经创建了一个自定义类来从我们的服务器下载单个音频文件。单个下载工作没有任何问题,但现在我需要包括一次或连续下载多个音频文件的功能..
问题是应用程序因我的下载实施而崩溃:"应用程序没有响应。你想关闭吗? [等待] [退出]"
我不确定导致问题的原因,但我已经知道NotificationManager可能是问题所以我已经在一个教程上实现了它,该教程说它会修复它但是它没有。所以我认为它必须是线程的问题..
AudioDownload类:
public class AudioDownload implements Runnable {
private static Boolean bIAmBusy = false;
private Activity activity;
OnAudioDownloadFinishedListener mycallback;
private String Folder;
private String FileName;
private String FileUrl;
public AudioDownload(String COURSE_FLAG, String AUDIO, String language, Activity a){
Folder = COURSE_FLAG;
FileName = AUDIO;
FileUrl = "http://SOMEURL/"+ language + "/" + COURSE_FLAG + "/" + FileName;
activity = a;
}
@Override
public void run() {
bIAmBusy = true;
File localFile = new File(activity.getFilesDir() + "/" + Folder + "/" + FileName);
if(localFile.exists()){
//don't download
}
else{
/*
In older android versions, your Notification has to have a content Intent,
so that when the user clicks your Notification, something happens. This means you must:
Make an Intent object, pointing somewhere, such as your MainActivity.
Make sure to add the Intent.FLAG_ACTIVITY_NEW_TASK flag.
*/
Intent intent = new Intent(activity, CoursesActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(activity,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManager notificationManager = (NotificationManager) activity.getSystemService(activity.getApplicationContext().NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(activity);
builder.setContentTitle("Audio Download");
builder.setContentText("Download in Progress");
builder.setSmallIcon(R.drawable.btn_download);
builder.setTicker("Audio Download");
builder.setContentIntent(pendingIntent);
int id = 1;
BufferedInputStream in = null;
FileOutputStream out = null;
boolean saved = false;
try {
URL url = new URL(FileUrl);
URLConnection conn = url.openConnection();
int size = conn.getContentLength();
in = new BufferedInputStream(new URL(FileUrl).openStream());
final File dir = new File(activity.getFilesDir() + "/" + Folder);
dir.mkdirs();
final File file = new File(dir,FileName);
out = new FileOutputStream(file);
final byte data[] = new byte[1024];
int count;
int sumCount = 0;
while ((count = in.read(data, 0, 1024)) != -1) {
sumCount += count;
builder.setProgress(size,sumCount,false);
notificationManager.notify(id, builder.build());
out.write(data, 0, count);
}
saved = true;
builder.setContentText("Download Complete");
builder.setProgress(0,0,false);
notificationManager.notify(id, builder.build());
}catch (IOException e){
}
finally {
if(in != null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
final boolean finalSaved = saved;
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
mycallback.OnAudioDownloadThreadFinished(finalSaved);
}
});
}
bIAmBusy = false;
}
在我的活动按钮上单击我尝试排队线程。
public void onClick(View view) {
Thread t = new Thread(){
@Override
public void run() {
Log.d("Audio", "Downloading all the audio for the chapter");
Toast.makeText(context, "Downloading all the audio for the chapter", Toast.LENGTH_SHORT).show();
List<AudioDownload> downloadList = new ArrayList<AudioDownload>();
for (int child = 0; child < chapters.get(groupPosition).getSubChapters().size(); child++) {
String Language = "en";
String FileName = subChapters.get(chapters.get(group)).get(child).getAudio();
audioDownload = new AudioDownload(Course, FileName, Language, activity);
audioDownload.setOnAudioDownloadFinishedListener(new AudioDownload.OnAudioDownloadFinishedListener() {
@Override
public void OnAudioDownloadThreadFinished(Boolean success) {
if (success) {
Toast.makeText(context, "Download was successful", Toast.LENGTH_SHORT).show();
}
}
});
downloadList.add(audioDownload);
}
for (int i = 0; i < downloadList.size(); i++) {
while (downloadList.get(i).isBusy()) {
//wait
}
if (downloadList.get(i).isBusy() == false) {
new Thread(downloadList.get(i), "AudioDownload_" + i).start();
}
}
}
};
t.start();
等待Thread完成的while循环应该有效,因为bIamBusy被声明为static - &gt;从我的观点来看,预期的行为是每个AudioDownload在另一个完成后启动/启动。
不幸的是,App崩溃了多个下载。如上所述,如果我将此类用于单个音频下载,则App / UIThread不会崩溃。有人知道为什么会这样吗?
更新 应用程序仅在我下拉NotificationManager时崩溃。
ThreadLog ... - &gt;似乎它不会等待启动它们
17 30669 Native 21 6 AudioDownload_6
18 30666 Native 19 7 AudioDownload_4
19 30657 Native 20 7 AudioDownload_3
20 30673 Native 18 6 AudioDownload_10
21 30677 Native 20 8 AudioDownload_12
堆栈跟踪:
09-16 01:43:57.235 405-440/? E/ActivityManager﹕ ANR in smapp.com.smapp (smapp.com.smapp/.Controller.Screen_4.ChapterOverviewActivity)
Reason: keyDispatchingTimedOut
Load: 1.12 / 0.76 / 0.51
CPU usage from 10166ms to 4102ms ago:
36% 30551/smapp.com.smapp: 35% user + 1.3% kernel / faults: 2463 minor
17% 481/com.android.systemui: 16% user + 0.8% kernel / faults: 5726 minor
9.5% 405/system_server: 8.2% user + 1.3% kernel / faults: 483 minor
1.8% 121/surfaceflinger: 0.6% user + 1.1% kernel
0.2% 124/mediaserver: 0% user + 0.2% kernel / faults: 3 minor
0.9% 114/local_opengl: 0% user + 0.9% kernel
0.3% 60/adbd: 0% user + 0.3% kernel / faults: 34 minor
0.3% 112/vinput: 0% user + 0.3% kernel
0% 28602/flush-8:16: 0% user + 0% kernel
0% 29589/logcat: 0% user + 0% kernel
70% TOTAL: 60% user + 8.8% kernel + 1.1% softirq
CPU usage from 257ms to 760ms later:
59% 30551/smapp.com.smapp: 59% user + 0% kernel
55% 30551/smapp.com.smapp: 55% user + 0% kernel
3.8% 31130/AudioDownload_5: 1.9% user + 1.9% kernel
1.9% 31121/AudioDownload_2: 1.9% user + 0% kernel
1.9% 31122/AudioDownload_3: 1.9% user + 0% kernel
24% 481/com.android.systemui: 20% user + 4% kernel / faults: 657 minor
16% 481/ndroid.systemui: 16% user + 0% kernel
4% 575/Binder_3: 2% user + 2% kernel
2% 519/GC: 2% user + 0% kernel
2% 526/Binder_2: 2% user + 0% kernel
10% 405/system_server: 8% user + 2% kernel
2% 405/system_server: 2% user + 0% kernel
2% 415/Binder_1: 0% user + 2% kernel
2% 416/Binder_2: 0% user + 2% kernel
2% 440/InputDispatcher: 0% user + 2% kernel
2% 662/Binder_5: 2% user + 0% kernel
1.7% 60/adbd: 0% user + 1.7% kernel
1.7% 121/surfaceflinger: 0% user + 1.7% kernel
1.7% 303/VSyncThread: 0% user + 1.7% kernel
100% TOTAL: 90% user + 10% kernel
答案 0 :(得分:0)
如果你想让线程等到其他线程完成,那么'CountDownLatch'将是一个巨大的帮助。这是一个关于如何使用它的快速sudocode示例。
'CountDownLatch l = new CountDownLatch(n)' n是您需要等待的任务数
'l.await()' 在后台线程中调用它来等待所有n个任务完全阻止
'l.countdown()' 在每个任务完成后调用,减少此锁存器等待的任务数量一旦达到0,await方法将释放,之后的其余代码将在该点执行
答案 1 :(得分:0)
我现在已经解决了问题,感谢您的支持。 CountDownLatch是我的解决方案。
现在正在制定工作守则:
public class AudioDownload implements Runnable {
private static Boolean bIAmBusy = false;
private Activity activity;
OnAudioDownloadFinishedListener mycallback;
private final CountDownLatch latch;
private String Folder;
private String FileName;
private String FileUrl;
public AudioDownload(String COURSE_FLAG, String AUDIO, String language, Activity a, CountDownLatch latch){
Folder = COURSE_FLAG;
FileName = AUDIO;
FileUrl = "http://xxx.xx/xxxxx/xxxx/"+ language + "/" + COURSE_FLAG + "/" + FileName;
activity = a;
this.latch = latch;
}
@Override
public void run() {
bIAmBusy = true;
File localFile = new File(activity.getFilesDir() + "/" + Folder + "/" + FileName);
if(localFile.exists()){
//don't download
}
else{
/*
In older android versions, your Notification has to have a content Intent,
so that when the user clicks your Notification, something happens. This means you must:
Make an Intent object, pointing somewhere, such as your MainActivity.
Make sure to add the Intent.FLAG_ACTIVITY_NEW_TASK flag.
*/
Intent intent = new Intent(activity, CoursesActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(activity,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManager notificationManager = (NotificationManager) activity.getSystemService(activity.getApplicationContext().NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(activity);
builder.setContentTitle("Audio Download");
builder.setContentText("Download in Progress");
builder.setSmallIcon(R.drawable.btn_download);
builder.setTicker("Audio Download");
builder.setContentIntent(pendingIntent);
int id = 1;
BufferedInputStream in = null;
FileOutputStream out = null;
boolean saved = false;
try {
URL url = new URL(FileUrl);
URLConnection conn = url.openConnection();
int size = conn.getContentLength();
in = new BufferedInputStream(new URL(FileUrl).openStream());
final File dir = new File(activity.getFilesDir() + "/" + Folder);
dir.mkdirs();
final File file = new File(dir,FileName);
out = new FileOutputStream(file);
final byte data[] = new byte[1024];
int count;
int sumCount = 0;
while ((count = in.read(data, 0, 1024)) != -1) {
sumCount += count;
builder.setProgress(size,sumCount,false);
notificationManager.notify(id, builder.build());
out.write(data, 0, count);
}
saved = true;
builder.setContentText("Download Complete");
builder.setProgress(0,0,false);
notificationManager.notify(id, builder.build());
}catch (IOException e){
}
finally {
if(in != null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
final boolean finalSaved = saved;
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
mycallback.OnAudioDownloadThreadFinished(finalSaved);
}
});
}
latch.countDown();
bIAmBusy = false;
}
public interface OnAudioDownloadFinishedListener{
void OnAudioDownloadThreadFinished(Boolean success);
}
public void setOnAudioDownloadFinishedListener(OnAudioDownloadFinishedListener listener){
mycallback = listener;
}
public Boolean isBusy() {
return bIAmBusy;
}
}
在我的onClick方法中:
public void onClick(View view) {
Thread t = new Thread(){
@Override
public void run() {
Log.d("Audio", "Downloading all the audio for the chapter");
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "Downloading all the audio for the chapter", Toast.LENGTH_SHORT).show();
}
});
final CountDownLatch latch = new CountDownLatch(chapters.get(groupPosition).getSubChapters().size());
Executor ex;
for (int child = 0; child < chapters.get(groupPosition).getSubChapters().size(); child++) {
String Language = "en";
String FileName = subChapters.get(chapters.get(group)).get(child).getAudio();
audioDownload = new AudioDownload(Course, FileName, Language, activity, latch);
audioDownload.setOnAudioDownloadFinishedListener(new AudioDownload.OnAudioDownloadFinishedListener() {
@Override
public void OnAudioDownloadThreadFinished(Boolean success) {
if (success) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "Download was successful", Toast.LENGTH_SHORT).show();
}
});
}
}
});
ex = new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
};
ex.execute(audioDownload);
}
try{
latch.await();
Log.d("multipleAudioDownload", "all Threads are finished");
Toast.makeText(context, "Downloading was successful", Toast.LENGTH_SHORT).show();
}catch (InterruptedException e){
Log.e("multipleAudioDownload",e.getMessage());
}
}
};
t.start();
}