在Android上同时运行多个异步任务
我正在努力允许我的用户在我的Android应用程序中进行调查。调查是在my rails服务器中创建的,调查的选择将发布回rails服务器 到目前为止,对于单选问题来说效果很好——用户的选择被存储并发送到服务器。问题在于多选题——我想我可以循环检查每个复选框,如果选中了该复选框,则通过我用于单选题的AsyncTask将该选项发送到服务器。然而,这似乎只是执行第一次发送的第一个选择 根据其他一些SO帖子,我发现Android似乎在允许异步任务并行运行和不允许异步任务并行运行之间来回切换。有人对如何处理这个问题有建议吗?我想支持回到API 10。提前谢谢 下面是我调用AsyncTask的方式:在Android上同时运行多个异步任务,android,ruby-on-rails,android-asynctask,Android,Ruby On Rails,Android Asynctask,我正在努力允许我的用户在我的Android应用程序中进行调查。调查是在my rails服务器中创建的,调查的选择将发布回rails服务器 到目前为止,对于单选问题来说效果很好——用户的选择被存储并发送到服务器。问题在于多选题——我想我可以循环检查每个复选框,如果选中了该复选框,则通过我用于单选题的AsyncTask将该选项发送到服务器。然而,这似乎只是执行第一次发送的第一个选择 根据其他一些SO帖子,我发现Android似乎在允许异步任务并行运行和不允许异步任务并行运行之间来回切换。有人对如何处
private void sendChoice() {
mQuestionId = mQuestion.getId();
if (mRadioGroupAnswers != null) {
mAnswerId = mRadioGroupAnswers.getCheckedRadioButtonId();
new ChoicePosted().execute();
}
if (mAnswerHolder.getChildCount() > 0) {
for (int i = 0; i < mAnswerHolder.getChildCount(); i++) {
CheckBox selected = (CheckBox) mAnswerHolder.getChildAt(i);
if (selected.isChecked()) {
mAnswerId = selected.getId();
new ChoicePosted().execute();
}
}
}
}
private class ChoicePosted extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
Log.i(TAG, "ChoicePosted");
boolean choicePosted = false;
try {
choicePosted = new SurveyMe().postChoice(
"8d707d9fa2b279f381eb416f1be887c0", mQuestionId,
mAnswerId);
} catch (Exception e) {
// TODO Auto-generated catch block
Log.e(TAG, "Errors: " + e);
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
Toast.makeText(getActivity(), "It worked!", Toast.LENGTH_SHORT)
.show();
}
}
private void sendChoice(){
mQuestionId=mQuestion.getId();
if(mRadioGroupAnswers!=null){
mAnswerId=mRadioGroupAnswers.getCheckedRadioButtonId();
新建ChoicePosted().execute();
}
if(mAnswerHolder.getChildCount()>0){
对于(int i=0;i
传递答案值列表可能是一个更好的选择,而不是依赖AsyncTask
读取mAnswerId
变量,该变量可以通过sendschoices()
方法根据执行顺序进行更改
尝试为您的ChoicePosted AsyncTask
创建一个构造函数,该构造函数接受一个List
参数,该参数用于迭代要发送的答案Id,因此迭代将在AsyncTask
中执行,而不是生成多个AsyncTasks
(另一个选项可以是通过单个字符串
发送到异步任务
。只要mAnswerId
在所选的异步任务使用时不保持全局和可编辑状态,您就可以了
向ChoicePosted
添加构造函数的示例,该构造函数将列表
中的字符串
作为答案发送:
private class ChoicePosted extends AsyncTask<Void, Void, Void> {
List<String> mAnswersToPost;
public ChoicePosted(List<String> strings){
mAnswersToPost = strings;
}
protected Void doInBackground(Void... params) {
for (String answer : mAnswersToPost){
new SurveyMe().postChoice(
"8d707d9fa2b279f381eb416f1be887c0", mQuestionId,
answer);
}
return null;
}
}
因此,您的AsyncTask
和sendschoices()
方法决不会使用相同的mAnswerId
变量,而是保留自己的副本,这些副本不会被无意中更改
然后,您应该能够从类中删除mAnswerId
,当然您需要考虑第一次调用new ChoicePosted()
(我可以看到您两次调用它)
当然,在这种方法中,AsyncTask
只运行一次,您可以调整为获取字符串(或使用AsyncTask
参数。目前您将它们都设置为Void
,但它们可以用于将参数直接传递到doInBackground
方法并作为返回类型)
要更深入地了解AsyncTask
,您可以阅读这篇Android开发者文章。下面的代码将演示如何在Android中同时运行多个异步任务
包com.vit.test.asynctask;
导入java.util.concurrent.AtomicInteger;
导入android.app.Activity;
导入android.os.AsyncTask;
导入android.os.Bundle;
导入android.os.SystemClock;
导入android.util.Log;
导入android.view.Gravity;
导入android.view.view;
导入android.widget.CheckBox;
导入android.widget.EditText;
导入android.widget.Toast;
/*
*免责声明:此代码是作为快速原型创建的。
*请不要在生产中使用它,因为它既不能处理
*设备配置更改或活动生命周期更改。
*/
公共类MainActivity扩展了活动{
//批处理中要运行的任务数
私有EditText numberOfTasksEditText;
//单个任务的有效负载作业的持续时间
私有EditText singleTaskDurationEditText;
//在两种不同模式之间切换(有/没有并行执行)
私有复选框启用并行执行复选框;
//每个任务一进入其doInBackground()就会增加此计数
//这样就可以跟踪任务执行的顺序
私有原子整数执行任务;
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
numberOfTasksEditText=(EditText)findviewbyd(R.id.tasks\u编号);
singleTaskDurationEditText=(EditText)findViewById(R.id.task\u payload\u duration);
enableParallelExecutionCheckbox=(复选框)findViewById(R.id.enable\u parallel\u execution);
}
单击开始测试时的公共无效(视图v){
if (mAnswerHolder.getChildCount() > 0) {
List<String> answerList = new ArrayList<String>();
for (int i = 0; i < mAnswerHolder.getChildCount(); i++) {
CheckBox selected = (CheckBox) mAnswerHolder.getChildAt(i);
if (selected.isChecked()) {
answerList.add(selected.getId());
}
}
new ChoicePosted(answerList).execute();
}
Below code will demonstrtate how to run multiple async task simultaneously in android
package com.vit.test.asynctask;
import java.util.concurrent.atomic.AtomicInteger;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
/*
* Disclaimer: this code is created as a quick prototype.
* Please don't use it in production, because it neither handles
* device configuration changes nor the Activity lifecycle changes.
*/
public class MainActivity extends Activity {
// the number of tasks to be run in a batch
private EditText numberOfTasksEditText;
// the duration of payload job for a single task
private EditText singleTaskDurationEditText;
// switches between 2 different modes (with/without parallel execution)
private CheckBox enableParallelExecutionCheckbox;
// each task increments this count as soon as it enters its doInBackground()
// so this allows to track the order of tasks execution
private AtomicInteger executedTasksCount;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
numberOfTasksEditText = (EditText) findViewById(R.id.tasks_number);
singleTaskDurationEditText = (EditText) findViewById(R.id.task_payload_duration);
enableParallelExecutionCheckbox = (CheckBox) findViewById(R.id.enable_parallel_execution);
}
public void onStartTestClicked(View v) {
executedTasksCount = new AtomicInteger(0); // reset this count
final int numberOfTasks = getIntFromTextView(numberOfTasksEditText);
final int taskDuration = getIntFromTextView(singleTaskDurationEditText);
log("number of tasks to run = " + numberOfTasks);
log("task payload duration = " + taskDuration + " ms");
final boolean useParallelExecution = enableParallelExecutionCheckbox.isChecked();
log("use parallel execution = " + useParallelExecution);
Toast toast = Toast.makeText(this, "Please watch the LogCat output", Toast.LENGTH_SHORT);
toast.setGravity((Gravity.CENTER_HORIZONTAL | Gravity.TOP), toast.getXOffset(), toast.getYOffset());
toast.show();
for (int i = 0; i < numberOfTasks; i++)
{
int taskId = i + 1;
startTask(taskId, taskDuration, useParallelExecution);
}
}
private void startTask(int taskId, int taskDuration, boolean useParallelExecution) {
TestTask task = new TestTask(taskId, taskDuration);
if (useParallelExecution) {
// this type of executor uses the following params:
//
// private static final int CORE_POOL_SIZE = 5;
// private static final int MAXIMUM_POOL_SIZE = 128;
// private static final int KEEP_ALIVE = 1;
//
// private static final ThreadFactory sThreadFactory = new ThreadFactory() {
// private final AtomicInteger mCount = new AtomicInteger(1);
//
// public Thread newThread(Runnable r) {
// return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
// }
// };
//
// private static final BlockingQueue<Runnable> sPoolWorkQueue =
// new LinkedBlockingQueue<Runnable>(10);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
// this is the same as calling task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
task.execute();
}
}
private int getIntFromTextView(EditText v) {
int result = 0;
try {
result = Integer.parseInt(v.getText().toString());
} catch (NumberFormatException ignored) {}
return result;
}
private void log(String msg) {
Log.d("MainActivity", msg);
}
private class TestTask extends AsyncTask<Void, Void, Void> /* Params, Progress, Result */ {
private final int id;
private final int duration;
TestTask(int id, int duration) {
this.id = id;
this.duration = duration;
}
@Override
protected Void doInBackground(Void... params) {
int taskExecutionNumber = executedTasksCount.incrementAndGet();
log("doInBackground: entered, taskExecutionNumber = " + taskExecutionNumber);
SystemClock.sleep(duration); // emulates some job
log("doInBackground: is about to finish, taskExecutionNumber = " + taskExecutionNumber);
return null;
}
private void log(String msg) {
Log.d("TestTask #" + id, msg);
}
}
}
//----place this layout code in xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Number of tasks:" />
<EditText
android:id="@+id/tasks_number"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:hint="0"
android:text="1"
android:maxLength="4" />
<View
android:layout_width="fill_parent"
android:layout_height="10dp" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Task payload duration (ms):" />
<EditText
android:id="@+id/task_payload_duration"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:hint="0"
android:text="1"
android:maxLength="5" />
<View
android:layout_width="fill_parent"
android:layout_height="10dp" />
<CheckBox
android:id="@+id/enable_parallel_execution"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Execute tasks in parallel" />
<View
android:layout_width="fill_parent"
android:layout_height="10dp" />
<Button
android:onClick="onStartTestClicked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Start Test" />
</LinearLayout>
</ScrollView>