Android頭像上傳(本地相冊和調用系統相機)
市面上上的android應用目前大都包含有頭像上傳的功能,恰好在本次的項目中在完成頭像上傳的功能中遇到了一些問題,在此進行記錄,以供日後查閱友善.
1.所謂頭像上傳,是要指定你要上傳的方式的,比如:調用本地相冊,在相冊中進行選取(此方法本人是寫在了工具類中,是以需要傳入activity為參數)
//從相冊中選取照片
public void doPickPhotoFromGallery(Activity activity) {
final Intent intent = getPhotoPickIntent();
activity.startActivityForResult(intent, Constant.PHOTO_PICKED_WITH_DATA);
}
public Intent getPhotoPickIntent() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType("image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 80);
intent.putExtra("outputY", 80);
intent.putExtra("return-data", true);
return intent;
}
2.再比如,你想要調用系統的相機來進行拍照(聲明了兩個全局變量)
/*拍照的照片存儲位置*/
private static final File PHOTO_DIR = new File(Environment.getExternalStorageDirectory() + "/DCIM/Camera");
public File mCurrentPhotoFile;//照相機拍照得到的圖檔
//打開系統相冊
public void openSystemCamera(Activity activity) {
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED)) {//判斷是否有SD卡
doTakePhoto(activity);// 使用者點選了從照相機擷取
} else {
Toast.makeText(activity, "未裝載記憶體卡", Toast.LENGTH_SHORT).show();
}
}
/**
* 拍照擷取圖檔
*/
public void doTakePhoto(Activity activity) {
try {
// Launch camera to take photo for selected contact
PHOTO_DIR.mkdirs();// 建立照片的存儲目錄
mCurrentPhotoFile = new File(PHOTO_DIR, getPhotoFileName());// 給新照的照片檔案命名
Intent intent = getTakePickIntent(mCurrentPhotoFile);
intent.putExtra(Constant.CURRENT_PHOTO_FILE, mCurrentPhotoFile);
activity.startActivityForResult(intent, Constant.CAMERA_WITH_DATA);
} catch (Exception e) {
Log.e("TAG", "開啟系統相機出問題啦");
}
}
public Intent getTakePickIntent(File f) {
final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
return intent;
}
/**
* 用目前時間給取得的圖檔命名
*/
private String getPhotoFileName() {
Date date = new Date(System.currentTimeMillis());
SimpleDateFormat dateFormat = new SimpleDateFormat(
"'IMG'_yyyy-MM-dd HH:mm:ss");
return dateFormat.format(date) + ".jpg";
}
3.到這裡已經可以擷取到選擇的圖檔資訊了,下面該對圖檔進行編輯了,截取圖檔中的某一塊區域(這裡也是寫在工具類中的,是以照例還是傳入了activity參數)
(1)在圖庫中選取:
從MemberActivity界面–>到圖庫的選擇界面–>選擇某一個圖檔的某個區域–>攜帶bitmap的對象傳回MemberActivity(在onAcitivityResult中取到了bitmap對象,具體中間的操作過程我也不是很清楚….)
(2)調用系統相機進行拍照:
從MemberActivity界面–>系統相機界面–>拍照并确認–>回到MemberActivity的onActivityResult方法中,并走case Constant.CAMERA_WITH_DATA的流程(在這裡需要對intent進行非空判斷,如果不進行判斷的話會報空指針的錯誤,具體為什麼intent會為空就不得而知了,如果intent為null的話,就将File file置為null,并傳入下一步的doCropPhoto(),如果intent不為空,則擷取file傳入的值,再将這個值傳入到doCropPhoto()中去處理)–> doCropPhoto()對圖檔進行區域的選擇(相應的,這一步要判斷file值是否為空,因為上一步的傳入過程中存在file為空的情況)–>開啟系統的圖庫去對圖檔進行區域的選擇–>攜帶這選擇的bitmap傳回MemberActivity,并執行onActivityResult的方法.
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (resultCode != RESULT_OK)
return;
switch (requestCode) {
//調用了從圖庫選取的功能的時候會直接走這個流程
case Constant.PHOTO_PICKED_WITH_DATA: {// 調用Gallery傳回的
//在控件中顯示得到的bitmap
Bitmap photo = intent.getParcelableExtra("data");
break;
}
case Constant.CAMERA_WITH_DATA: {// 照相機程式傳回的,再次調用圖檔剪輯程式去修剪圖檔
File file = null;
if (intent != null) {
file = (File) intent.getSerializableExtra(Constant.CURRENT_PHOTO_FILE);
}
SPUtils.getInstance().doCropPhoto(file, MemberSettingActivity.this);
break;
}
}
}
public void doCropPhoto(File f, Activity activity) {
Intent intent = null;
if (f == null) {
intent = getCropImageIntent(Uri.fromFile(mCurrentPhotoFile));
} else {
intent = getCropImageIntent(Uri.fromFile(f));
}
try {
// 啟動gallery去剪輯這個照片
activity.startActivityForResult(intent, Constant.PHOTO_PICKED_WITH_DATA);
} catch (Exception e) {
}
}
/**
* Constructs an intent for image cropping. 調用圖檔剪輯程式
*/
public Intent getCropImageIntent(Uri photoUri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(photoUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 80);
intent.putExtra("outputY", 80);
intent.putExtra("return-data", true);
return intent;
}
3.順利的拿到bitmap的對象了,現在我們該做的就是把圖檔上傳到雲存儲中去了,我在這裡用的是七牛雲存儲,鑒于現在所在的公司條件有限,在沒有背景的情況下,上傳圖檔到七牛的過程中是遇到了一些問題的,下面簡單的介紹一下遇到的問題.
3.1.首先,在查閱了七牛中關于android上傳圖檔的文檔中,關于android上傳圖檔的介紹是非常簡單的,操作起來也确實不是很複雜.大概用到的代碼如下:
//在Application中對其進行的初始化(我是這麼做的,至于在别的地方行不行,我沒試)
Configuration config = new Configuration.Builder()
.chunkSize(256 * 1024) //分片上傳時,每片的大小。 預設256K
.putThreshhold(512 * 1024) // 啟用分片上傳閥值。預設512K
.connectTimeout(10) // 連結逾時。預設10秒
.responseTimeout(60) // 伺服器響應逾時。預設60秒
.recorder(recorder) // recorder分片上傳時,已上傳片記錄器。預設null
.recorder(recorder, keyGen) //keyGen 分片上傳時,生成辨別符,用于片記錄器區分是那個檔案的上傳記錄
.zone(Zone.zone0) // 設定區域,指定不同區域的上傳域名、備用域名、備用IP。
.build();
// 重用uploadManager。一般地,隻需要建立一個uploadManager對象
UploadManager uploadManager = new UploadManager(config);
data = <File對象、或 檔案路徑、或 位元組數組>
String key = <指定七牛服務上的檔案名,或 null>;
String token = <從服務端SDK擷取>;
uploadManager.put(data, key, token,
new UpCompletionHandler() {
@Override
public void complete(String key, ResponseInfo info, JSONObject res) {
//這裡就是上傳完成以後的回調(應該是吧?我是這麼了解的,不過我不确定)
}
}, null);
3.2 傳圖檔到伺服器上基本上就是上面的這幾行代碼,其實真正在進行上傳操作的隻有最後的幾行,就是uploadManager.putxxxx這些,當然了,如果用過的話,可能會對其中需要的幾個參數比較了解,但初次接觸的話可能确實會有些疑惑(反正我是懵逼了,尤其是在沒有背景的情況下).
key:就是你存入七牛雲的檔案的名稱,例如: ceshi.jpg(這個名字就看你自己想叫什麼了,阿貓阿狗的也行)
token:這裡是需要經過一定的算法以及需要你傳一些你的七牛帳号的參數的,如果有背景的話,可以讓他傳回給你.而如果巧的是沒有背景的話,這裡是需要你自己進行擷取的.(這個值不正确的話是無法上傳圖檔的)
擷取token的過程:在七牛的官網上下載下傳java的sdk–>将其中util目錄下的auth.java檔案複制到你自己的工程下–>在把auth.java複制過來以後,會有報錯,這時候把java的sdk下相關的類一起複制過來就可以了(這裡就不詳細的說了,就那麼幾個工具類,我相信大家都可以的).當然在完成這些以後,擷取token值也變得比較簡單了:
Auth auth = Auth.create(七牛個人賬戶的AccessKey,七牛個人賬戶的SecretKey);
//相當于在你的七牛帳号下建立的一個檔案夾吧,這個名稱貌似是唯一的,就是你的和别人的也不能重複(我也不确定,猜的)
String token = auth.uploadToken(七牛個人賬戶下的某個空間名稱);
3.3 上傳七牛的參數拿到了,下面就是上傳我們的bitmap對象了,因為上傳到七牛的資料這是有限制的,是以我們先把我們的bitmap轉成一個數組,然後進行上傳的操作.(這裡的photo就是上面的bitmap對象,我把他聲明成了一個全局變量)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] bytes = baos.toByteArray();
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
//開始上傳我們的圖檔了
uploadManager.put(bytes, key, token, new UpCompletionHandler() {
@Override
public void complete(String key, ResponseInfo info, JSONObject response) {
Log.e("TAG", "qiniu" + key + info);
//我沒有在這裡調用bitmap.recycle()的方法,是因為如果我調用的話,再次進行拍照擷取圖檔的話會報一個什麼什麼什麼的錯誤,我也不知道具體是什麼
}
}, null);
4.最後,在MemberActivity的onDestroy()中,加上了photo.recycle()的方法,其實我也不知道有沒有什麼卵用.基本上就到此為止了.當然,本人對于android的一些知識了解尚淺,歡迎大牛們予以指點,謝謝!