android - 多次运行相同的 AsyncTask

标签 android android-asynctask

我正在尝试创建一个 Messenger 应用程序,它可以在聊天室参与者之间共享一张照片,包括一个稍后要实现的图像编辑器。从服务器下载和上传到服务器的功能运行良好,但是当我尝试更新图像时,我得到一个 IllegalStateException,它说我不允许多次调用和 AsyncTask,这显然对我的目标。

所以我有我的 MainActivity:

package com.sixcoresecond.imageSync;

import io.socket.IOAcknowledge;
import io.socket.IOCallback;
import io.socket.SocketIO;
import io.socket.SocketIOException;

import java.io.File;

import javax.net.ssl.SSLContext;

import org.json.JSONObject;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

import com.sixcoresecond.helper.ImageDownloader;
import com.sixcoresecond.helper.ImageUploader;
import com.sixcoresecond.helper.Toaster;
import com.sixcoresecond.sketchmessenger.R;

public class ImageSyncActivity extends Activity {

    private static final int SELECT_PHOTO = 100;

    //URL for SocketIO
    private static final String COMMS_URL = "http://132.199.139.24:8998/";

    //URL for downloads
    private static final String DOWNLOAD_URL = "http://132.199.139.24/~krm22840/uploads/";

    //URL for uploads
    private static final String UPLOAD_URL = "http://132.199.139.24/~krm22840/upload.php";

    //Path for saving files
    private static String STORAGE_PATH = "";

    private static String CHAT_ID = "";

    //UI stuff
    private ImageView mainImageView;
    private Button submitButton;

    //Subclass objects
    private IOClient socketClient;

    private ImageDownloader downloader;
    private ImageUploader uploader;
    private Toaster toaster;

