1. 程式人生 > >Android--利用相機或相簿擷取使用者頭像(解決了miui無法擷取,以及部分機型拍照無返回Uri)【上】

Android--利用相機或相簿擷取使用者頭像(解決了miui無法擷取,以及部分機型拍照無返回Uri)【上】

宣告:

本文的Demo可用於從本地獲取使用者頭像時使用,解決了有些手機系統相機拍照後獲取不到拍攝照片的問題,以及解決小米miui系統呼叫系統裁剪圖片功能camera.action.CROP後崩潰或重新開啟app的問題。

主活動檔案ChooseImageMainActivity

package com.example.no_clay.demolist.ChooseImage;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import
android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.support.annotation.Nullable; import
android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.Gravity; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; import com.example.no_clay.demolist.R; import java.io.File; import java.io.IOException; import
cn.bmob.v3.Bmob; import cn.bmob.v3.datatype.BmobFile; import cn.bmob.v3.listener.SaveListener; import cn.bmob.v3.listener.UploadFileListener; /** * Created by 寒 on 2016/6/4. */ public class ChooseImageMainActivity extends AppCompatActivity { private ImageView imageView; private SelectPicPopupWindow menuWindow; private static final int REQUEST_CODE_PICK_IMAGE = 0; private static final int REQUEST_CODE_CAPTURE_CAMEIA = 1; private static final int RESIZE_REQUEST_CODE = 2; private static final String TAG = "ChooseImageMainActivity"; private Uri userImageUri;//儲存使用者頭像的uri private Context context = ChooseImageMainActivity.this; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.choose_image_main_layout); imageView = (ImageView) findViewById(R.id.choose_image_image); imageView.setOnClickListener(new View.OnClickListener() {//給ImageView設定點選監聽 @Override public void onClick(View v) { menuWindow = new SelectPicPopupWindow(context, new View.OnClickListener() { @Override public void onClick(View v) { menuWindow.dismiss(); switch (v.getId()){ case R.id.takePhotoBtn: { String state = Environment.getExternalStorageState(); if (state.equals(Environment.MEDIA_MOUNTED)) { Intent getImageByCamera = new Intent("android.media.action.IMAGE_CAPTURE"); startActivityForResult(getImageByCamera, REQUEST_CODE_CAPTURE_CAMEIA); } else { Toast.makeText(getApplicationContext(), "請確認已經插入SD卡", Toast.LENGTH_LONG).show(); } break; } case R.id.pickPhotoBtn: // Intent intent = new Intent(Intent.ACTION_PICK);//從相簿中選取圖片 Intent intent = new Intent("android.intent.action.GET_CONTENT");//從相簿/檔案管理中選取圖片 intent.setType("image/*");//相片型別 startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE); break; case R.id.cancelBtn:{ break; } } } }); menuWindow.showAtLocation(findViewById(R.id.mainLayout), Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Uri imageUri = null; if(resultCode == RESULT_CANCELED){ Toast.makeText(context,"獲取失敗",Toast.LENGTH_SHORT).show(); imageView.setImageBitmap(null);//預設的圖片 }else if(resultCode == RESULT_OK) {//選取成功後進行裁剪 if (requestCode == REQUEST_CODE_PICK_IMAGE) { //從相簿中選擇圖片作為頭像 imageUri = data.getData(); Log.d(TAG, "onActivityResult: " + imageUri); reSizeImage(imageUri); } else if (requestCode == REQUEST_CODE_CAPTURE_CAMEIA) { //使用相機獲取頭像 Log.d(TAG, "onActivityResult: from photo"); imageUri = data.getData(); Log.d(TAG, "onActivityResult: " + imageUri); if (imageUri == null) { //use bundle to get data Bundle bundle = data.getExtras(); if (bundle != null) { Bitmap bitMap = (Bitmap) bundle.get("data"); //get bitmap imageUri = Uri.parse(MediaStore.Images.Media. insertImage(getContentResolver(), bitMap, null,null)); Log.d(TAG, "onActivityResult: bndle != null" + imageUri); reSizeImage(imageUri); } else { Toast.makeText(getApplicationContext(), "Error", Toast.LENGTH_SHORT).show(); } } }else if(requestCode == RESIZE_REQUEST_CODE){ Log.d(TAG, "onActivityResult: " + userImageUri); showImage(userImageUri); } } } private void reSizeImage(Uri uri) {//重新剪裁圖片的大小 Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*"); intent.putExtra("crop", "true");//可以裁剪 intent.putExtra("aspectX", 1);//寬高比例 intent.putExtra("aspectY", 1); intent.putExtra("outputX", 100); intent.putExtra("outputY", 100); /** * 此方法返回的圖片只能是小圖片(測試為高寬160px的圖片) * 故將圖片儲存在Uri中,呼叫時將Uri轉換為Bitmap,此方法還可解決miui系統不能return data的問題 */ // intent.putExtra("return-data", true); // intent.putExtra("output", Uri.fromFile(new File("/mnt/sdcard/temp")));//儲存路徑 userImageUri = Uri.parse("file://"+ Environment.getExternalStorageDirectory().getPath() + "/" + "small.jpg"); intent.putExtra(MediaStore.EXTRA_OUTPUT, userImageUri); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); startActivityForResult(intent, RESIZE_REQUEST_CODE); } private void showImage(Uri uri) { Log.d(TAG, "showImage: "); try { Log.d(TAG, "showImage: " + uri.toString()); SharedPreferences.Editor editor = getSharedPreferences("image",MODE_PRIVATE).edit(); editor.putString("imageUri",uri.toString()); editor.commit();//儲存頭像的uri Bitmap photo = MediaStore.Images.Media.getBitmap(context .getContentResolver(), uri); imageView.setImageDrawable(new BitmapDrawable(photo)); Toast.makeText(context,"頭像設定成功",Toast.LENGTH_SHORT).show(); } catch (IOException e) { Toast.makeText(context,"頭像設定失敗",Toast.LENGTH_SHORT).show(); e.printStackTrace(); } } }

【註解】:

1.Environment.getExternalStorageState是用來獲取外部儲存裝置的狀態,即SD卡的狀態,這裡為大家推薦一篇博文:[Android中的Environment.getExternalStorageState使用]

(http://blog.csdn.net/yuzhiboyi/article/details/8645730)

2.android.media.action.IMAGE_CAPTURE為呼叫系統照相機

3.Itent.ACTION_PICK 、Intent.ACTION_GET_CONTENT

兩者都可以彈出一張選擇列表, 兩者都可以當作我們獲取手機本地資源的途徑,通過設定Intent.setType(String type);即可實現不同資源的選取,不同的是Intent.ACTION_GET_CONTENT會彈出對話方塊選擇資源的來源。常用的型別有:

   //選擇圖片 requestCode 返回的標識
  Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT); //"Android.intent.action.GET_CONTENT"
  innerIntent.setType(contentType); //檢視型別 String IMAGE_UNSPECIFIED = "image/*";
  Intent wrapperIntent = Intent.createChooser(innerIntent, null);
  ((Activity) context).startActivityForResult(wrapperIntent, requestCode);



  //視訊
  Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT);
  innerIntent.setType(contentType); //String VIDEO_UNSPECIFIED = "video/*";
  Intent wrapperIntent = Intent.createChooser(innerIntent, null);
  ((Activity) context).startActivityForResult(wrapperIntent, requestCode);



  //新增音訊
  Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT);
  innerIntent.setType(contentType); //String VIDEO_UNSPECIFIED = "video/*";
  Intent wrapperIntent = Intent.createChooser(innerIntent, null);
  ((Activity) context).startActivityForResult(wrapperIntent, requestCode);



  //錄音
  Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
  intent.setType(ContentType.AUDIO_AMR); //String AUDIO_AMR = "audio/amr";
  intent.setClassName("com.android.soundrecorder",
  "com.android.soundrecorder.SoundRecorder");
  ((Activity) context).startActivityForResult(intent, requestCode);

