Android在ImageView上从URI设置图像

更新了更多代码

我试图抓取刚拍摄的照片并以编程方式将其设置为ImageView.

按下图片按钮,

picture_button.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
        takePhoto(mTextureView);
    }
});

它运行takePhoto方法

public void takePhoto(View view) {
    try {
        mImageFile = createImageFile();
        final ImageView latest_picture = (ImageView) findViewById(R.id.latest_picture);
        final RelativeLayout latest_picture_container = (RelativeLayout) findViewById(R.id.latest_picture_container);
        final String mImageFileLocationNew = mImageFileLocation.replaceFirst("^/","");
        Toast.makeText(getApplicationContext(),"" + mImageFile,Toast.LENGTH_SHORT).show();
        Uri uri = Uri.fromFile(mImageFile);
        Toast.makeText(getApplicationContext(),""+uri,Toast.LENGTH_LONG).show();
        latest_picture.setImageURI(uri);
        latest_picture_container.setVisibility(View.VISIBLE);
    } catch (IOException e){
        e.printStackTrace();
    }
    lockFocus();
    captureStillImage();
}

运行createImageFile()和captureStillImage()

private void captureStillImage() {
    try {
        CaptureRequest.Builder captureStillBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        captureStillBuilder.addTarget(mImageReader.getSurface());
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        captureStillBuilder.set(CaptureRequest.JPEG_ORIENTATION,ORIENTATIONS.get(rotation));
        CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
            @Override
            public void onCaptureCompleted(CameraCaptureSession session,CaptureRequest request,TotalCaptureResult result) {
                super.onCaptureCompleted(session,request,result);
                //Toast.makeText(getApplicationContext(),"Image Taken",Toast.LENGTH_SHORT).show();
                unLockFocus();
            }
        };
        mCameraCaptureSession.capture(captureStillBuilder.build(),captureCallback,null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

File createImageFile() throws IOException {
    String timestamp = new SimpleDateFormat("yyyyMMdd").format(new Date());
    String subFolder = "";
    if(pref_session_unique_gallery.equals("yes")){
        if(event_name != null){
            subFolder = event_name;
        } else {
            subFolder = timestamp;
        }
    } else {
        subFolder = "_GEN";
    }
    if(event_name == null){
        event_name = "";
    } else {
        event_name = event_name + "_";
    }
    String imageFileName = "CPB_"+event_name+timestamp+"_";
    File storageDirectory = new File(Environment.getExternalStorageDirectory() + File.separator + "CPB" + File.separator + subFolder);
    storageDirectory.mkdir();
    File image = File.createTempFile(imageFileName,".jpg",storageDirectory);
    mImageFileLocation = image.getAbsolutePath();
    return image;
}

和图像保存在这里:

private static class ImageSaver implements Runnable {
    private final Image mImage;
    private ImageSaver(Image image) {
        mImage = image;
    }
    @Override
    public void run() {
        ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer();
        byte[] bytes = new byte[byteBuffer.remaining()];
        byteBuffer.get(bytes);

        FileOutputStream fileOutputStream = null;

        try {
            fileOutputStream = new FileOutputStream(mImageFile);
            fileOutputStream.write(bytes);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            mImage.close();
            if(fileOutputStream != null){
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }

我在createImageFile()之后获取了正确的图像路径并将其烘烤以显示每次都是什么.但即使是latest_picture_container上的setVisibility也没有工作……如果我注释掉InputStream,Bitmap和setImageBitmap,那么latest_picture_container就会正常显示.不知道为什么这是错的.

出于某种原因,URI在文件后面会有三个斜杠,

file:///storage/0/...
最佳答案
AssetManager#open()方法仅适用于您应用的资产;即项目的/ assets文件夹中的文件.由于您尝试打​​开外部文件,因此应该在从路径创建的File对象上使用FileInputStream.此外,takePhoto()方法在将任何内容写入文件之前在ImageView上设置图像,这将导致空的ImageView.

由于您的应用程序直接使用相机,我们可以从正在写入图像文件的相同字节数组中解码图像,并为自己节省不必要的存储读取.此外,在您的代码示例中,文件写入发生在单独的线程上,因此我们不妨利用它来执行图像解码,因为它将最小化对UI线程的影响.

首先,我们将创建一个接口,ImageSaver可以通过该接口将图像传递回活动以在ImageView中显示.

public interface OnImageDecodedListener {
    public void onImageDecoded(Bitmap b);
}

然后我们需要稍微改变ImageSaver类以在构造函数获取Activity参数.我还添加了一个File参数,因此Activity的相应字段不必是静态的.

private static class ImageSaver implements Runnable {
    private final Activity mActivity;
    private final Image mImage;
    private final File mImageFile;

    public ImageSaver(Activity activity,Image image,File imageFile) {
        mActivity = activity;
        mImage = image;
        mImageFile = imageFile;
    }

    @Override
    public void run() {
        ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer();
        byte[] bytes = new byte[byteBuffer.remaining()];
        byteBuffer.get(bytes);

        final Bitmap b = BitmapFactory.decodeByteArray(bytes,bytes.length);
        mActivity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    ((OnImageDecodedListener) mActivity).onImageDecoded(b);
                }
            }
        );

        FileOutputStream fileOutputStream = null;
        ...
    }
}

一旦我们在字节数组中获取图像数据,我们就将其解码并将其传递回Activity,因此它不必等待文件写入,这可以在后台安静地进行.我们需要在UI线程上调用接口方法,因为我们在那里“触摸”了视图.

Activity需要实现接口,我们可以将与视图相关的东西从takePhoto()移动到onImageDecoded()方法.

public class MainActivity extends Activity
    implements ImageSaver.OnImageDecodedListener {
    ...

    @Override
    public void onImageDecoded(Bitmap b) {
        final ImageView latest_picture =
            (ImageView) findViewById(R.id.latest_picture);
        final RelativeLayout latest_picture_container =
            (RelativeLayout) findViewById(R.id.latest_picture_container);

        latest_picture.setImageBitmap(b);
        latest_picture_container.setVisibility(View.VISIBLE);
    }

    public void takePhoto(View view) {
        try {
            mImageFile = createImageFile();
            captureStillImage();
            lockFocus();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
    ...
}

最后,我们需要在ImageReader的onImageAvailable()方法中实际执行ImageSaver.再次按照这个例子,它会是这样的.

private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = 
    new ImageReader.OnImageAvailableListener() {
    @Override
    public void onImageAvailable(ImageReader reader) {
        mBackgroundHandler.post(new ImageSaver(MainActivity.this,reader.acquireNextImage(),mImageFile)
        );
    }
};

相关文章

以下为个人理解,如错请评 CE: 凭据加密 (CE) 存储空间, 实际路径/data/user_ce/ DE: 设备加密 (DE) 存...
转载来源:https://blog.csdn.net/yfbdxz/article/details/114702144 用EventLog.writeEvent打的日志(或...
事件分发机制详解 一、基础知识介绍 1、经常用的事件有:MotionEvent.ACTION_DOWN,MotionEvent.ACTION...
又是好久没有写博客了,一直都比较忙,最近终于有时间沉淀和整理一下最近学到和解决的一些问题。 最近进...
Android性能优化——之控件的优化 前面讲了图像的优化,接下来分享一下控件的性能优化,这里主要是面向...
android的开源库是用来在android上显示gif图片的。我在网上查了一下,大家说这个框架写的不错,加载大的...