Ứng dụng máy ảnh làm việc đơn giản tránh vấn đề mục đích null
- tất cả các mã thay đổi được bao gồm trong trả lời này; gần với hướng dẫn Android
Tôi đã dành nhiều thời gian cho vấn đề này, vì vậy tôi quyết định tạo một tài khoản và chia sẻ kết quả của mình với bạn.
Hướng dẫn chính thức dành cho Android "Chụp ảnh đơn giản" hóa ra không hoàn toàn giữ đúng những gì nó đã hứa. Mã được cung cấp ở đó không hoạt động trên thiết bị của tôi: Samsung Galaxy S4 Mini GT-I9195 chạy phiên bản Android 4.4.2 / KitKat / API Cấp 19.
Tôi đã tìm ra rằng vấn đề chính là dòng sau trong phương thức được gọi khi chụp ảnh ( dispatchTakePictureIntent
trong hướng dẫn):
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
Nó dẫn đến ý định sau đó bị bắt bởi onActivityResult
null.
Để giải quyết vấn đề này, tôi đã lấy nhiều cảm hứng từ các câu trả lời trước đây ở đây và một số bài viết hữu ích trên github (chủ yếu là bài này của deepwinter - rất cảm ơn anh ấy; bạn có thể muốn xem câu trả lời của anh ấy trên một bài đăng liên quan chặt chẽ ).
Theo những lời khuyên thú vị này, tôi đã chọn chiến lược xóa putExtra
dòng đã đề cập và thực hiện điều tương ứng là lấy lại ảnh đã chụp từ máy ảnh trong phương thức onActivityResult (). Các dòng mã quyết định để lấy lại bitmap được liên kết với hình ảnh là:
Uri uri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
Tôi đã tạo ra một ứng dụng mẫu mực có khả năng chụp ảnh, lưu nó vào thẻ SD và hiển thị nó. Tôi nghĩ rằng điều này có thể hữu ích cho những người có cùng hoàn cảnh như tôi khi tôi vấp phải vấn đề này, vì các đề xuất trợ giúp hiện tại chủ yếu đề cập đến các bài đăng github khá rộng rãi làm vấn đề nhưng không quá dễ dàng để giám sát những người mới như tôi. Đối với hệ thống tệp mà Android Studio tạo theo mặc định khi tạo dự án mới, tôi chỉ phải thay đổi ba tệp cho mục đích của mình:
Activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.android.simpleworkingcameraapp.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="takePicAndDisplayIt"
android:text="Take a pic and display it." />
<ImageView
android:id="@+id/image1"
android:layout_width="match_parent"
android:layout_height="200dp" />
</LinearLayout>
MainActivity.java:
package com.example.android.simpleworkingcameraapp;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.Image;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private ImageView image;
static final int REQUEST_TAKE_PHOTO = 1;
String mCurrentPhotoPath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image1);
}
// copied from the android development pages; just added a Toast to show the storage location
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmm").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
Toast.makeText(this, mCurrentPhotoPath, Toast.LENGTH_LONG).show();
return image;
}
public void takePicAndDisplayIt(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) != null) {
File file = null;
try {
file = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
startActivityForResult(intent, REQUEST_TAKE_PHOTO);
}
}
@Override
protected void onActivityResult(int requestCode, int resultcode, Intent intent) {
if (requestCode == REQUEST_TAKE_PHOTO && resultcode == RESULT_OK) {
Uri uri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
image.setImageBitmap(bitmap);
}
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.simpleworkingcameraapp">
<!--only added paragraph-->
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- only crucial line to add; for me it still worked without the other lines in this paragraph -->
<uses-permission android:name="android.permission.CAMERA" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Lưu ý rằng giải pháp tôi tìm thấy cho vấn đề cũng dẫn đến việc đơn giản hóa tệp kê khai Android: những thay đổi được đề xuất bởi hướng dẫn Android về việc thêm nhà cung cấp không còn cần thiết vì tôi không sử dụng bất kỳ mã java nào. Do đó, chỉ có một vài dòng tiêu chuẩn - chủ yếu liên quan đến quyền - phải được thêm vào tệp kê khai.
Ngoài ra, có thể có giá trị khi chỉ ra rằng tính năng tự động nhập của Android Studio có thể không có khả năng xử lý java.text.SimpleDateFormat
và java.util.Date
. Tôi đã phải nhập cả hai bằng tay.