android - 如何在单独的线程中调用 startActivityForResult() 和 onResultActivity()?

标签 android multithreading

在我制作图像效果的android应用程序中,当涉及到选择图像时,有以下两个optoins:

1) 从图库中选择

2) 从你的相机中取出

以下是完成上述任务的代码:

String imagePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" +  System.currentTimeMillis() + "_ePixels.jpg";
File imageFile = new File(imagePath);
imageUri = Uri.fromFile(imageFile);



public void onClick(View clickedView) {

    int clickedViewId = clickedView.getId();

    switch(clickedViewId) {
        case R.id.takeFromCamera:
            Intent imageCaptureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            imageCaptureIntent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageUri);
            startActivityForResult(imageCaptureIntent,1888);
            break;
        case R.id.chooseFromGallery:
            Intent choosePictureIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            startActivityForResult(choosePictureIntent, 1);
            break;
        default:
            // As we have only two buttons, and nothing else can be clicked except the buttons. So no need to put
            // code in the "DEFAULT CASE"
    }
}

// Using one onActivityResult() for both calls and using a switch statement to differentiate what was called for actually!

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

    switch(requestCode) {
        case 1888:
            if(resultCode == RESULT_OK) {
                // Success, when user actually took a photo and camera returned back it to us!
                Intent cameraIntent = new Intent(MainOptionsActivity.this,ApplyEffectsActivity.class);
                cameraIntent.putExtra("imageFileUri", imageUri);
                startActivity(cameraIntent);
            } else if(resultCode == RESULT_CANCELED){
                // Failure, Activity couldn't receive the photo captured by the camera
                Toast.makeText(MainOptionsActivity.this, "You didn't capture a photo!", Toast.LENGTH_LONG).show();
            }
            break;
        case 1:
            if(resultCode == RESULT_OK) {
                // Success, Activity received the image from gallery
                Uri imageUriForGallery = intent.getData();
                Intent galleryIntent = new Intent(MainOptionsActivity.this,ApplyEffectsActivity.class);
                galleryIntent.putExtra("imageFileUri", imageUriForGallery);
                startActivity(galleryIntent);
            } else if(resultCode == RESULT_CANCELED) {
                // Failure, Gallery didn't send an image
                Toast.makeText(MainOptionsActivity.this, "You didn't select an image", Toast.LENGTH_LONG).show();
            }
            break;
    }

}

它工作得很好。但是,当我尝试加载一些大图像或在相机具有高分辨率分辨率的手机上运行我的应用程序时,android 给我 ANR 错误,这显然是由于主线程上的繁重工作。

显然,这个问题的解决方案是在单独的线程上完成所有繁重 工作。但是怎么做呢?我无法找到解决方案。我不是在问您如何在单独的线程上运行代码,而是在调用另一个 Activity 并从该 Activity 获得结果时如何在单独的线程上运行代码。

以下是 ApplyEffectsActivity 的代码:

package com.arslanali.epixels;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.arslanali.epixels.imagelibrary.ImageEffectFactory;