4.menuWindow.dismiss();//在點選空白處的時候彈出視窗消失

5.在onActivityResult(int requestCode, int resultCode, Intent data)中為什麼要寫出兩種方法來獲取相機拍照後的Uri?

前邊通過圖片選擇返回一個Uri,但是部分機型在拍照在Intent中返回的為Uri為空,於是我們需要將這些機型的獲取Uri方法寫出來,通過獲取儲存在bundle中的縮圖的Uri實現。(有些機型利用Bundle來返回照片資料)

6.reSizeImage(Uri uri)中為何不使用下列方法:

Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");//可以裁剪
intent.putExtra("aspectX", 1);//寬高比例
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 100);
intent.putExtra("outputY", 100);
intent.putExtra("return-data", true);
intent.putExtra("output", Uri.fromFile(new File("/mnt/sdcard/temp")));//儲存路徑
startActivityForResult(intent, RESIZE_REQUEST_CODE);

上述方法中,裁剪後的圖片通過Intent的putExtra(“return-data”,true)方法進行傳遞,miui系統問題就出在這裡,return-data的方式只適用於小圖,miui系統預設的裁剪圖片可能裁剪得過大,或對return-data分配的資源不足,造成return-data失敗。
解決思路是:裁剪後,將裁剪的圖片儲存在Uri中,在onActivityResult()方法中,再提取對應的Uri圖片轉換為Bitmap使用。
其實大家直觀也能感覺出來,Intent主要用於不同Activity之間通訊,是一種動態的小巧的資源佔用,類似於Http請求中的GET,並不適用於傳遞圖片之類的大資料。於是當A生成一個大資料要傳遞給B,往往不是通過Intent直接傳遞,而是在A生成資料的時候將資料儲存到C,B再去呼叫C,C相當於一個轉換的中介軟體。

