您好,登錄后才能下訂單哦!
小編給大家分享一下Android如何實現拍照選擇圖片并上傳功能,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
一、實現思路:
1.Android手機客戶端,拍照(或選擇圖片),然后上傳到服務器。
2.服務器端接收手機端上傳上來的圖片。
二、實現步驟:
項目結構:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="5dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="圖片預覽" /> <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="400dp" android:background="#fff" android:padding="1dp" android:scaleType="fitXY" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:orientation="horizontal"> <Button android:id="@+id/btnPhoto" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="拍照" /> <Button android:id="@+id/btnSelect" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="選擇" /> </LinearLayout></LinearLayout>
MainActivity.java
package com.qingshan.note;import androidx.annotation.NonNull;import androidx.annotation.RequiresApi;import androidx.appcompat.app.AppCompatActivity;import androidx.core.app.ActivityCompat;import androidx.core.content.ContextCompat;import android.Manifest;import android.app.AlertDialog;import android.content.ContentValues;import android.content.DialogInterface;import android.content.Intent;import android.content.pm.PackageManager;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Matrix;import android.net.Uri;import android.os.Build;import android.os.Bundle;import android.os.Environment;import android.provider.MediaStore;import android.provider.Settings;import android.view.View;import android.widget.Button;import android.widget.ImageView;import android.widget.Toast;import java.io.BufferedReader;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStream;import java.net.HttpURLConnection;import java.net.URL;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button btnPhoto, btnSelect; private Intent intent; private final int CAMERA = 1;//事件枚舉(可以自定義) private final int CHOOSE = 2;//事件枚舉(可以自定義) private final String postUrl = "http://qingshanboke.com/Home/AndoridUploadFile";//接收上傳圖片的地址 String photoPath = "";//要上傳的圖片路徑 private final int permissionCode = 100;//權限請求碼 //權限集合,對應在AndroidManifest.xml文件中添加配置 // <uses-permission android:name="android.permission.CAMERA" /> // <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> // <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> // <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> // <uses-permission android:name="android.permission.INTERNET"/> String[] permissions = new String[]{ Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.ACCESS_WIFI_STATE, Manifest.permission.INTERNET }; AlertDialog alertDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //6.0才用動態權限 if (Build.VERSION.SDK_INT >= 23) { checkPermission(); } btnPhoto = findViewById(R.id.btnPhoto); btnSelect = findViewById(R.id.btnSelect); btnPhoto.setOnClickListener(this); btnSelect.setOnClickListener(this); } //檢查權限 private void checkPermission() { List<String> permissionList = new ArrayList<>(); for (int i = 0; i < permissions.length; i++) { if (ContextCompat.checkSelfPermission(this, permissions[i]) != PackageManager.PERMISSION_GRANTED) { permissionList.add(permissions[i]); } } if (permissionList.size() <= 0) { //說明權限都已經通過,可以做你想做的事情去 } else { //存在未允許的權限 ActivityCompat.requestPermissions(this, permissions, permissionCode); } } //授權后回調函數 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); boolean haspermission = false; if (permissionCode == requestCode) { for (int i = 0; i < grantResults.length; i++) { if (grantResults[i] == -1) { haspermission = true; } } if (haspermission) { //跳轉到系統設置權限頁面,或者直接關閉頁面,不讓他繼續訪問 permissionDialog(); } else { //全部權限通過,可以進行下一步操作 } } } //打開手動設置應用權限 private void permissionDialog() { if (alertDialog == null) { alertDialog = new AlertDialog.Builder(this) .setTitle("提示信息") .setMessage("當前應用缺少必要權限,該功能暫時無法使用。如若需要,請單擊【確定】按鈕前往設置中心進行權限授權。") .setPositiveButton("設置", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { cancelPermissionDialog(); Uri packageURI = Uri.parse("package:" + getPackageName()); Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI); startActivity(intent); } }) .setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { cancelPermissionDialog(); } }) .create(); } alertDialog.show(); } //用戶取消授權 private void cancelPermissionDialog() { alertDialog.cancel(); } @Override public void onClick(View v) { switch (v.getId()) { //拍照按鈕事件 case R.id.btnPhoto: //方法一:這樣拍照只能取到縮略圖(不清晰) //intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); //startActivityForResult(intent, CAMERA); //方法二:指定加載路徑圖片路徑(保存原圖,清晰) String SD_PATH = Environment.getExternalStorageDirectory().getPath() + "/拍照上傳示例/"; SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); String fileName = format.format(new Date(System.currentTimeMillis())) + ".JPEG"; photoPath = SD_PATH + fileName; File file = new File(photoPath); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } //兼容7.0以上的版本 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { try { ContentValues values = new ContentValues(1); values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg"); values.put(MediaStore.Images.Media.DATA, photoPath); Uri tempuri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); if (tempuri != null) { intent.putExtra(MediaStore.EXTRA_OUTPUT, tempuri); intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); } startActivityForResult(intent, CAMERA); } catch (Exception e) { e.printStackTrace(); } } else { intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); Uri uri = Uri.fromFile(file); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); //指定拍照后的存儲路徑,保存原圖 startActivityForResult(intent, CAMERA); } break; //選擇按鈕事件 case R.id.btnSelect: intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(intent, CHOOSE); break; } } @RequiresApi(api = Build.VERSION_CODES.O) @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { // 調用照相機拍照 case CAMERA: if (resultCode == RESULT_OK) { //對應方法一:圖片未保存,需保存文件到本地// Bundle bundle = data.getExtras();// Bitmap bitmap = (Bitmap) bundle.get("data");// String savePath;// String SD_PATH = Environment.getExternalStorageDirectory().getPath() + "/拍照上傳示例/";// SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");// String fileName = format.format(new Date(System.currentTimeMillis())) + ".JPEG";// if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {// savePath = SD_PATH;// } else {// Toast.makeText(MainActivity.this, "保存失敗!", Toast.LENGTH_SHORT).show();// return;// }// photoPath = savePath + fileName;// File file = new File(photoPath);// try {// if (!file.exists()) {// file.getParentFile().mkdirs();// file.createNewFile();// }// FileOutputStream stream = new FileOutputStream(file);// bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);// Toast.makeText(MainActivity.this, "保存成功,位置:" + file.getAbsolutePath(), Toast.LENGTH_SHORT).show();// } catch (IOException e) {// e.printStackTrace();// } //對應方法二:圖片已保存,只需讀取就行了 try { FileInputStream stream = new FileInputStream(photoPath); Bitmap bitmap = BitmapFactory.decodeStream(stream); //預覽圖片 ImageView image = findViewById(R.id.imageView); image.setImageBitmap(bitmap); //上傳圖片(Android 4.0 之后不能在主線程中請求HTTP請求) File file = new File(photoPath); if (file.exists()) { new Thread(new Runnable() { @Override public void run() { //文本字段(用于驗證用戶身份) HashMap<String, String> form = new HashMap<String, String>(); form.put("username", "zhangqs"); form.put("password", "123456"); //圖片字段 HashMap<String, String> file = new HashMap<String, String>(); file.put(PathHelper.getFileNameFromPath(photoPath), photoPath); formUpload(postUrl, form, file); } }).start(); } } catch (FileNotFoundException e) { e.printStackTrace(); } } break; // 選擇圖片庫的圖片 case CHOOSE: if (resultCode == RESULT_OK) { try { Uri uri = data.getData(); photoPath = PathHelper.getRealPathFromUri(MainActivity.this, uri); Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri); //壓縮圖片 bitmap = scaleBitmap(bitmap, (float) 0.5); //預覽圖片 ImageView image = findViewById(R.id.imageView); image.setImageBitmap(bitmap); //上傳圖片(Android 4.0 之后不能在主線程中請求HTTP請求) File file = new File(photoPath); if (file.exists()) { new Thread(new Runnable() { @Override public void run() { //文本字段(用于驗證用戶身份) HashMap<String, String> form = new HashMap<String, String>(); form.put("username", "zhangqs"); form.put("password", "123456"); //圖片字段 HashMap<String, String> file = new HashMap<String, String>(); file.put(PathHelper.getFileNameFromPath(photoPath), photoPath); formUpload(postUrl, form, file); } }).start(); } } catch (IOException e) { e.printStackTrace(); } } break; } } //壓縮圖片 public Bitmap scaleBitmap(Bitmap origin, float ratio) { if (origin == null) { return null; } int width = origin.getWidth(); int height = origin.getHeight(); Matrix matrix = new Matrix(); matrix.preScale(ratio, ratio); Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false); return newBM; } //POST 表單提交 @RequiresApi(api = Build.VERSION_CODES.O) public static String formUpload(String posturl, Map<String, String> textMap, Map<String, String> fileMap) { String res = ""; HttpURLConnection conn = null; String BOUNDARY = "---------------------------123821742118716"; //boundary就是request頭和上傳文件內容的分隔符 try { URL url = new URL(posturl); conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setReadTimeout(30000); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); conn.setRequestMethod("POST"); conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)"); conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); OutputStream out = new DataOutputStream(conn.getOutputStream()); // text if (textMap != null) { StringBuffer buffer = new StringBuffer(); Iterator iter = textMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); String inputName = (String) entry.getKey(); String inputValue = (String) entry.getValue(); if (inputValue == null) { continue; } buffer.append("\r\n").append("--").append(BOUNDARY).append("\r\n"); buffer.append("Content-Disposition: form-data; name=\"" + inputName + "\"\r\n\r\n"); buffer.append(inputValue); } out.write(buffer.toString().getBytes()); } // file if (fileMap != null) { Iterator iter = fileMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); String inputName = (String) entry.getKey(); String inputValue = (String) entry.getValue(); if (inputValue == null) { continue; } File file = new File(inputValue); String filename = file.getName(); String contentType = ""; if (filename.endsWith(".jpg")) { contentType = "image/jpg"; } else if (filename.endsWith(".png")) { contentType = "image/png"; } else if (contentType == null || contentType.equals("")) { contentType = "application/octet-stream"; } StringBuffer buffer = new StringBuffer(); buffer.append("\r\n").append("--").append(BOUNDARY).append("\r\n"); buffer.append("Content-Disposition: form-data; name=\"" + inputName + "\"; filename=\"" + filename + "\"\r\n"); buffer.append("Content-Type:" + contentType + "\r\n\r\n"); out.write(buffer.toString().getBytes()); DataInputStream in = new DataInputStream(new FileInputStream(file)); int bytes = 0; byte[] bufferOut = new byte[1024]; while ((bytes = in.read(bufferOut)) != -1) { out.write(bufferOut, 0, bytes); } in.close(); } } byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes(); out.write(endData); out.flush(); out.close(); // 讀取返回數據 StringBuffer buffer = new StringBuffer(); BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line = null; while ((line = reader.readLine()) != null) { buffer.append(line).append("\n"); } res = buffer.toString(); reader.close(); reader = null; } catch (Exception e) { System.out.println("發送POST請求出錯。" + posturl); e.printStackTrace(); } finally { if (conn != null) { conn.disconnect(); conn = null; } } return res; }}
PathHelper.java
package com.qingshan.note;import android.annotation.SuppressLint;import android.content.ContentUris;import android.content.Context;import android.database.Cursor;import android.net.Uri;import android.os.Build;import android.provider.DocumentsContract;import android.provider.MediaStore;//Android 路徑輔助類public class PathHelper { //適配api19以下(不包括api19),根據uri獲取圖片的絕對路徑 public static String getRealPathFromUri(Context context, Uri uri) { int sdkVersion = Build.VERSION.SDK_INT; if (sdkVersion >= 19) { // api >= 19 return getRealPathFromUriAboveApi19(context, uri); } else { // api < 19 return getRealPathFromUriBelowAPI19(context, uri); } } /** * 適配api19以下(不包括api19),根據uri獲取圖片的絕對路徑 * * @param context 上下文對象 * @param uri 圖片的Uri * @return 如果Uri對應的圖片存在, 那么返回該圖片的絕對路徑, 否則返回null */ private static String getRealPathFromUriBelowAPI19(Context context, Uri uri) { return getDataColumn(context, uri, null, null); } /** * 適配api19及以上,根據uri獲取圖片的絕對路徑 * * @param context 上下文對象 * @param uri 圖片的Uri * @return 如果Uri對應的圖片存在, 那么返回該圖片的絕對路徑, 否則返回null */ @SuppressLint("NewApi") private static String getRealPathFromUriAboveApi19(Context context, Uri uri) { String filePath = null; if (DocumentsContract.isDocumentUri(context, uri)) { // 如果是document類型的 uri, 則通過document id來進行處理 String documentId = DocumentsContract.getDocumentId(uri); if (isMediaDocument(uri)) { // MediaProvider // 使用':'分割 String id = documentId.split(":")[1]; String selection = MediaStore.Images.Media._ID + "=?"; String[] selectionArgs = {id}; filePath = getDataColumn(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs); } else if (isDownloadsDocument(uri)) { // DownloadsProvider Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId)); filePath = getDataColumn(context, contentUri, null, null); } } else if ("content".equalsIgnoreCase(uri.getScheme())) { // 如果是 content 類型的 Uri filePath = getDataColumn(context, uri, null, null); } else if ("file".equals(uri.getScheme())) { // 如果是 file 類型的 Uri,直接獲取圖片對應的路徑 filePath = uri.getPath(); } return filePath; } private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { String path = null; String[] projection = new String[]{MediaStore.Images.Media.DATA}; Cursor cursor = null; try { cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst()) { int columnIndex = cursor.getColumnIndexOrThrow(projection[0]); path = cursor.getString(columnIndex); } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close(); } } return path; } private static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri.getAuthority()); } private static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri.getAuthority()); } //從路徑中提取文件名 public static String getFileNameFromPath(String path) { int start = path.lastIndexOf("/"); int end = path.lastIndexOf("."); if (start != -1 && end != -1) { return path.substring(start + 1, end); } else { return null; } }}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.qingshan.note"> <!-- 因為拍照需要寫入文件 所以需要申請讀取內存的權限 --> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.INTERNET"/> <application android:networkSecurityConfig="@xml/network_security_config" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:usesCleartextTraffic="true" 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>
\res\xml\network_security_config.xml
<?xml version="1.0" encoding="utf-8"?><network-security-config> <base-config cleartextTrafficPermitted="true" /> <domain-config cleartextTrafficPermitted="true" > <domain includeSubdomains="true">127.0.0.1</domain> <domain includeSubdomains="true">192.168.100.192</domain> <domain includeSubdomains="true">localhost</domain> <domain includeSubdomains="true">qingshanboke.com</domain> </domain-config></network-security-config>
服務器端接收(asp.net mvc 接收)
public ActionResult AndoridUploadFile() { var userName = Request.Params["username"]; var password = Request.Params["password"]; if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password)) { return Content("抱歉,用戶名和密碼錯誤!"); } //todo:身份驗證 var dir = PathHelper.GetMapPath("~/Uploadfiles/" + DateTime.Now.ToString("yyyy-MM")); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } for (int i = 0; i < Request.Files.Count; i++) { var path = Path.Combine(dir, DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpg"); if (Request.Files[i] != null) { Request.Files[i].SaveAs(path); } } return Content("{\"isSuccess\":true}"); }
三、注意事項
1.Android發起http請求時,默認請求地址需https,需要增加 network-security-config 配置來允許使用http。(詳見上面6.\res\xml\network_security_config.xml)
2.發起post提交時,往往需要做接口身份識別,需要將文本字段和圖片字段一起提交,構造表單時,需要 "Content-Type", "multipart/form-data; boundary..."。
3.拍照時,默認只能取到縮略圖,不夠清晰,若要取到原圖,需要在拍照時,傳入指定保存位置,在回調函數中只需讀取就可以了。
以上是“Android如何實現拍照選擇圖片并上傳功能”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。