Простий робочий додаток для камери, уникаючи проблеми з нульовим наміром
- весь змінений код, включений у цю відповідь; близько до Android підручник
Я витрачав багато часу на це питання, тому вирішив створити обліковий запис і поділитися своїми результатами з вами.
Офіційний підручник для Android "Фотографування просто" виявився не зовсім таким, що обіцяв. Код за умови, що на моєму пристрої не працював: Samsung Galaxy S4 Mini GT-I9195 під керуванням Android версії 4.4.2 / KitKat / API Рівень 19.
Я зрозумів, що головна проблема полягала в наступному рядку в методі, який викликається під час зйомки фотографії ( dispatchTakePictureIntent
у підручнику):
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
Це призвело до того, що намір згодом виявився onActivityResult
нульовим.
Щоб вирішити цю проблему, я отримав багато натхнення з попередніх відповідей тут і декількох корисних дописів на Github (в основному, цей за допомогою deepwinter - велике спасибі йому; ви можете перевірити його відповідь і на тісно пов'язаній публікації ).
Дотримуючись цих приємних порад, я вибрав стратегію видалення згаданого putExtra
рядка і зробив відповідне завдання повернення зробленого зображення з камери в методі onActivityResult (). Визначальними рядками коду для повернення растрового зображення, пов'язаного із зображенням, є:
Uri uri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
Я створив зразковий додаток, який просто має можливість сфотографувати, зберегти його на SD-картці та відобразити. Я думаю, що це може бути корисним людям, що перебувають у тій же ситуації, що й я, коли я натрапив на це питання, оскільки нинішні пропозиції щодо допомоги в основному стосуються досить обширних постів про github, які займаються питанням, але їх не так просто наглядати за новичками, як я. Що стосується файлової системи Android Studio створюється за замовчуванням під час створення нового проекту, мені просто довелося змінити три файли за своїм призначенням:
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>
Зауважте, що знайдене нами рішення для проблеми також призвело до спрощення файлу маніфесту андроїд: зміни, запропоновані підручником для Android з точки зору додавання постачальника, більше не потрібні, оскільки я не використовую жодного в своєму коді Java. Отже, до файлу маніфесту потрібно було додати лише кілька стандартних рядків - переважно щодо дозволів.
Крім того, може бути корисним зазначити, що автоімпорт Android Studio може не працювати java.text.SimpleDateFormat
і java.util.Date
. Мені довелося імпортувати обидва вручну.