即以下方法:

        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");//可以裁剪
        intent.putExtra("aspectX", 1);//寬高比例
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 100);
        intent.putExtra("outputY", 100);
        userImageUri = Uri.parse("file://"+ Environment.getExternalStorageDirectory().getPath() + "/" + "small.jpg");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, userImageUri);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        startActivityForResult(intent, RESIZE_REQUEST_CODE);

主介面佈局程式碼

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:id="@+id/mainLayout"
    android:backgroundTint="@color/bisque"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:textColor="@color/white"
        android:paddingLeft="20dp"
        android:gravity="center_vertical|left"
        android:background="@color/brown"
        android:textSize="20sp"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="選擇圖片" />

    <ImageView
        android:id="@+id/choose_image_image"
        android:layout_marginTop="50dp"
        android:layout_gravity="center_horizontal"
        android:layout_width="100dp"
        android:layout_height="100dp" />

</LinearLayout>

彈出視窗程式碼:

package com.example.no_clay.demolist.ChooseImage;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.PopupWindow;

import com.example.no_clay.demolist.R;


/**
 * Created by 寒 on 2016/6/4.
 */
class SelectPicPopupWindow extends PopupWindow {
    private Button takePhotoBtn, pickPhotoBtn, cancelBtn;
    private View mMenuView;

    @SuppressLint("InflateParams")
    public SelectPicPopupWindow(Context context, View.OnClickListener itemsOnClick) {
        super(context);
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mMenuView = inflater.inflate(R.layout.choose_image_layout_dialog_pic, null);
        takePhotoBtn = (Button) mMenuView.findViewById(R.id.takePhotoBtn);
        pickPhotoBtn = (Button) mMenuView.findViewById(R.id.pickPhotoBtn);
        cancelBtn = (Button) mMenuView.findViewById(R.id.cancelBtn);

        cancelBtn.setOnClickListener(itemsOnClick);
        pickPhotoBtn.setOnClickListener(itemsOnClick);
        takePhotoBtn.setOnClickListener(itemsOnClick);


        this.setContentView(mMenuView);

        this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);

        this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);

        this.setFocusable(true);

        this.setAnimationStyle(R.style.PopupAnimation);
        ColorDrawable dw = new ColorDrawable(0x80000000);

        this.setBackgroundDrawable(dw);

        mMenuView.setOnTouchListener(new View.OnTouchListener() {

            @Override
            @SuppressLint("ClickableViewAccessibility")
            public boolean onTouch(View v, MotionEvent event) {

                int height = mMenuView.findViewById(R.id.pop_layout).getTop();
                int y = (int) event.getY();
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    if (y < height) {
                        dismiss();
                    }
                }
                return true;
            }
        });
    }
}