public class ApplyEffectsActivity extends Activity implements OnClickListener{

ImageView sepiaGreenishImage;
ImageView embossImage;
ImageView sharpenImage;
ImageView slightYellowishImage;
ImageView slightBluishImage;
ImageView slightReddishImage;
ImageView slightGreenishImage;
ImageView negativeImage;
ImageView greyScaleImage;
ImageView tintSeventyImage;
ImageView tintThirtyImage;
ImageView snowImage;
ImageView darkImage;
ImageView noiseImage;
ImageView flipImage;
ImageView rotateImage;
ImageView gaussianBlurImage;
ImageView reddishImage;
ImageView bluishImage;
ImageView greenishImage;
ImageView blackFilterImage;
ImageView increasedSepiaImage;
ImageView spiaBluishImage;
ImageView brightImage;
ImageView mirrorImage;


Button nextButton;
Button saveCurrentEditedImageButton;

// For displaying the image after modification
ImageView affectedImageView;

ProgressBar waitingProgressBar;

Bitmap sourceBitmap;
Bitmap modifiedBitmap;

// For sending it to next activity for the sharing purposes
Uri modifiedImgaeUri;

// Since, In beginning, we are dealing with the raw image
Boolean isEdited = false;

EffectNames currentEffectName;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_apply_effects);
    // Restricting the user to use mobile phone only in portrait mode
    setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

    // Grabbing the references of all the images
    sepiaGreenishImage      = (ImageView) findViewById(R.id.sepiaGreenish);
    embossImage             = (ImageView) findViewById(R.id.emboss);
    sharpenImage            = (ImageView) findViewById(R.id.sharpen);
    slightYellowishImage    = (ImageView) findViewById(R.id.ligth_yellow);
    slightBluishImage       = (ImageView) findViewById(R.id.light_blue);
    slightReddishImage      = (ImageView) findViewById(R.id.light_red);
    slightGreenishImage     = (ImageView) findViewById(R.id.light_green);
    negativeImage           = (ImageView) findViewById(R.id.negative);
    greyScaleImage          = (ImageView) findViewById(R.id.greyscale);
    tintSeventyImage        = (ImageView) findViewById(R.id.tint_at_70);
    tintThirtyImage         = (ImageView) findViewById(R.id.tint_at_30);
    snowImage               = (ImageView) findViewById(R.id.snow);
    darkImage               = (ImageView) findViewById(R.id.darken);
    noiseImage              = (ImageView) findViewById(R.id.noise);
    flipImage               = (ImageView) findViewById(R.id.flip);
    rotateImage             = (ImageView) findViewById(R.id.rotate);
    gaussianBlurImage       = (ImageView) findViewById(R.id.blur);
    reddishImage            = (ImageView) findViewById(R.id.reddish);
    bluishImage             = (ImageView) findViewById(R.id.bluish);
    greenishImage           = (ImageView) findViewById(R.id.greenish);
    blackFilterImage        = (ImageView) findViewById(R.id.black_filter);
    increasedSepiaImage     = (ImageView) findViewById(R.id.increased_sepia);
    spiaBluishImage         = (ImageView) findViewById(R.id.sepia_bluish);
    brightImage             = (ImageView) findViewById(R.id.brighten);
    mirrorImage             = (ImageView) findViewById(R.id.mirror);






    nextButton = (Button) findViewById(R.id.share);
    saveCurrentEditedImageButton = (Button) findViewById(R.id.saveit);

    affectedImageView = (ImageView) findViewById(R.id.affectedImage);
    waitingProgressBar =  (ProgressBar) findViewById(R.id.progressBar1);

    // Since, at the start we are displaying the image. So ProgressBar should be invisible
    waitingProgressBar.setVisibility(ProgressBar.INVISIBLE);

    nextButton.setOnClickListener(this);
    saveCurrentEditedImageButton.setOnClickListener(this);

    sepiaGreenishImage.setOnClickListener(this);
    embossImage.setOnClickListener(this);
    sharpenImage.setOnClickListener(this);
    slightYellowishImage.setOnClickListener(this);
    slightBluishImage.setOnClickListener(this);
    slightReddishImage.setOnClickListener(this);
    slightGreenishImage.setOnClickListener(this);
    negativeImage.setOnClickListener(this);
    greyScaleImage.setOnClickListener(this);
    tintSeventyImage.setOnClickListener(this);
    tintThirtyImage.setOnClickListener(this);
    snowImage.setOnClickListener(this);
    darkImage.setOnClickListener(this);
    noiseImage.setOnClickListener(this);
    flipImage.setOnClickListener(this);
    rotateImage.setOnClickListener(this);
    gaussianBlurImage.setOnClickListener(this);
    reddishImage.setOnClickListener(this);
    bluishImage.setOnClickListener(this);
    greenishImage.setOnClickListener(this);
    blackFilterImage.setOnClickListener(this);
    increasedSepiaImage.setOnClickListener(this);
    spiaBluishImage.setOnClickListener(this);
    brightImage.setOnClickListener(this);
    mirrorImage.setOnClickListener(this);


    // Grabbing the Uri from the previous calling activity
    Uri imageUri = (Uri) getIntent().getExtras().getParcelable("imageFileUri");

    try {
        sourceBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
        affectedImageView.setImageBitmap(sourceBitmap);


    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

}



@Override
public boolean onCreateOptionsMenu(Menu menu) {

    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}


// Using a switch statement for all cases and storing the result in "currentEffectName"

