如何将Android端Socket传图片代码改写为AsyncTask?
Hey there! I totally get why you're stuck—moving network/file operations off the main thread with AsyncTask can feel tricky at first, especially when you're used to putting everything in the click listener. Let's fix your code step by step, replacing that main-thread socket logic with a proper AsyncTask to keep your app responsive.
First, the big issue with your original code is that all the socket and file I/O runs on the main UI thread when you tap the send button. That's a no-no on Android—it'll cause your app to freeze, and might even trigger an ANR (Application Not Responding) error. AsyncTask lets us run those heavy operations in a background thread, while still updating the UI safely when we're done.
Here's your rewritten SendfileActivity with AsyncTask integrated:
public class SendfileActivity extends Activity { private static final int SELECT_PICTURE = 1; private String selectedImagePath; private ImageView img; private TextView status; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); img = (ImageView) findViewById(R.id.ivPic); status = (TextView) findViewById(R.id.tvStatus); // Browse button logic remains mostly the same ((Button) findViewById(R.id.bBrowse)).setOnClickListener(new OnClickListener() { public void onClick(View arg0) { Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult( Intent.createChooser(intent, "Select Picture"), SELECT_PICTURE); } }); // Send button now triggers the AsyncTask instead of running logic directly Button send = (Button) findViewById(R.id.bSend); send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { if (selectedImagePath == null || selectedImagePath.isEmpty()) { status.setText("Please select an image first!"); return; } // Execute the AsyncTask with the selected image path new SendImageTask().execute(selectedImagePath); } }); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // Don't forget this! if (resultCode == RESULT_OK) { if (requestCode == SELECT_PICTURE) { Uri selectedImageUri = data.getData(); selectedImagePath = getPath(selectedImageUri); TextView path = (TextView) findViewById(R.id.tvPath); path.setText("Image Path : " + selectedImagePath); img.setImageURI(selectedImageUri); } } } public String getPath(Uri uri) { String[] projection = { MediaStore.Images.Media.DATA }; Cursor cursor = managedQuery(uri, projection, null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); return cursor.getString(column_index); } // Our AsyncTask to handle image sending in the background private class SendImageTask extends AsyncTask<String, Void, Boolean> { @Override protected void onPreExecute() { super.onPreExecute(); // Update UI before starting the background task status.setText("Connecting..."); } @Override protected Boolean doInBackground(String... params) { String imagePath = params[0]; Socket sock = null; try { // Connect to PC server (make sure IP/port matches your Java PC app!) sock = new Socket("192.168.0.3", 27015); File myFile = new File(imagePath); byte[] mybytearray = new byte[(int) myFile.length()]; FileInputStream fis = new FileInputStream(myFile); BufferedInputStream bis = new BufferedInputStream(fis); bis.read(mybytearray, 0, mybytearray.length); OutputStream os = sock.getOutputStream(); os.write(mybytearray, 0, mybytearray.length); os.flush(); return true; // Return success } catch (UnknownHostException e) { e.printStackTrace(); return false; } catch (IOException e) { e.printStackTrace(); return false; } finally { // Always close the socket to avoid leaks if (sock != null) { try { sock.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Override protected void onPostExecute(Boolean success) { super.onPostExecute(success); // Update UI after background task finishes if (success) { status.setText("Image sent successfully!"); } else { status.setText("Failed to send image. Check connection!"); } } } }
Key Changes Explained:
- Extracted Status TextView: Made
statusa class-level variable so the AsyncTask can update it safely without extra hoops. - Send Button Guard Check: Now verifies an image is selected before attempting to send, with a friendly error message if not.
- AsyncTask Breakdown:
onPreExecute(): Runs on the main thread to set a "Connecting..." status before the heavy work starts.doInBackground(String... params): All socket and file operations live here (in a background thread). It takes the image path as input and returns a boolean to signal success/failure.onPostExecute(Boolean success): Runs back on the main thread to update the UI with the final result—success or error message.
- Socket Cleanup: Added a
finallyblock to ensure the socket is always closed, even if an error occurs mid-send. - Fixed
onActivityResult: Added the mandatorysupercall to ensure the parent class handles result processing correctly.
Important Notes:
- Permissions: Make sure you have these in your
AndroidManifest.xml:<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Required for older Android versions --> - PC Server Sync: Double-check that your Java PC server is running and listening on
192.168.0.3:27015, and both devices are on the same local network. - Enhanced Error Handling: You could expand the error messages to be more specific (e.g., "Unknown host" vs "Connection refused") if you want to give users clearer feedback.
内容的提问来源于stack exchange,提问作者matarda

