为何AsyncTask运行在主线程?Android界面阻塞问题求助
Hey there, let's break down what's going wrong here and fix your issue step by step.
Core Problem Analysis
The blank screen issue you're facing stems from two critical mistakes:
- UI operations in background thread: You're calling
recyclerview.setAdapter()directly insidedoInBackground()—Android strictly prohibits modifying UI components from non-main threads. This blocks the UI until the background task finishes, resulting in the delayed display. - Adapter variable assignment error: Your
ItemAdapterconstructor usesgalleryItems = galleryItems, which only assigns the local parameter to itself instead of the adapter's member variable. This leads togetItemCount()returning 0, so the list never shows up.
Additionally, loading Bitmaps directly in onBindViewHolder() with BitmapFactory.decodeFile() is a hidden issue—it runs time-consuming IO operations on the main thread, causing list scroll lag. Let's fix the blank screen first, then touch on this optimization.
Fixed Code Implementation
We'll restructure the AsyncTask to handle only background data fetching, move UI updates to the main thread, and fix the adapter's bugs:
1. Adjust AsyncTask Logic & Generics
Change the AsyncTask's return type to List<GalleryItem> so doInBackground() focuses solely on data retrieval, while onPostExecute() handles UI updates:
private class ListTask extends AsyncTask<Void, Void, List<GalleryItem>> { @Override protected List<GalleryItem> doInBackground(Void... voids) { // Only handle background data fetching here, no UI operations return getInternalFileList(); } @Override protected void onPostExecute(List<GalleryItem> galleryItems) { super.onPostExecute(galleryItems); // Update UI on main thread recyclerview.setAdapter(new ItemAdapter(galleryItems)); // Hide progress bar after task completes progressbar.setVisibility(View.GONE); } }
2. Fix ItemAdapter Constructor & Variable Issues
Correct the variable name mismatch and constructor assignment error:
private class ItemAdapter extends RecyclerView.Adapter<ItemHolder> { private List<GalleryItem> galleryItems; ItemAdapter(List<GalleryItem> galleryItems) { // Use 'this' to distinguish member variable from local parameter this.galleryItems = galleryItems; } @NonNull @Override public ItemHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) { LayoutInflater inflater = LayoutInflater.from(getActivity()); View v = inflater.inflate(R.layout.gallery_item, viewGroup, false); return new ItemHolder(v); } @Override public void onBindViewHolder(@NonNull ItemHolder itemHolder, int position) { GalleryItem galleryItem = galleryItems.get(position); // Fix variable case mismatch String path = getActivity().getFilesDir() + "/" + galleryItem.getID(); File file = new File(path); // Recommend async Bitmap loading here (e.g., AsyncTask/Glide) to avoid main thread lag Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); itemHolder.bindBackgroundImage(bitmap); itemHolder.bindImageViewer(path); } @Override public int getItemCount() { // Null check to avoid NullPointerException return galleryItems != null ? galleryItems.size() : 0; } }
3. Launch the Task Correctly
In your Activity/Fragment's onCreate() or onViewCreated(), show the progress bar first, then start the background task:
// Show progress bar before starting task progressbar.setVisibility(View.VISIBLE); // Launch the background task new ListTask().execute();
Extra Optimization Tips
- Async Bitmap Loading:
BitmapFactory.decodeFile()is a slow operation. Move this to an AsyncTask or use an image loading library like Glide to load Bitmaps off the main thread—this will eliminate list scroll stutter. - Replace AsyncTask: AsyncTask is deprecated. For new code, consider using Kotlin Coroutines or
ExecutorServicewithHandlerfor background task management, but the above fixes will resolve your immediate issue.
After these changes, your screen will show the progress bar first, then load the list once the background task finishes—no more blank waiting.
内容的提问来源于stack exchange,提问作者newbieandroid