    //Private objects
    private Bitmap currentBitmap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.image_sync_layout);

        //Setup directory for all images
        setupDirectory();
        //Setup the UI
        initUI();

        //Assign Listener to all Buttons
        assignListener();

        //Set a default image to the ImageView if necessary
        setupDefaultImage();

        //Setting up a toaster, a downloader and an uploader
        toaster = new Toaster(this);
        downloader = new ImageDownloader(this, mainImageView);
        uploader = new ImageUploader(this);

        //Setting up a socketIO client and connecting it to the server
        try {
            socketClient = new IOClient(COMMS_URL);
        } catch (Exception e) {
            e.printStackTrace();
            Log.i("Debug", e.toString());
        }
    }

    @Override
    protected void onStart(){
        super.onStart();
        if(socketClient != null && CHAT_ID.equals("")){
            socketClient.send("NEW_ID_REQUEST", "");
        }else{
            toaster.popToast("No server-connection established. \nPlease try again later.");
        }
    }

    private void setupDirectory(){
        Log.i("Debug", "Setting up Directory...");
        if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            Log.i("Debug", "Directory Error: No SDCARD");
        }else{
            File directory = new File(Environment.getExternalStorageDirectory() + File.separator + "SketchMessenger");
            directory.mkdirs();
            STORAGE_PATH = directory.getAbsolutePath();
            Log.i("Debug", "Directory created/set to: " + STORAGE_PATH);
        }
    }

    private void initUI(){
        mainImageView = (ImageView)findViewById(R.id.syncImageView);
        submitButton = (Button)findViewById(R.id.syncSubmitButton);
    }

    private void assignListener(){
        mainImageView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                openImagePicker();
            }
        });

        submitButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                submitCurrentImage();
            }
        });
    }

    private void setupDefaultImage(){
        if((!CHAT_ID.equals(""))){
            File file = new File(STORAGE_PATH + "/" + CHAT_ID + ".png");
            if(!file.exists()){
                Log.i("Debug", "Setting up a default Image for the main view...");
                Drawable drawable = getResources().getDrawable(R.drawable.scribble_icon_white);
                currentBitmap = ((BitmapDrawable)drawable).getBitmap(); 
            }
        }
    }

    private void openImagePicker(){
        Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(intent, SELECT_PHOTO);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent){
        super.onActivityResult(requestCode, resultCode, imageReturnedIntent);

        switch(requestCode){
        case SELECT_PHOTO:
            if(resultCode == Activity.RESULT_OK){
                Uri selectedImage = imageReturnedIntent.getData();
                String[] filePathColumn = {MediaStore.Images.Media.DATA};

                Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
                cursor.moveToFirst();

                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                String filePath = cursor.getString(columnIndex);
                cursor.close();

                Bitmap mySelectedImage = BitmapFactory.decodeFile(filePath);
                if(mySelectedImage != null){
                    mainImageView.setImageBitmap(mySelectedImage);
                    currentBitmap = mySelectedImage;
                }
            }
        }
    }

    private void submitCurrentImage(){
        if(!CHAT_ID.equals("")){
            Log.i("Debug", "UploadUrl" + UPLOAD_URL + "\n" + "Path: " + STORAGE_PATH + "\n" + "ChatID: " + CHAT_ID);
            uploader.setup(UPLOAD_URL, mainImageView, STORAGE_PATH, CHAT_ID);
            uploader.execute(STORAGE_PATH, CHAT_ID);
        }else{
            toaster.popToast("No ID acquired. Connect to Server.");
        }
    }

    private void updateCurrentImage(){
        if(!CHAT_ID.equals("")){
            downloader.execute(DOWNLOAD_URL, CHAT_ID, STORAGE_PATH);
        }
    }

    public class IOClient implements IOCallback{

        private SocketIO socket;

        public IOClient(String url) throws Exception{
            SocketIO.setDefaultSSLSocketFactory(SSLContext.getDefault());
            socket = new SocketIO(url);
            socket.connect(this);
        }

        @Override
        public void on(String arg0, IOAcknowledge arg1, final Object... args) {
            if(arg0.equals("NEW_ID_REQUEST_ECHO")){
                String result = args[0].toString();
                CHAT_ID = result;
                downloader.execute(DOWNLOAD_URL, CHAT_ID, STORAGE_PATH);
            }
            else if(arg0.equals("NEW_CHAT_ECHO")){
                final String result = args[0].toString();
                CHAT_ID = result;
                submitCurrentImage();
            }
        }

        @Override
        public void onConnect() {
            Log.i("Debug", "onConnect");
        }

        @Override
        public void onDisconnect() {
            Log.i("Debug", "onDisconnect");
        }

        @Override
        public void onError(SocketIOException arg0) {
            Log.i("Debug", "on Error: " + arg0.getCause().toString());
        }

        @Override
        public void onMessage(String arg0, IOAcknowledge arg1) {
            Log.i("Debug", "onMessageString: " + arg0);
        }

        @Override
        public void onMessage(JSONObject arg0, IOAcknowledge arg1) {
            Log.i("Debug", "onMessageJSON: " + arg0.toString());
        }

        public void send(String tag, String msg){
            socket.emit(tag, msg);
        }

        public void disconnect(){
            socket.disconnect();
        }
    }

    @Override
    protected void onDestroy(){
        socketClient.disconnect();
        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch(item.getItemId()){
        case R.id.menu_update:
            updateCurrentImage();
            return true;
        default: 
            return super.onOptionsItemSelected(item);
        }
    }
}

然后是我的 Uploader 类:

package com.sixcoresecond.helper;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Looper;
import android.util.Log;
import android.widget.ImageView;

import com.sixcoresecond.imageSync.ImageSyncActivity.IOClient;

public class ImageUploader extends AsyncTask<String, Void, Integer> {

    private int serverResponseCode = 0;

    private String uploadURL;
    private ImageView imgView;
    private String filePath;
    private String chatID;

    private Toaster toaster;
    private Progressor progressor;

    private boolean fileCreated = true;

    public ImageUploader(Context context){
        toaster = new Toaster(context);
        progressor = new Progressor(context);
        uploadURL = "";
        imgView = null;
        filePath = "";
        chatID = "";
    }

    public void setup(String serverUrl, ImageView view, String path, String id){
        uploadURL = serverUrl;
        imgView = view;
        filePath = path;
        chatID = id;
    }

    @Override 
    protected void onPreExecute(){
        Looper.prepare();
        progressor.showProgressor("Uploading Image");
        try {
            saveImage(filePath, chatID);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Log.i("Debug", "Saving Failed: " + e.toString());
            this.cancel(true);
            return;
        }
    }

