所以我试图让用户拍一张照片然后发送到服务器.我在
android中有点像菜鸟,所以我按照
this教程了解如何操作.我见过几个类似于我的问题,但不完全一样.该应用程序确实启动相机应用程序,并允许我拍照,这是当我点击“检查”接受图像,以便说我收到消息“不幸的是,相机已经停止”,应用程序返回到活动的地方我没有明显地获得缩略图和图像.从相机启动到停止工作的那一刻起,Logcat都不会显示任何内容.这是我的代码:
活动
package com.example.ignacio.androidchat; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.location.LocationManager; import android.net.Uri; import android.os.Environment; import android.provider.MediaStore; import android.support.v4.content.FileProvider; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Base64; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.net.URI; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; public class TaskCompletionForm extends AppCompatActivity{ private static final String TAG = "TaskCompletionForm"; private static int REQUEST_IMAGE_CAPTURE = 1; ImageView formImageView; private String currImagePath; private final boolean submitTime = false; private final boolean submitGPS = false; private final boolean requestImage = true; private final boolean requestQRRead = false; private final boolean requestRFID = false; private LinearLayout formContainer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_task_completion_form); formContainer = (LinearLayout) findViewById(R.id.ll_formContainer); final Button b_submit = (Button) findViewById(R.id.b_submit); b_submit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { submitForm(); } }); final Button b_takePicture = (Button) findViewById(R.id.b_takePicture); b_takePicture.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dispatchPhotographIntent(); } }); formImageView = (ImageView) findViewById(R.id.formImageView); } private void submitForm() { final int childCount = formContainer.getChildCount() - 1; JSONObject jsonObject = new JSONObject(); try { // add text fields int textFieldCount = 0; ArrayList<String> entries = new ArrayList<>(); for (int i = 0; i < childCount; i++) { View v = formContainer.getChildAt(i); if (v instanceof EditText) { entries.add(((EditText) v).getText().toString()); textFieldCount++; } } jsonObject.put("fieldCount",textFieldCount); jsonObject.put("fields",new JSONArray(entries)); // add image if (requestImage && !currImagePath.equals("")) { Bitmap bitmap = BitmapFactory.decodeFile(currImagePath); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG,100,byteArrayOutputStream); byte[] byteArray = byteArrayOutputStream.toByteArray(); String encodedImage = Base64.encodeToString(byteArray,Base64.DEFAULT); jsonObject.put("image",encodedImage); } } catch (JSONException e) { e.printStackTrace(); } WebSocket.getInstance().submitCompletionForm(jsonObject); } private void dispatchPhotographIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { File photoFile = null; try{ photoFile = createImageFile(); } catch (IOException e) { e.printStackTrace(); // handle exeption } // continue only if the file was successfully created if (photoFile != null) { Uri photoURI = FileProvider.getUriForFile(this,"com.example.ignacio.androidchat.fileprovider",photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,photoURI); startActivityForResult(takePictureIntent,REQUEST_IMAGE_CAPTURE); } } } private File createImageFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File image = File.createTempFile(imageFileName,".jpg",storageDir); if (!image.exists()) { image.getParentFile().mkdirs(); image.createNewFile(); } currImagePath = image.getAbsolutePath(); return image; } @Override protected void onActivityResult(int requestCode,int resultCode,Intent data) { if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { Bundle extras = data.getExtras(); Bitmap imageBitmap = (Bitmap) extras.get("data"); formImageView.setImageBitmap(imageBitmap); } } }
表现
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.ignacio.androidchat"> <uses-permission android:name="android.permission.INTERNET" /> <!-- To auto-complete the email text field in the login form with the user's emails <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_CONTACTS" />--> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.CAMERA" android:required = "true"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" 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> <activity android:name=".HomeScreen" android:launchMode="singleTask"/> <activity android:name=".TaskDescription" /> <activity android:name=".TaskCompletionForm" android:configChanges="keyboardHidden|orientation"/> <service android:name=".WebSocketIntentService" /> <@R_301_338@-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.ignacio.androidchat.fileprovider" android:exported="false" android:grantUriPermissions="true"> <@R_301_338@-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application> </manifest>
file_paths.xml
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="my_images" path="Android/data/com.example.ignacio.androidchat/files/Pictures/" /> </paths>
解决方法
我假设在较旧的三星Android设备(我的情况下为api 17)上的相机应用程序需要格式为“file:/// …..”的uri.问题是文件uri格式导致Android Nougat(api 24和更高版本)抛出FileUriExposedException.
我得到了这个工作:
Uri imageUri; // N is for Nougat Api 24 Android 7 if (Build.VERSION_CODES.N <= android.os.Build.VERSION.SDK_INT) { // FileProvider required for Android 7. Sending a file URI throws exception. imageUri = FileProvider.getUriForFile(getContext(),"com.<your name here>.fileprovider",imageFile); } else { // For older devices: // Samsung Galaxy Tab 7" 2 (Samsung GT-P3113 Android 4.2.2,API 17) // Samsung S3 imageUri = Uri.fromFile(imageFile); }
理想的是只在Nougat或更高版本中使用FileProvider.
您可能希望降低Build.VERSION_CODES的api版本. YMMV,取决于您对文件uri曝光的容忍度.
有关Android Nougat中FileUriExposedException的注释,请参阅:Android Documentation.