@Override
public void onClick(View clickedView) {
    int clickedViewId = clickedView.getId();

    switch(clickedViewId) {
        case R.id.sepiaGreenish:
            currentEffectName = EffectNames.SEPIA_GREEN_EFFECT;
            ImageAffector sepia = new ImageAffector();
            sepia.execute(sourceBitmap);
            break;
        case R.id.emboss:
            currentEffectName = EffectNames.EMBOSSING_EFFECT;
            ImageAffector emboss = new ImageAffector();
            emboss.execute(sourceBitmap);
            break;
        case R.id.sharpen:
            currentEffectName = EffectNames.SHARPEN_EFFECT;
            ImageAffector sharpen = new ImageAffector();
            sharpen.execute(sourceBitmap);
            break;
        case R.id.ligth_yellow:
            currentEffectName = EffectNames.LIGHT_YELLOW_EFFECT;
            ImageAffector lightYellow = new ImageAffector();
            lightYellow.execute(sourceBitmap);
            break;
        case R.id.light_blue:
                currentEffectName = EffectNames.SLIGHT_BLUISH_EFFECT;
                ImageAffector lightBlue = new ImageAffector();
                lightBlue.execute(sourceBitmap);
            break;
        case R.id.light_red:
            currentEffectName = EffectNames.SLIGHT_REDDISH_EFFECT;
            ImageAffector lightRed = new ImageAffector();
            lightRed.execute(sourceBitmap);
        break;
        case R.id.light_green:
            currentEffectName = EffectNames.SLIGHT_GREENISH_EFFECT;
            ImageAffector lightGreen = new ImageAffector();
            lightGreen.execute(sourceBitmap);
        break;
        case R.id.negative:
            currentEffectName = EffectNames.INVERT_EFFECT;
            ImageAffector negative = new ImageAffector();
            negative.execute(sourceBitmap);
        break;
        case R.id.greyscale:
            currentEffectName = EffectNames.GRAY_SCALE_EFFECT;
            ImageAffector greyScale = new ImageAffector();
            greyScale.execute(sourceBitmap);
        break;
        case R.id.tint_at_30:
            currentEffectName = EffectNames.TINT_AT_30;
            ImageAffector tintAt30 = new ImageAffector();
            tintAt30.execute(sourceBitmap);
        break;
        case R.id.tint_at_70:
            currentEffectName = EffectNames.TINT_AT_70;
            ImageAffector tintAt70 = new ImageAffector();
            tintAt70.execute(sourceBitmap);
        break;
        case R.id.snow:
            currentEffectName = EffectNames.SNOW_EFFECT;
            ImageAffector snowEffect = new ImageAffector();
            snowEffect.execute(sourceBitmap);
        break;
        case R.id.darken:
            currentEffectName = EffectNames.DARKEN_EFFECT;
            ImageAffector darken = new ImageAffector();
            darken.execute(sourceBitmap);
        break;
        case R.id.noise:
            currentEffectName = EffectNames.NOSIY_EFFECT;
            ImageAffector noise = new ImageAffector();
            noise.execute(sourceBitmap);
        break;
        case R.id.flip:
            currentEffectName = EffectNames.FLIPPING_EFFECT;
            ImageAffector flip = new ImageAffector();
            flip.execute(sourceBitmap);
        break;
        case R.id.rotate:
            currentEffectName = EffectNames.ROTATE_EFFECT;
            ImageAffector rotate = new ImageAffector();
            rotate.execute(sourceBitmap);
        break;
        case R.id.blur:
            currentEffectName = EffectNames.BLUR_EFFECT;
            ImageAffector blur = new ImageAffector();
            blur.execute(sourceBitmap);
        break;
        case R.id.reddish:
            currentEffectName = EffectNames.REDDISH_EFFECT;
            ImageAffector reddish = new ImageAffector();
            reddish.execute(sourceBitmap);
        break;
        case R.id.bluish:
            currentEffectName = EffectNames.BLUISH_EFFECT;
            ImageAffector bluish = new ImageAffector();
            bluish.execute(sourceBitmap);
        break;
        case R.id.greenish:
            currentEffectName = EffectNames.GREENISH_EFFECT;
            ImageAffector greenish = new ImageAffector();
            greenish.execute(sourceBitmap);
        break;
        case R.id.black_filter:
            currentEffectName = EffectNames.BLACK_FILTER_EFFECT;
            ImageAffector blackFilter = new ImageAffector();
            blackFilter.execute(sourceBitmap);
        break;
        case R.id.increased_sepia:
            currentEffectName = EffectNames.INCREASED_SEPIA_EFFECT;
            ImageAffector increasedSepia = new ImageAffector();
            increasedSepia.execute(sourceBitmap);
        break;
        case R.id.sepia_bluish:
            currentEffectName = EffectNames.SEPIA_BLUE_EFFECT;
            ImageAffector sepiaBluish = new ImageAffector();
            sepiaBluish.execute(sourceBitmap);
        break;
        case R.id.brighten:
            currentEffectName = EffectNames.BRIGHTENING_EFFECT;
            ImageAffector brighten = new ImageAffector();
            brighten.execute(sourceBitmap);
        break;
        case R.id.mirror:
            currentEffectName = EffectNames.MIRROR_EFFECT;
            ImageAffector mirror = new ImageAffector();
            mirror.execute(sourceBitmap);
        break;
        case R.id.saveit:
            modifiedImgaeUri = saveEditedImageIntoSDCard(modifiedBitmap);
            Toast.makeText(this, "Saved!" , Toast.LENGTH_SHORT).show();
            isEdited = true;
            break;
        case R.id.share:
            // Making sure that user has applied at least one effect. Otherwise it will be useless 
            // to share the unmodified image with the use of app.
            if(!isEdited) {
                // If not modified, enforce the user to first modify and then share!
                Toast.makeText(this, "You didn't apply any effect", Toast.LENGTH_LONG).show();
                break;
            }
            Intent shareActivityIntent = new Intent(ApplyEffectsActivity.this, ShareActivity.class);
            shareActivityIntent.putExtra("modifiedImageUri", modifiedImgaeUri);
            startActivity(shareActivityIntent);
        break;
    }
}