彈出窗口布局choose_image_layout_dialog_pic.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/pop_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="#312E3F"
        android:gravity="center_horizontal"
        android:orientation="vertical" >

        <Button
            android:id="@+id/takePhotoBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dip"
            android:layout_marginRight="10dip"
            android:layout_marginTop="10dp"
            android:background="#373447"
            android:padding="10dp"
            android:text="拍照"
            android:textColor="#CEC9E7"
            android:textSize="18sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/pickPhotoBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dip"
            android:layout_marginRight="10dip"
            android:layout_marginTop="5dp"
            android:background="#373447"
            android:padding="10dp"
            android:text="從相簿選擇"
            android:textColor="#CEC9E7"
            android:textSize="18sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/cancelBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="15dip"
            android:layout_marginLeft="10dip"
            android:layout_marginRight="10dip"
            android:layout_marginTop="20dp"
            android:background="@android:color/white"
            android:padding="10dp"
            android:text="取消"
            android:textColor="#373447"
            android:textSize="18sp"
            android:textStyle="bold" />
    </LinearLayout>

</RelativeLayout>

相關推薦

Android--利用相機相簿擷取使用者頭像解決miui無法擷取以及部分機型拍照返回Uri

宣告:本文的Demo可用於從本地獲取使用者頭像時使用,解決了有些手機系統相機拍照後獲取不到拍攝照片的問題,以及解決小米miui系統呼叫系統裁剪圖片功能camera.action.CROP後崩潰或重新開啟app的問題。 主活動檔案ChooseImageMain

Android--利用相機相簿擷取使用者頭像解決miui無法擷取以及部分機型拍照返回Uri

宣告 本文的Demo可用於從本地獲取使用者頭像時使用,解決了有些手機系統相機拍照後獲取不到拍攝照片的問題,以及解決小米miui系統呼叫系統裁剪圖片功能camera.action.CROP後崩潰或重新開啟app的問題。 修改了部分機型拍照後返回的是縮圖的臨時

Android 呼叫相機相簿適配6.0

又好久沒有寫部落格了,好習慣不能斷,該寫點就得寫點,今天帶來的筆記是關於Android 專案呼叫系統相機 與呼叫系統相簿的之後拿到照片的基本操作,我感覺好多人還是不太熟悉的哈。專案相容 Android 5.0裝置、Android 6.0裝置、Android 7.0、Android 8.0

Android--利用Handler訊息轉發機制實現倒計時內含防止記憶體洩露處理

真正學會Handler必須要了解的相關概念 相關概念圖示: Message:儲存資訊的物件,被Handler線上程間轉發,實現執行緒間的通訊。 MessageQueue:以有序的方式排列的,等待處理的事件(Runnable或者Message)。

Android 利用Java實現壓縮與解壓縮zip、gzip支援中文路徑

  zip扮演著歸檔和壓縮兩個角色;gzip並不將檔案歸檔,僅只是對單個檔案進行壓縮,所以,在UNIX平臺上,命令tar通常用來建立一個檔案檔案,然後命令gzip來將檔案檔案壓縮。   Java I/O類庫還收錄了一些能讀寫壓縮格式流的類。要想提供壓縮功能,只要把它們包

android使用Java設計模式建造模式Builder模式的寫法:

建造者模式的定義 將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。 這裡給大家分析一下: 定義的前半句說,構造與表示分離,其實就是繼承(或實現)。 兩種工廠模式也都是為某個物件提供一個介面,而且無需指定它們的具體類。

iOS10訪問許可權的配置解決訪問奔潰問題包括相簿相機

這裡僅以相簿的為例: plist檔案裡面新增,Privacy - Photo Library Usage Description,Value值為描述,彈出的提示框會顯示出來。 修改plist 升到iOS10之後,需要設定許可權的有: 麥克風許可權:Privac

Delphi 調試連接 任意Android手機/平板/盒子要安裝Google USB Driver並且還有USB的相關許多文章

ogl .org blog broadcast 通過 並且 install 無法 設備 Delphi有時候無法連接調試一些手機,解決方案: 1.安裝Google USB Driver 2.通過設備管理器查看手機或平板USB的VID,PID 3.修改你的電腦上的andr

