Correctly parallelize AsyncTask threading on Honeycomb and beyond

git-svn-id: https://zxing.googlecode.com/svn/trunk@2381 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2012-08-07 09:21:12 +00:00
parent 5ec54ac140
commit 3e2b52fa38
15 changed files with 208 additions and 38 deletions

View file

@ -10,7 +10,7 @@
# be complete or up to date. (The "arithmetic" optimization can be
# used if you are only targeting Android 2.0 or later.) Make sure you
# test thoroughly if you go this route.
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
-optimizations !code/simplification/cast,!field/*,!class/merging/*
-optimizationpasses 5
-allowaccessmodification
-dontpreverify
@ -28,7 +28,8 @@
-keep public class com.android.vending.licensing.ILicensingService
# ADDED
-keep class com.google.zxing.client.android.**
-keep class com.srowen.bs.android.camera.open.**
-keep class com.srowen.bs.android.common.executor.**
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {

View file

@ -11,4 +11,4 @@
proguard.config=proguard-android-optimize.txt
# Project target.
target=android-10
target=android-15

View file

@ -25,6 +25,9 @@ import android.os.AsyncTask;
import android.os.BatteryManager;
import android.util.Log;
import com.google.zxing.client.android.common.executor.AsyncTaskExecInterface;
import com.google.zxing.client.android.common.executor.AsyncTaskExecManager;
/**
* Finishes an activity after a period of inactivity if the device is on battery power.
*/
@ -35,11 +38,13 @@ final class InactivityTimer {
private static final long INACTIVITY_DELAY_MS = 5 * 60 * 1000L;
private final Activity activity;
private final AsyncTaskExecInterface taskExec;
private final BroadcastReceiver powerStatusReceiver;
private InactivityAsyncTask inactivityTask;
InactivityTimer(Activity activity) {
this.activity = activity;
taskExec = new AsyncTaskExecManager().build();
powerStatusReceiver = new PowerStatusReceiver();
onActivity();
}
@ -47,7 +52,7 @@ final class InactivityTimer {
synchronized void onActivity() {
cancel();
inactivityTask = new InactivityAsyncTask();
inactivityTask.execute();
taskExec.execute(inactivityTask);
}
public void onPause() {
@ -87,9 +92,9 @@ final class InactivityTimer {
}
}
private final class InactivityAsyncTask extends AsyncTask<Void,Void,Void> {
private final class InactivityAsyncTask extends AsyncTask<Object,Object,Object> {
@Override
protected Void doInBackground(Void... objects) {
protected Object doInBackground(Object... objects) {
try {
Thread.sleep(INACTIVITY_DELAY_MS);
Log.i(TAG, "Finishing activity due to inactivity");

View file

@ -30,7 +30,7 @@ import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import com.google.zxing.client.android.HttpHelper;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@ -40,9 +40,12 @@ import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import com.google.zxing.client.android.Intents;
import com.google.zxing.client.android.HttpHelper;
import com.google.zxing.client.android.LocaleManager;
import com.google.zxing.client.android.R;
import com.google.zxing.client.android.Intents;
import com.google.zxing.client.android.common.executor.AsyncTaskExecInterface;
import com.google.zxing.client.android.common.executor.AsyncTaskExecManager;
/**
* Uses Google Book Search to find a word or phrase in the requested book.
@ -64,6 +67,12 @@ public final class SearchBookContentsActivity extends Activity {
private Button queryButton;
private ListView resultListView;
private TextView headerView;
private NetworkTask networkTask;
private final AsyncTaskExecInterface taskExec;
public SearchBookContentsActivity() {
taskExec = new AsyncTaskExecManager().build();
}
private final Button.OnClickListener buttonListener = new Button.OnClickListener() {
@Override
@ -134,11 +143,25 @@ public final class SearchBookContentsActivity extends Activity {
queryTextView.selectAll();
}
@Override
protected void onPause() {
NetworkTask oldTask = networkTask;
if (oldTask != null) {
oldTask.cancel(true);
networkTask = null;
}
super.onPause();
}
private void launchSearch() {
String query = queryTextView.getText().toString();
if (query != null && query.length() > 0) {
NetworkTask networkTask = new NetworkTask();
networkTask.execute(query, isbn);
NetworkTask oldTask = networkTask;
if (oldTask != null) {
oldTask.cancel(true);
}
networkTask = new NetworkTask();
taskExec.execute(networkTask, query, isbn);
headerView.setText(R.string.msg_sbc_searching_book);
resultListView.setAdapter(null);
queryTextView.setEnabled(false);

View file

@ -22,11 +22,14 @@ import android.hardware.Camera;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.util.Log;
import com.google.zxing.client.android.PreferencesActivity;
import java.util.ArrayList;
import java.util.Collection;
import com.google.zxing.client.android.PreferencesActivity;
import com.google.zxing.client.android.common.executor.AsyncTaskExecInterface;
import com.google.zxing.client.android.common.executor.AsyncTaskExecManager;
final class AutoFocusManager implements Camera.AutoFocusCallback {
private static final String TAG = AutoFocusManager.class.getSimpleName();
@ -43,9 +46,11 @@ final class AutoFocusManager implements Camera.AutoFocusCallback {
private final boolean useAutoFocus;
private final Camera camera;
private AutoFocusTask outstandingTask;
private final AsyncTaskExecInterface taskExec;
AutoFocusManager(Context context, Camera camera) {
this.camera = camera;
taskExec = new AsyncTaskExecManager().build();
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
String currentFocusMode = camera.getParameters().getFocusMode();
useAutoFocus =
@ -59,7 +64,7 @@ final class AutoFocusManager implements Camera.AutoFocusCallback {
public synchronized void onAutoFocus(boolean success, Camera theCamera) {
if (active) {
outstandingTask = new AutoFocusTask();
outstandingTask.execute();
taskExec.execute(outstandingTask);
}
}
@ -91,9 +96,9 @@ final class AutoFocusManager implements Camera.AutoFocusCallback {
active = false;
}
private final class AutoFocusTask extends AsyncTask<Void,Void,Void> {
private final class AutoFocusTask extends AsyncTask<Object,Object,Object> {
@Override
protected Void doInBackground(Void... voids) {
protected Object doInBackground(Object... voids) {
try {
Thread.sleep(AUTO_FOCUS_INTERVAL_MS);
} catch (InterruptedException e) {

View file

@ -0,0 +1,25 @@
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.common.executor;
import android.os.AsyncTask;
public interface AsyncTaskExecInterface {
<T> void execute(AsyncTask<T,?,?> task, T... args);
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.common.executor;
import com.google.zxing.client.android.common.PlatformSupportManager;
public final class AsyncTaskExecManager extends PlatformSupportManager<AsyncTaskExecInterface> {
public AsyncTaskExecManager() {
super(AsyncTaskExecInterface.class, new DefaultAsyncTaskExecInterface());
addImplementationClass(11, "com.google.zxing.client.android.common.executor.HoneycombAsyncTaskExecInterface");
}
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.common.executor;
import android.os.AsyncTask;
/**
* Before Honeycomb, {@link AsyncTask} uses parallel execution by default, which is desired. Good thing
* too since there is no API to request otherwise.
*/
public final class DefaultAsyncTaskExecInterface implements AsyncTaskExecInterface {
@Override
public <T> void execute(AsyncTask<T,?,?> task, T... args) {
task.execute();
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android.common.executor;
import android.annotation.TargetApi;
import android.os.AsyncTask;
/**
* On Honeycomb and later, {@link AsyncTask} returns to serial execution by default which is undesirable.
* This calls Honeycomb-only APIs to request parallel execution.
*/
@TargetApi(11)
public final class HoneycombAsyncTaskExecInterface implements AsyncTaskExecInterface {
@Override
public <T> void execute(AsyncTask<T,?,?> task, T... args) {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, args);
}
}

View file

@ -19,8 +19,11 @@ package com.google.zxing.client.android.result;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.widget.Toast;
import com.google.zxing.client.android.CaptureActivity;
import com.google.zxing.client.android.R;
import com.google.zxing.client.android.common.executor.AsyncTaskExecInterface;
import com.google.zxing.client.android.common.executor.AsyncTaskExecManager;
import com.google.zxing.client.android.wifi.WifiConfigManager;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.WifiParsedResult;
@ -34,10 +37,12 @@ import com.google.zxing.client.result.WifiParsedResult;
public final class WifiResultHandler extends ResultHandler {
private final CaptureActivity parent;
private final AsyncTaskExecInterface taskExec;
public WifiResultHandler(CaptureActivity activity, ParsedResult result) {
super(activity, result);
parent = activity;
taskExec = new AsyncTaskExecManager().build();
}
@Override
@ -57,7 +62,7 @@ public final class WifiResultHandler extends ResultHandler {
WifiParsedResult wifiResult = (WifiParsedResult) getResult();
WifiManager wifiManager = (WifiManager) getActivity().getSystemService(Context.WIFI_SERVICE);
Toast.makeText(getActivity(), R.string.wifi_changing_network, Toast.LENGTH_LONG).show();
new WifiConfigManager(wifiManager).execute(wifiResult);
taskExec.execute(new WifiConfigManager(wifiManager), wifiResult);
parent.restartPreviewAfterDelay(0L);
}
}

View file

@ -17,7 +17,6 @@
package com.google.zxing.client.android.result.supplement;
import android.content.Context;
import android.nfc.Tag;
import android.os.AsyncTask;
import android.text.Spannable;
import android.text.SpannableString;
@ -26,18 +25,21 @@ import android.text.method.LinkMovementMethod;
import android.text.style.URLSpan;
import android.util.Log;
import android.widget.TextView;
import com.google.zxing.client.result.ISBNParsedResult;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ProductParsedResult;
import com.google.zxing.client.result.URIParsedResult;
import com.google.zxing.client.android.history.HistoryManager;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
public abstract class SupplementalInfoRetriever extends AsyncTask<Void,Void,Void> {
import com.google.zxing.client.android.common.executor.AsyncTaskExecInterface;
import com.google.zxing.client.android.common.executor.AsyncTaskExecManager;
import com.google.zxing.client.android.history.HistoryManager;
import com.google.zxing.client.result.ISBNParsedResult;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ProductParsedResult;
import com.google.zxing.client.result.URIParsedResult;
public abstract class SupplementalInfoRetriever extends AsyncTask<Object,Object,Object> {
private static final String TAG = "SupplementalInfo";
@ -45,15 +47,16 @@ public abstract class SupplementalInfoRetriever extends AsyncTask<Void,Void,Void
ParsedResult result,
HistoryManager historyManager,
Context context) {
AsyncTaskExecInterface taskExec = new AsyncTaskExecManager().build();
if (result instanceof URIParsedResult) {
new URIResultInfoRetriever(textView, (URIParsedResult) result, historyManager, context).execute();
taskExec.execute(new URIResultInfoRetriever(textView, (URIParsedResult) result, historyManager, context));
} else if (result instanceof ProductParsedResult) {
String productID = ((ProductParsedResult) result).getProductID();
new ProductResultInfoRetriever(textView, productID, historyManager, context).execute();
taskExec.execute(new ProductResultInfoRetriever(textView, productID, historyManager, context));
} else if (result instanceof ISBNParsedResult) {
String isbn = ((ISBNParsedResult) result).getISBN();
new ProductResultInfoRetriever(textView, isbn, historyManager, context).execute();
new BookResultInfoRetriever(textView, isbn, historyManager, context).execute();
taskExec.execute(new ProductResultInfoRetriever(textView, isbn, historyManager, context));
taskExec.execute(new BookResultInfoRetriever(textView, isbn, historyManager, context));
}
}
@ -70,7 +73,7 @@ public abstract class SupplementalInfoRetriever extends AsyncTask<Void,Void,Void
}
@Override
public final Void doInBackground(Void... args) {
public final Object doInBackground(Object... args) {
try {
retrieveSupplementalInfo();
} catch (IOException e) {
@ -80,7 +83,7 @@ public abstract class SupplementalInfoRetriever extends AsyncTask<Void,Void,Void
}
@Override
protected void onPostExecute(Void arg) {
protected void onPostExecute(Object arg) {
TextView textView = textViewRef.get();
if (textView != null) {
for (Spannable content : newContents) {

View file

@ -18,33 +18,42 @@ package com.google.zxing.client.android.share;
import android.app.ListActivity;
import android.content.Intent;
import android.os.AsyncTask;
import android.provider.Browser;
import android.view.View;
import android.widget.ListView;
import com.google.zxing.client.android.common.executor.AsyncTaskExecInterface;
import com.google.zxing.client.android.common.executor.AsyncTaskExecManager;
import java.util.ArrayList;
import java.util.List;
public final class AppPickerActivity extends ListActivity {
private final List<String[]> labelsPackages = new ArrayList<String[]>();
private final List<String[]> labelsPackages;
private LoadPackagesAsyncTask backgroundTask;
private final AsyncTaskExecInterface taskExec;
public AppPickerActivity() {
labelsPackages = new ArrayList<String[]>();
taskExec = new AsyncTaskExecManager().build();
}
@Override
protected void onResume() {
super.onResume();
labelsPackages.clear();
backgroundTask = new LoadPackagesAsyncTask(this);
backgroundTask.execute(labelsPackages);
taskExec.execute(backgroundTask, labelsPackages);
}
@Override
protected void onPause() {
if (backgroundTask.getStatus() != AsyncTask.Status.FINISHED) {
backgroundTask.cancel(true);
LoadPackagesAsyncTask task = backgroundTask;
if (task != null) {
task.cancel(true);
backgroundTask = null;
}
backgroundTask = null;
super.onPause();
}

View file

@ -33,7 +33,7 @@ import java.util.List;
*
* @author Sean Owen
*/
final class LoadPackagesAsyncTask extends AsyncTask<List<String[]>, Void, List<String[]>> {
final class LoadPackagesAsyncTask extends AsyncTask<List<String[]>,Object,List<String[]>> {
private static final String[] PKG_PREFIX_WHITELIST = {
"com.google.android.apps.",

View file

@ -30,7 +30,7 @@ import com.google.zxing.client.result.WifiParsedResult;
* @author Vikram Aggarwal
* @author Sean Owen
*/
public final class WifiConfigManager extends AsyncTask<WifiParsedResult,Void,Void> {
public final class WifiConfigManager extends AsyncTask<WifiParsedResult,Object,Object> {
private static final String TAG = WifiConfigManager.class.getSimpleName();
@ -43,7 +43,7 @@ public final class WifiConfigManager extends AsyncTask<WifiParsedResult,Void,Voi
}
@Override
protected Void doInBackground(WifiParsedResult... args) {
protected Object doInBackground(WifiParsedResult... args) {
WifiParsedResult theWifiResult = args[0];
// Start WiFi, otherwise nothing will work
if (!wifiManager.isWifiEnabled()) {

View file

@ -8,5 +8,5 @@
# project structure.
# Project target.
target=android-10
target=android-15
proguard.config=proguard.cfg