Ответ 1
Просто создайте другой экземпляр и выполните его.
У меня запускается asyncTask при первом запуске, тогда, если сетевое подключение недоступно, у меня есть кнопка обновления, которая пытается запустить asyncTask, чтобы повторить попытку. Но я получаю ошибку отладки, говоря об этом.
07-29 18:14:21.290: ERROR/AndroidRuntime(9080): FATAL EXCEPTION: main
07-29 18:14:21.290: ERROR/AndroidRuntime(9080): java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)
07-29 18:14:21.290: ERROR/AndroidRuntime(9080): at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:541)
07-29 18:14:21.290: ERROR/AndroidRuntime(9080): at android.os.AsyncTask.execute(AsyncTask.java:499)
07-29 18:14:21.290: ERROR/AndroidRuntime(9080): at com.fttech.gameIT.MainMenu$1.onClick(MainMenu.java:90)
Можно ли запустить это дважды?
Просто создайте другой экземпляр и выполните его.
Как и потоки, AsyncTask
нельзя использовать повторно. Вы должны создать новый экземпляр каждый раз, когда хотите его запустить.
Вы никогда не сможете выполнить поток снова, а не в Java
, а не на каком-либо другом языке, как только поток выполняется с помощью метода run()
, его нельзя перезапустить, поэтому вы получаете IllegalStateException
,
Однако вы все равно можете вызвать методы в этом потоке, но они будут выполняться в потоке, который вызывает их NOT в другом потоке. Поэтому вам нужно будет создать новый.
Вы не можете запускать один и тот же экземпляр AsyncTask более одного раза. Предположим, у вас есть AsyncTask с именем MyAsyncTaks, и вы намерены сделать что-то вроде этого,
MyAsyncTask myAsyncTask = new MyAsyncTaks();
myAsyncTask.execute(); // Works as expected
.
.
.
.
myAsyncTask.execute(); // This will throw you exception
Причиной этого является то, что нить, однажды закончившая свой метод "run", не может быть назначена другой задаче. Здесь, при первом вызове execute(), ваш AsyncTask начал работать и после выполнения своей работы поток выходит из строя. Естественно, что следующий вызов execute() вызовет вам исключение.
Самый простой способ запускать это более одного раза - создать новый экземпляр MyAsyncTaks и выполнить его выполнение.
MyAsyncTask myAsyncTask = new MyAsyncTaks();
myAsyncTask.execute(); // Works as expected
.
.
.
MyAsyncTask myAsyncTask2 = new MyAsyncTaks();
myAsyncTask2.execute(); // Works as expected
Хотя его не нужно упоминать здесь, нужно помнить, что после Android SDK версии Honeycomb, если вы запускаете сразу несколько Асинхронных задач, они фактически запускаются последовательно. Если вы хотите запустить их параллально, вместо этого используйте executeOnExecutor.
Просто создайте новый вызов, как новый asyncTask(). execute(); Вы должны создать новый объект для перезапуска этой задачи.
Я просто создаю asynctask, а затем создаю runnable, который создает новые экземпляры asynctask. Затем вы можете снова и снова пересылать ваш runnable в обработчик.
class MyAsyncTask extends AsyncTask<String, Void, String>{ ...}
Runnable myRunner = new Runnable(){
public void run() {
new MyAsyncTask ().execute(...);
}};
myHandler.post(myRunner);
Вы можете сделать это так:
private MyAsyncTask createAsyncTask(){
if (myAsyncTask == null){
return myAsyncTask = new MyAsyncTask();
}
myAsyncTask.cancel(true);
return myAsyncTask = new MyAsyncTask();
}
а затем вы можете использовать его:
createAsyncTask().execute();
это делает новый экземпляр вашей фоновой задачи каждый раз.
Я создал Arraylist типа ProgressUpdater (имя класса, который расширяет AsyncTask) и добавил в него экземпляры (в кнопке onClick). Таким образом, вы можете выполнять и отменять эту задачу при необходимости.
public class MainActivity extends Activity {
ProgressBar progress;
ProgressUpdater task;
ArrayList<ProgressUpdater> pu = new ArrayList<MainActivity.ProgressUpdater>();
int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progress = (ProgressBar) findViewById(R.id.progress);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn:
task = new ProgressUpdater();
pu.add(task);
count++;
pu.get(count - 1).execute(0);
System.out.println("task" + task);
// task.execute(10);
break;
case R.id.btnCancel:
if (count >= 0) {
pu.get(count - 1).cancel(true);
pu.remove(count - 1);
count--;
}
// task.cancel(true);
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class ProgressUpdater extends AsyncTask<Integer, Integer, Void> {
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
progress = (ProgressBar) findViewById(R.id.progress);
progress.setMax(100);
}
@Override
protected Void doInBackground(Integer... params) {
// TODO Auto-generated method stub
int start = params[0];
for (int i = start; i <= 100; i++) {
try {
boolean cancelled = isCancelled();
if (!cancelled) {
publishProgress(i);
SystemClock.sleep(100);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
Log.v("Progress", "Finished");
}
@Override
protected void onCancelled() {
// TODO Auto-generated method stub
super.onCancelled();
progress.setMax(0);
}
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
progress.setProgress(values[0]);
}
}
}
в вашем MainActivity вы можете сделать так:
LeoAsyncTask leoAsyncTaskGeneric;
public void onClick_AsyncTask(View view) {
LeoAsyncTask leoAsyncTaskInner = new LeoAsyncTask();
leoAsyncTaskInner.execute();
leoAsyncTaskGeneric=leoAsyncTaskInner;
}
/**, если вы создаете пространство в памяти вашего класса AsyncTask в качестве общего, тогда вы можете создать экземпляр того же класса в методе onClick, и там равны, поэтому каждый раз, когда вы нажимаете onClick, вы будете используя новый экземпляр класса AsyncTask, он не даст вам проблем */
Вы можете отменить асинхронную задачу, нажав кнопку и затем выполнить ее снова.
Внутри OnClic метод:
asyncTask.cancel();
AsyncTask asyncTask = new AsyncTask();
asyncTask.execute();
Это решило мою проблему:
public class MainActivity extends AnimationActivity {
MyAsyncTasks asyncTasks = new MyAsyncTasks();
@BindView(R.id.refresh_btn)
Button refreshBtn;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setUnbinder(ButterKnife.bind(this)); // ButterKnife usage
syncTasks(); // run asyncTasks on activity start
refreshBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
syncTasks(); // run asyncTasks on button click
}
});
}
private void syncTasks() {
try {
if (asyncTasks.getStatus() != AsyncTask.Status.RUNNING){ // check if asyncTasks is running
asyncTasks.cancel(true); // asyncTasks not running => cancel it
asyncTasks = new MyAsyncTasks(); // reset task
asyncTasks.execute(); // execute new task (the same task)
}
} catch (Exception e) {
e.printStackTrace();
Log.e("MainActivity_TSK", "Error: "+e.toString());
}
}
}
@coder_For_Life22 Я думаю, что опоздал на ответ, в любом случае вы можете сделать как
@Override
protected void onPostExecute(Void a) {
myAsyncTask=new MyAsyncTask();
}
для запуска новой AsyncTask после выполнения :)
Правила потоков
Для более подробной информации, пожалуйста, войдите в эту ссылку