Android开发:PlaceAutocompleteAdapter主线程外调用及AsyncTask实现咨询
Hey there! Let's sort out how to wrap that Google Places API call in an AsyncTask so you avoid that "must be called off main thread" error. I've been in your shoes before—getting that error when you're just starting out with Places API can be confusing, but this fix is straightforward.
First, let's break down the issue: the line in question (193) calls Places.GeoDataApi.getAutocompletePredictions(), which makes a network request. Network operations block the thread they're on, so Android forces us to run them off the main UI thread to keep the app responsive and prevent ANRs (Application Not Responding) crashes.
Here's how to modify your PlaceAutocompleteAdapter to use AsyncTask properly:
Step 1: Add an AsyncTask inner class to your Adapter
Inside your PlaceAutocompleteAdapter class, create a private inner AsyncTask that handles fetching predictions in the background. This task will take the search query as input, run the API call, and return the list of predictions to update the UI.
private class FetchPredictionsTask extends AsyncTask<CharSequence, Void, List<AutocompletePrediction>> { @Override protected List<AutocompletePrediction> doInBackground(CharSequence... params) { // Exit early if there's no search query if (params.length == 0 || params[0].length() == 0) { return null; } // Run the Places API call off the main thread PendingResult<AutocompletePredictionBuffer> results = Places.GeoDataApi.getAutocompletePredictions( mGoogleApiClient, params[0].toString(), mBounds, mPlaceFilter); // Wait for results with a timeout (adjust the 60-second value as needed) AutocompletePredictionBuffer buffer = results.await(60, TimeUnit.SECONDS); // Handle API errors com.google.android.gms.common.api.Status status = buffer.getStatus(); if (!status.isSuccess()) { buffer.release(); Log.e(TAG, "Error fetching predictions: " + status.toString()); return null; } // Convert the buffer to a usable list and release resources to avoid leaks return buffer.copyToList(new ArrayList<AutocompletePrediction>()); } @Override protected void onPostExecute(List<AutocompletePrediction> predictions) { // Update the adapter's data source and notify the UI to refresh mResultList = predictions; notifyDataSetChanged(); } }
Step 2: Modify filtering logic to use the AsyncTask
First, add a member variable to track the current running task—this prevents outdated predictions from popping up after the user types a new query:
private FetchPredictionsTask mCurrentTask;
Then update your performFiltering method (part of the Filterable interface) to cancel any existing tasks and start a new one:
@Override protected FilterResults performFiltering(CharSequence constraint) { // Cancel any ongoing task to avoid stale results if (mCurrentTask != null) { mCurrentTask.cancel(true); } // Start a new task to fetch predictions for the current query mCurrentTask = new FetchPredictionsTask(); mCurrentTask.execute(constraint); // Return an empty temporary result (the actual data will come via onPostExecute) FilterResults results = new FilterResults(); results.values = mResultList; results.count = mResultList != null ? mResultList.size() : 0; return results; }
Step 3: Clean up tasks to avoid memory leaks
Add a method to your adapter to cancel the task when it's no longer needed (like when the parent activity/fragment is destroyed):
public void cancelCurrentTask() { if (mCurrentTask != null) { mCurrentTask.cancel(true); mCurrentTask = null; } }
Then call this method from your activity's onDestroy() or fragment's onDestroyView():
@Override protected void onDestroy() { super.onDestroy(); if (mAutocompleteAdapter != null) { mAutocompleteAdapter.cancelCurrentTask(); } }
Key Tips to Remember:
- Always cancel previous tasks before starting a new one—this ensures the user sees predictions for their latest query, not an old one.
- Never forget to release the
AutocompletePredictionBufferafter copying results—this is critical to avoid memory leaks. - The
await()timeout prevents your app from hanging indefinitely if the API call takes too long.
That should eliminate the thread error and keep your place autocomplete feature running smoothly!
内容的提问来源于stack exchange,提问作者Matej Košút