    @Override
    protected Integer doInBackground(String... params) {
        String fileName = params[0] + "/" + params[1] + ".png";
        Log.i("Debug", fileName);

        HttpURLConnection conn = null;
        DataOutputStream dos = null;  
        String lineEnd = "\r\n";
        String twoHyphens = "--";
        String boundary = "*****";
        int bytesRead, bytesAvailable, bufferSize;
        byte[] buffer;
        int maxBufferSize = 1 * 1024 * 1024; 
        File sourceFile = new File(fileName); 

        try{
             // open a URL connection to the Server
            FileInputStream fileInputStream = new FileInputStream(sourceFile);
            URL url = new URL(uploadURL);

            // Open a HTTP  connection to  the URL
            conn = (HttpURLConnection) url.openConnection(); 
            conn.setDoInput(true); // Allow Inputs
            conn.setDoOutput(true); // Allow Outputs
            conn.setUseCaches(false); // Don't use a Cached Copy
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("ENCTYPE", "multipart/form-data");
            conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
            conn.setRequestProperty("uploaded_file", fileName); 

            dos = new DataOutputStream(conn.getOutputStream());

            dos.writeBytes(twoHyphens + boundary + lineEnd); 
            dos.writeBytes("Content-Disposition: form-data; name='uploaded_file'; filename=" + fileName + "" + lineEnd);

            dos.writeBytes(lineEnd);

            // create a buffer of  maximum size
            bytesAvailable = fileInputStream.available(); 

            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            buffer = new byte[bufferSize];

            // read file and write it into form...
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);  

            while (bytesRead > 0) {

              dos.write(buffer, 0, bufferSize);
              bytesAvailable = fileInputStream.available();
              bufferSize = Math.min(bytesAvailable, maxBufferSize);
              bytesRead = fileInputStream.read(buffer, 0, bufferSize);   

             }

            // send multipart form data necesssary after file data...
            dos.writeBytes(lineEnd);
            dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

            // Responses from the server (code and message)
            serverResponseCode = conn.getResponseCode();
            String serverResponseMessage = conn.getResponseMessage();

            Log.i("Debug", "HTTP Response is : " + serverResponseMessage + ": " + serverResponseCode);  

            if(serverResponseCode == 200){
                String msg = "File Upload Completed.";
                toaster.popToast(msg);               
            }

            //close the streams //
            fileInputStream.close();
            dos.flush();
            dos.close();

        }catch(Exception e){
            e.printStackTrace();
            toaster.popToast(e.toString());
            Log.i("Debug", "Upload failed: " + e.toString());
        }
        return null;
    }

    @Override
    protected void onPostExecute(Integer result){
        progressor.dismiss();
        toaster.popToast("Upload done.");
    }

    @SuppressWarnings("finally")
    private String saveImage(String path, String id) throws FileNotFoundException{

        Drawable drawable = imgView.getDrawable();
        Rect bounds = drawable.getBounds();
        Bitmap bitmap = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.draw(canvas);
        OutputStream fOut = null;
        try{
            new File("/storage/sdcard0/SketchMessenger").mkdirs();
            fOut = new FileOutputStream(path + "/" + id + ".png");
            bitmap.compress(Bitmap.CompressFormat.PNG, 95, fOut);
        }finally{
            if(fOut != null){
                try{
                    fOut.close();
                    return path + id + ".png";
                }catch(IOException e){
                    e.printStackTrace();
                    Log.i("Debug", e.toString());
                }

            }
            return null;
        }
    }
}

和下载器类:

package com.sixcoresecond.helper;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.util.Log;
import android.widget.ImageView;

public class ImageDownloader extends AsyncTask<String, Void, Bitmap> {

    private static int imageWidth;
    private static int imageHeight;

    private String filePath;
    private String chatID;

    private ImageView imgView;
    private Toaster toaster;
    private Progressor progressor;

    public ImageDownloader(Context context, ImageView view){
        toaster = new Toaster(context);
        progressor = new Progressor(context);
        imageWidth = 0;
        imageHeight = 0;
        imgView = view;

        filePath = "";
        chatID = "";
    }

    @Override
    protected void onPreExecute(){
        progressor.showProgressor("Downloading latest Image.");
    }

    @Override
    protected Bitmap doInBackground(String... args) {
        String url = args[0] + args[1] + ".png";
        Log.i("Debug", "Downloading from: " + url);
        Bitmap bitmap = null;

        byte[] imageData = getImageFromUrl(url);

        bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length);