public static Uri saveEditedImageIntoSDCard(Bitmap bitmap) {


    // Using PNG format over JPEG for better performance of the app
    String imageFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/ePixels_" + System.currentTimeMillis() + ".png";
    File imageFile = new File(imageFilePath);
    Uri modifiedImageUri = Uri.fromFile(imageFile);



    FileOutputStream outStream;
    try {

        outStream = new FileOutputStream(imageFile);
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream); 
        // Writing the image to outStream 


        outStream.flush();
        // Making sure nothing else could be written to file from any other source
        outStream.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }   
    return modifiedImageUri;
}

private class ImageAffector extends AsyncTask<Bitmap, Integer, Bitmap>{

    protected void onPreExecute(){
        // Since, image has gone into background for modification. Therefore hiding it and making
        // ProgressBar visible
        waitingProgressBar.setVisibility(ProgressBar.VISIBLE);
        affectedImageView.setVisibility(ImageView.INVISIBLE);
    }
    protected Bitmap doInBackground(Bitmap... bitmap) {
        try{

            switch(currentEffectName) {
                case SEPIA_GREEN_EFFECT:
                    modifiedBitmap = ImageEffectFactory.applySepiaEffectWithGreenAsMajority(bitmap[0]);
                    return modifiedBitmap;
                case EMBOSSING_EFFECT:
                    modifiedBitmap = ImageEffectFactory.embossAnImage(bitmap[0]);
                    return modifiedBitmap;
                case SHARPEN_EFFECT:
                    modifiedBitmap = ImageEffectFactory.sharpenAnImage(bitmap[0]);
                    return modifiedBitmap;
                case MIRROR_EFFECT:
                    modifiedBitmap = ImageEffectFactory.mirrorAnImage(bitmap[0]);
                    return modifiedBitmap;
                case LIGHT_YELLOW_EFFECT:
                    modifiedBitmap = ImageEffectFactory.produceSlightYellowishEffect(bitmap[0]);
                    return modifiedBitmap;
                case SLIGHT_REDDISH_EFFECT:
                    modifiedBitmap = ImageEffectFactory.produceSlightReddishEffect(bitmap[0]);
                    return modifiedBitmap;
                case SLIGHT_GREENISH_EFFECT:
                    modifiedBitmap = ImageEffectFactory.produceSlightGreenishEffect(bitmap[0]);
                    return modifiedBitmap;
                case SLIGHT_BLUISH_EFFECT:
                    modifiedBitmap = ImageEffectFactory.produceSlightBluishEffect(bitmap[0]);
                    return modifiedBitmap;
                case INVERT_EFFECT:
                    modifiedBitmap = ImageEffectFactory.invertAllPixels(bitmap[0]);
                    return modifiedBitmap;
                case GRAY_SCALE_EFFECT:
                    modifiedBitmap = ImageEffectFactory.turnIntoGrayScale(bitmap[0]);
                    return modifiedBitmap;
                case TINT_AT_30:
                    modifiedBitmap = ImageEffectFactory.tintImage(bitmap[0], 30);
                    return modifiedBitmap;
                case TINT_AT_70:
                    modifiedBitmap = ImageEffectFactory.tintImage(bitmap[0], 70);
                    return modifiedBitmap;
                case SNOW_EFFECT:
                    modifiedBitmap = ImageEffectFactory.applySnowEffect(bitmap[0]);
                    return modifiedBitmap;
                case DARKEN_EFFECT:
                    modifiedBitmap = ImageEffectFactory.darkenAnImage(bitmap[0]);
                    return modifiedBitmap;
                case NOSIY_EFFECT:
                    modifiedBitmap = ImageEffectFactory.applyNoiseEffect(bitmap[0]);
                    return modifiedBitmap;
                case FLIPPING_EFFECT:
                    modifiedBitmap = ImageEffectFactory.flipAnImage(bitmap[0]);
                    return modifiedBitmap;
                case ROTATE_EFFECT:
                    modifiedBitmap = ImageEffectFactory.rotateAnImage(bitmap[0]);
                    return modifiedBitmap;
                case BLUR_EFFECT:
                    modifiedBitmap = ImageEffectFactory.applyGaussainBlur(bitmap[0]);
                    return modifiedBitmap;
                case REDDISH_EFFECT:
                    modifiedBitmap = ImageEffectFactory.produceReddieshEffect(bitmap[0]);
                    return modifiedBitmap;
                case BLUISH_EFFECT:
                    modifiedBitmap = ImageEffectFactory.produceBluishEffect(bitmap[0]);
                    return modifiedBitmap;
                case GREENISH_EFFECT:
                    modifiedBitmap = ImageEffectFactory.produceGreenishEffect(bitmap[0]);
                    return modifiedBitmap;
                case BLACK_FILTER_EFFECT:
                    modifiedBitmap = ImageEffectFactory.applyBlackFilter(bitmap[0]);
                    return modifiedBitmap;
                case INCREASED_SEPIA_EFFECT:
                    modifiedBitmap = ImageEffectFactory.applyIncreasedSepiaEffect(bitmap[0]);
                    return modifiedBitmap;
                case SEPIA_BLUE_EFFECT:
                    modifiedBitmap = ImageEffectFactory.applySepiaEffectWithBlueAsMajority(bitmap[0]);
                    return modifiedBitmap;
                case BRIGHTENING_EFFECT:
                    modifiedBitmap = ImageEffectFactory.brigthenAnImage(bitmap[0]);
                    return modifiedBitmap;



            }

        }catch(Exception e){
            // For the reason: if the size of image is too large to load
            Toast.makeText(ApplyEffectsActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
            Log.e("Image","Failed to load image",e);
        }

        return null;
    } 

    protected void onPostExecute(Bitmap img){
            // After the modification of image, displaying it and hiding ProgressBar.
            waitingProgressBar.setVisibility(ProgressBar.INVISIBLE);
            affectedImageView.setVisibility(ImageView.VISIBLE);
            affectedImageView.setImageBitmap(img);
            // Setting it modifiedBitmap so that we could share it on next activity
            modifiedBitmap = img;
    }
    protected void onProgressUpdate(Integer... params){
         super.onProgressUpdate(params);
    }

    protected void onCancelled(){
    }
}

最佳答案

使用 AsyncTask 在您的 ApplyEffectsActivity 中完成繁重的工作。 the documentation 上都有解释.基本上,在 doInBackground 方法中进行处理,在 onProgressUpdateonPostExecute 函数中进行所有 UI 更新。

在 ApplyEffectsActivity 中,流程基本上是:

开始时:

  1. 显示进度指示器
  2. 开始任务

在你的任务中:

  1. 在doInBackground中进行处理
  2. 在 onPostExecute 中隐藏进度指示器

编辑:

应该将什么移到任务中:

    sourceBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
    affectedImageView.setImageBitmap(sourceBitmap);

根据我的说法,您应该在 UI 中显示原始位图的缩小版本(节省内存)。然后您的任务将处理它,并在保存时将相同的效果设置应用于原始位图。

关于android - 如何在单独的线程中调用 startActivityForResult() 和 onResultActivity()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16385849/

相关文章:

multithreading - golang线程数误导

android - 在 recyclerView android 中显示来自 hereNow Pubnub 的结果数据

android - 自定义操作栏删除 Logo 的左边距

android - Google Play 控制台警告 : Unknown validation VALIDATE_APP_MESSAGE_NO_APKS

c# - 升级 Xamarin 表单后按钮无法立即呈现

c++ - Boost Asio io_service 析构函数卡在 OS X 上

Java - 使用执行器服务的线程

android - android系统多久扫描一次wifi

java - 在队列中等待的线程,Java

c - 使用pthread在C中生成随机数的最正确方法是什么