Unity 使用C/C++ 跨平臺終極解決方式PCiOSAndroid以及支持C/C++的平臺

log initial ava open tis called 文章 sharp strong PC的事實上根本不用說,畢竟C#和C++交互的文章已經夠多了,當然我

Unity 使用C/C++ 跨平臺終極解決方案PCiOSAndroid以及支持C/C++的平臺

細節 -h comment 個人 tle lan source 多說 sharp https://blog.csdn.net/fg5823820/article/details/47865741 PC的其實根本不用說,畢竟C#和C++交互的文章已經夠多了,當然我自認為經過幾

Android 屬性動畫Property Animation 完全解析

轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/38067475 1、概述 Android提供了幾種動畫型別:View Animation 、Drawable Animation 、Property Anima

linux驅動由淺入深系列:PBL-SBL1-(bootloader)LK-Android啟動過程詳解之一高通MSM8953啟動例項

本文轉載自:https://blog.csdn.net/radianceblau/article/details/73229005 對於嵌入式工程師瞭解晶片啟動過程是十分有必要的,在分析、除錯各種問題的時候都有可能涉及到這方面的知識。同時這部分知識也是比較複雜的,因為其中涉及到晶片內部架構,啟動各個階段軟體

Unity3d 旋轉相機檢視物體指令碼掛在相機上要檢視的物體作為中心點

using System.Collections; using System.Collections.Generic; using UnityEngine; public class CamRotate : MonoBehaviour { private float ClampYMin=1

利用lisp進行AutoCAD二次開發環境說明、檔案讀取、以及表格建立與寫值

今天學習的這個例子是lisp計算機語言程式設計,說到這門計算機語言還是大學的時候接觸的,不過那時候都是停留在瞭解的層面上,後面編寫AutoCAD二次開發程式幾乎是用的是C#。所以對lisp不熟,就別提關於lisp在AutoCAD方面的介面。而今天所以又撿起這麼計算機語言,是出

Android破解學習之路十四——Unity3D王牌大作戰破解

一、前言 今天帶來的是王牌大作戰的破解教程,遊戲下載的話,我是直接去TapTap官網下載的 支付寶內購破解用老套了,今天學點破解的新花樣吧!! 二、支付寶內購破解 支付寶的內購破解已經很熟悉了, 直接搜尋“9000”,之後找到程式碼,修改判斷條件即可,若不明白,請看我之前寫的部落格,Android破解

Android Webview完美支援播放各種視訊。解決無法播放優酷視訊的問題以及週末無法播放優酷視訊的問題

通常我們會有這樣的業務需求:手機端展示某個H5頁面,H5頁面來源可能是優酷、56、愛奇藝等某個視訊網站的一個視訊。使用者可以直接操作觀看。很簡單。但是很容易出現問題。比如屬性沒有處理好。會出現可以載入56、愛奇藝視訊都沒有問題  但是無法載入優酷視訊的bug。網上介紹的解決

[Android]AIDL詳解

1、概述 AIDL是一個縮寫,全稱是Android Interface Definition Language,也就是Android介面定義語言。是的,首先我們知道的第一點就是:AIDL是一種語言。既然是一種語言,那麼相應的就很自然的衍生出了一些問題: 為什麼要設

android usb otg模式轉換成host模式不使用otg線連線只用普通usb四線連線

把usb otg轉換成host接U盤。 開始除錯時,以為只要把OTG的配置去掉,即CONFIG_USB_MS_OTG遮蔽掉即可,但編譯燒錄後,插入和撥出U盤時發現提示 android_work: did not send uevent (0 0 (null)) U盤的燈也不亮,說明沒有上電。 後來搜

Android中xml佈局檔案中使用include引入佈局進行復用解決使用include佈局重疊顏色設定無效問題

使用include引入佈局的作用   提取重複的佈局程式碼,方便進行復用 如何使用   比如我們想要線上性佈局中建立三塊需要複用的佈局headview、centerview、butto

筆記Java8利用Lambda處理String[]轉String

//記錄一下相關的轉換,以備後續學習 public static void main(String[] args){    String[] a = stripAll("1","2","3","4");//org.apache.commons.lang3.StringUt