#java #android #android-asynctask
#java #Android #android-asynctask
Вопрос:
У меня есть AsycTask
выполнение действий, таких как копирование или перемещение файлов в приложении, и я часто обновляю индикатор выполнения в диалоговом publishProgress()
окне.
ПРОБЛЕМА
Код работает почти нормально, хотя, когда AsyncTask
выполняет действия и обновляет индикатор выполнения (вызовы setProgress()
onProgressUpdate()
), он обновляется не сразу, пока задача не будет завершена… тем не менее TextView
, обновленное в том же месте обновляется.
Я попробовал обходной путь… для использования sleep(1)
в AsyncTask
потоке, чтобы разрешить выполнение основного потока (обновите индикатор выполнения :-)). Это сработало, и индикатор выполнения обновлялся по мере удаления файлов… но существует большая разница во времени выполнения следующим образом.
Перед добавлением sleep(1)
Общее количество удаленных файлов — 3804
Среднее затраченное время — 5s
(в среднем 3 теста)
После добавления sleep(1)
Общее количество удаленных файлов — 3804
Среднее затраченное время — 1m 40s
(в среднем 3 теста)
Как вы можете видеть sleep(1)
, это привело к огромному изменению времени выполнения. Есть ли другой способ обойти это… Чтобы обновить индикатор выполнения атомарно, я действительно благодарен за любые предложения…вот код…
Примечание: я попытался удалить те же файлы с помощью другого загруженного приложения filemanager, которое показывает индикатор выполнения во время удаления, а время указано относительно теста, в котором я добавил sleep (1) (1m 40s)
Мой doInBackground()
@Override
protected Boolean doInBackground(HashMap.SimpleImmutableEntry<Integer, File[]>... args) {
mTask = args [0].getKey ();
mFiles = args [0].getValue ();
// This calls the method according to task
switch (mTask) {
case TASK_COPY:
return copy ();
case TASK_MOVE:
return move ();
...
}
}
Мой onProgressUpdate()
(где я обновляю представления, он часто вызывается при вызове publishProgress()
)
@Override
protected void onProgressUpdate (Object[] values) {
...
// THIS IS WHERE I UPDATE VALUES OF PROGRESS BAR IN PERCENTAGE
// instance fields
// private AtomicLong mProgress, mLimit
double i = mProgress.get (), j = mLimit.get ();
int k = ((int) (j < 1 ? 0 : (i / j) * 100));
// THIS mTextView updates properly immediately
mTextView.setText (mTaskMsg k "%tt" mProgress.get () "/" mLimit.get ());
// but this progress bar does update until task is fully done (that is to 100) unless i sleep(1)
mProgressBar.setProgress (k, true);
}
Другие методы вызываются из потока asynctask…
// implemented FileVisitor
@Override
public FileVisitResult visitFile (Path path, BasicFileAttributes attrs) {
mProgress.incrementAndGet ();
publishProgress ();
// THIS IS WHERE I AM FORCED TO SLEEP TO ALLOW PROGRESS UPDATE IN MAIN THREAD
try {
Thread.sleep(1); // NOT REALLY THE BEST I KNOW...
Files.delete (path); }
catch (Throwable t) {
publishProgress (ERROR_CODE, t); }
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed (Path path, IOException io) {
mProgress.incrementAndGet ();
publishProgress (ERROR_CODE, io);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory (Path path, IOException io) {
mProgress.incrementAndGet ();
publishProgress ();
try {
Files.delete (path); }
catch (Throwable t) {
publishProgress (ERROR_CODE, t); }
return FileVisitResult.CONTINUE;
}
...
private boolean delete () {
publishProgress ();
try {
if (mFiles [0].isDirectory ()) {
Stream<Path> s = Files.walk (mFiles [0].toPath ());
// I count the files here myself because the count method
// of the stream crashes if files are 3000 the app with no exception...i caught Throwable.
// Though its not the issue...
s.forEach (this);
publishProgress ();
Files.walkFileTree (mFiles [0].toPath (), this);
}
else {
mLimit.incrementAndGet ();
mProgress.incrementAndGet ();
publishProgress ();
return mFiles [0].delete ();
}
}
catch (Throwable t) {
publishProgress (ERROR_CODE, t); }
return false;
}