使用Thread获取图像资源时,Intent选择器保持打开状态

时间:2014-06-13 15:18:30

标签: android android-asynctask

我正在构建一个照片上传表单,该表单必须从相机或图库或任何其他可用资源(Dropbox / Google Drive / Astro文件管理器等)获取图像。我认为除了一个小组件之外,我已经全部工作了。

如果所选图片来自网络资源(例如Google云端硬盘),则可能需要很长时间才能返回活动状态。我想让这个异步,以避免用户在图像下载时盯着黑屏。

我写了很多代码来完成整个工作,但这里是它的一般过程:

  1. 活动开始并显示表格。

  2. Intent选择器自动打开并要求用户从相机或其他应用程序中选择图像。

  3. 用户选择某个应用,例如Google云端硬盘,选择图片并关闭该应用,然后返回选定的图片Uri

  4. 将文件内容缓存到变通方法KitKat权限,如果活动关闭并需要恢复,则可以阻止重新读取图像。

  5. 使用缓存文件作为源异步显示缩放位图。

  6. Intent选择器关闭,图像显示在ImageButton中,用户可以在提交前填写表单。

  7. 点击提交按钮后,将启动异步任务,允许将多部分上传到服务器。

  8. 异步上传使用回调函数通知用户上传进度。

  9. 我陷入了#3和#4之间的过渡期。

    如果我使用Thread或AsyncTask Intent选择器将保持打开状态,但图像也将显示在表单上。

    如果我只是强迫用户等待(连续) 用户看着黑屏,然后关闭意图选择器,图像显示在表单上。

    打开Intent选择器

    /**
     * see http://stackoverflow.com/a/12347567/940217
     */
    private void openImageIntent() {
    
        // Camera.
        final List<Intent> cameraIntents = new ArrayList<Intent>();
        final PackageManager packageManager = getPackageManager();
        Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    
        File photoFile;
        try {
            uploadableImage.makeCameraTempFile();
            photoFile = uploadableImage.getCameraTempFile();
            uploadableImage.setCameraFilepath(photoFile.getAbsolutePath());
        } catch (IOException ex) {
            // Error occurred while creating the File
            photoFile = null;
            uploadableImage.invalidate();
            Log.e(TAG, "Error while creating the temporary file needed for image capture from camera.");
            ex.printStackTrace();
        }
        // Continue only if the File was successfully created
        if (photoFile != null && packageManager != null) {
            final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
            for (ResolveInfo res : listCam) {
                // Create the File where the photo should go
                if (res.activityInfo == null) {
                    continue;
                }
                final String packageName = res.activityInfo.packageName;
                final Intent intent = new Intent(captureIntent);
                intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
                intent.setPackage(packageName);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
                cameraIntents.add(intent);
            }
        } else {
            Toast.makeText(this, "Could not make temporary file.", Toast.LENGTH_LONG).show();
        }
    
        // Filesystem.
        final Intent galleryIntent = new Intent();
        galleryIntent.setType("image/*");
        galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
    
        // Chooser of filesystem options.
        final Intent chooserIntent = Intent.createChooser(galleryIntent, "Select Source");
    
        // Add the camera options.
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[cameraIntents.size()]));
        startActivityForResult(chooserIntent, REQUEST_IMAGE_CAPTURE);
    }
    

    onActivityResult

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK && requestCode == REQUEST_IMAGE_CAPTURE) {
            if (tempUpFile != null){
                tempUpFile.invalidate();
            }
            if (data == null) {
                Log.d(TAG, "Data was null -- source was from camera");
                uploadableImage.preserveCameraFile();
                setPic();
            } else {
    
                Uri selectedImageUri = data.getData();
                if (selectedImageUri == null) {
                    Log.e(TAG, "An error that should never occur has occurred -- selectedImageUri was null when trying to get the data from the Image Capture activity result.");
                    Toast.makeText(this, "Unexpected error when trying to get an image from the gallery or file manager.", Toast.LENGTH_LONG).show();
                    return;
                }
                uploadableImage.setSourceImageUri(selectedImageUri, imageButton);
                setPic();  // only do this if doing this serially.
            }
        } else if (resultCode == RESULT_CANCELED){
            uploadableImage.invalidate();
            if (tempUpFile != null){
                uploadableImage = tempUpFile;
            }
            setPic();
        }
    }
    

    UploadableImage#setSourceImageUri

    public void setSourceImageUri(Uri selectedImageUri, final ImageView iView) {
    
        // Important!! - clean up after ourselves!
        deleteFile(this.cameraFile);
        this.cameraFile = null;
    
        InputStream tempInStream = null;
        OutputStream tempOutStream = null;
        try {
            this.cacheFile = createFile();
            tempInStream = context.getContentResolver().openInputStream(selectedImageUri);
            tempOutStream = new FileOutputStream(this.cacheFile);
        } catch (IOException e) {
            Toast.makeText(context, "Error while trying to read the selected image.", Toast.LENGTH_LONG).show();
            Log.e(TAG, "IOException while trying to copy the selected image to our cache file");
            e.printStackTrace();
        }
    
        if (tempInStream == null || tempOutStream == null){
            Toast.makeText(context, "Error while trying to "+(tempInStream == null ? "read" :"store")+" the selected image.", Toast.LENGTH_LONG).show();
            Log.e(TAG, "Error while trying to get the " + (tempInStream == null ? "input" : "output") + " stream");
            return;
        }
    
        // Works, but makes the UI hang on a black screen while waiting for the resource.
        try {
            copy(tempInStream, tempOutStream);
        }catch (IOException e){
            Toast.makeText(context, "Error while trying to read the selected image.", Toast.LENGTH_LONG).show();
            Log.e(TAG, "IOException while trying to copy the selected image to our cache file");
            e.printStackTrace();
        }
    
        /*
        // Works, but leaves the IntentChooser open
        final InputStream inStream = tempInStream;
        final OutputStream outStream = tempOutStream;
        new Thread(new Runnable() {
            public void run() {
                try {
                    copy(inStream, outStream);
                    // FIXME: somehow notify/display the bitmap in the UI
                    // --maybe use Message and Handler? callback Interface?
                } catch (IOException e) {
                    Toast.makeText(context, "Error while trying to read the selected image.", Toast.LENGTH_LONG).show();
                    Log.e(TAG, "IOException while trying to copy the selected image to our cache file");
                    e.printStackTrace();
                }
            }
        }).start();
        */
    }
    

    编辑:

    我发现这将/不会发生,具体取决于API级别。

    不会发生:

    • KitKat(Nexus 4)
    • ICS MR1(模拟器)

    确实发生:

    • KitKat(模拟器)
    • ICS MR1(Galaxy Tab 10.1)

    编辑2:

    以下是不应该发生的截图;图像来自KitKat模拟器。

    开始活动

    Intent chooser opens

    从图库或其他资源中选择图像

    Select image from gallery

    onActivityResult返回并且选择器保持打开状态

    Intent chooser is open and image is displayed

    这是它应该如何照顾onActivityResult

    Intent chooser is closed and image is displayed

1 个答案:

答案 0 :(得分:2)

感觉非常愚蠢,但我找到了解决方案。

问题出在第二步:&#34;意图选择器会自动打开...&#34;

为了做到这一点,我正在检查位图是否可用,如果它不是,那么它应该显示占位符图像,然后打开Intent选择器。我在onStart方法中有这个逻辑,它通常在onActivityResult之后运行。但是,因为这一切都是异步发生的,所以我不能依赖这个顺序。

我必须做的是放入一个布尔标志,它可以告诉我是否在等待位图,然后如果我们这样做就不会打开选择器。