        /*
        ByteArrayInputStream inputStream = new ByteArrayInputStream(imageData);
        bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeStream(inputStream), 296, 425, true);*/
        return bitmap;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap){
        imgView.setImageBitmap(bitmap);
        try {
            saveImage(filePath, chatID);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Log.i("Debug", "Downloader failed to save image\n" + e.toString());
        }
        progressor.dismiss();
        toaster.popToast("Download done.");
    }

    private byte[] getImageFromUrl(String url){

        InputStream in = null;
        byte[] byteImage = null;

        try{
            URL imageUrl = new URL(url);
            URLConnection conn = imageUrl.openConnection();
            HttpURLConnection httpConn = (HttpURLConnection) conn;
            httpConn.setAllowUserInteraction(false);
            httpConn.setInstanceFollowRedirects(true);
            httpConn.setRequestMethod("GET");
            httpConn.connect();

            int response = httpConn.getResponseCode();

            if(response == HttpURLConnection.HTTP_OK){
                in = httpConn.getInputStream();
            }

            int nRead;
            byte[] data = new byte[16384];      
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();

            while((nRead = in.read(data, 0, data.length)) != -1){
                buffer.write(data, 0, nRead);
            }

            buffer.flush();         
            byteImage = buffer.toByteArray();
        }
        catch(IOException e){
            e.printStackTrace();
            Log.i("Debug", "Download Error: " + e.toString());
        }   

        return byteImage;
    }

    @SuppressWarnings("finally")
    private String saveImage(String path, String id) throws FileNotFoundException{

        Drawable drawable = imgView.getDrawable();
        Rect bounds = drawable.getBounds();
        Bitmap bitmap = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.draw(canvas);
        OutputStream fOut = null;
        try{
            new File("/storage/sdcard0/Download").mkdir();
            fOut = new FileOutputStream(path + "/" + id + ".png");
            bitmap.compress(Bitmap.CompressFormat.PNG, 95, fOut);
        }finally{
            if(fOut != null){
                try{
                    fOut.close();

                    return path + id + ".png";
                }catch(IOException e){
                    e.printStackTrace();
                    Log.i("Debug", e.toString());
                }
            }
            return null;
        }
    }
}

结果是这样的:

08-31 23:36:20.669: E/AndroidRuntime(1108): FATAL EXCEPTION: main
08-31 23:36:20.669: E/AndroidRuntime(1108): java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:578)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at android.os.AsyncTask.execute(AsyncTask.java:534)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at com.sixcoresecond.imageSync.ImageSyncActivity.updateCurrentImage(ImageSyncActivity.java:197)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at com.sixcoresecond.imageSync.ImageSyncActivity.onOptionsItemSelected(ImageSyncActivity.java:276)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at android.app.Activity.onMenuItemSelected(Activity.java:2566)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at com.android.internal.policy.impl.PhoneWindow.onMenuItemSelected(PhoneWindow.java:1039)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:735)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:874)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at com.android.internal.view.menu.ActionMenuView.invokeItem(ActionMenuView.java:547)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at com.android.internal.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:115)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at android.view.View.performClick(View.java:4247)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at android.view.View$PerformClick.run(View.java:17728)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at android.os.Handler.handleCallback(Handler.java:730)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at android.os.Handler.dispatchMessage(Handler.java:92)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at android.os.Looper.loop(Looper.java:137)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at android.app.ActivityThread.main(ActivityThread.java:5289)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at java.lang.reflect.Method.invokeNative(Native Method)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at java.lang.reflect.Method.invoke(Method.java:525)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:555)
08-31 23:36:20.669: E/AndroidRuntime(1108):     at dalvik.system.NativeStart.main(Native Method)

大部分代码,例如 toastr /进度条类,都可以忽略。这些部件工作正常。我已经研究过类似的问题,所以我知道基本的多重调用是不可能的。但我想知道这是如何“绕过”以使其工作的。

提前致谢。

最佳答案

查看堆栈跟踪,您正在尝试多次执行 AsyncTask 的同一个实例..尝试创建一个新实例..

关于android - 多次运行相同的 AsyncTask,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25596728/

相关文章:

android - 如何使用单独的线程来执行http请求

android - 更改语言环境在 Android 10 中停止工作

Android:如何连接到 Eclipse Build Project?

android - 异步任务与任务

java - Android 从 AsyncTask 访问 MainActivity

android - 在 AsyncTask 中使用 runOnUiThread 是否效率低且不好?

android - 数据未插入到 android 中的 Sqlite 数据库中

android - android 中谷歌地图中的自定义标记

Android 市场上的 Android 发布者帐户

android: cancel(true) 不会终止 AsyncTask