編輯:關於Android編程
先來點雞湯:
Stay hungry,stay foolish
這句話的的解讀:我們必須了解自己的渺小。如果我們不學習,科技發展的速度會讓我們五年後被清空。所以,我們必須用初學者謙虛的自覺,饑餓者渴望的求知態度,來擁抱未來的知識。
CharSequence[] items = { "拍照", "圖庫" };
new AlertDialog.Builder(context).setTitle("請選擇:")
.setIcon(R.drawable.ic_choose_picture)
.setItems(items, new OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
switch (which) {
case 0:
// 調用拍照功能
// 創建File對象,用於存儲拍照後的對象
takePhotoImage = new File(Environment.getExternalStorageDirectory(),"take_photo_image.jpg");
try {
if (takePhotoImage.exists()) {
takePhotoImage.delete();
}
takePhotoImage.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
// 將File對象轉換成Uri對象
imageUri =Uri.fromFile(takePhotoImage);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// 指定圖片的輸出地址
intent.putExtra(MediaStore.EXTRA_OUTPUT,
imageUri);
startActivityForResult(intent, TAKE_PHOTO);
break;
case 1:
// 調用系統圖庫
// 創建File對象,用於存儲選擇圖庫後的圖片
File choosePhoto = new File(Environment.getExternalStorageDirectory(),"choose_photo.jpg");
try {
if (choosePhoto.exists()) {
choosePhoto.delete();
}
choosePhoto.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
// 將File對象轉換成Uri對象
imageUri = Uri.fromFile(choosePhoto);
Intent intent2 = new Intent("android.intent.action.GET_CONTENT");
intent2.setType("image/*");
intent2.putExtra("crop", "true");
intent2.putExtra("scale", true);
intent2.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
startActivityForResult(intent2, CROP_PHOTO);
break;
}
}
}).show();
以上代碼很簡單,就是創建一個對話框,有兩個item選項。一個是拍照、一個是圖庫。如下所示:
兩個item選項的功能都是為了生成一張圖片並設置到ImageView控件上。
拍照和從圖庫選擇圖片都先創建了一個File對象,用於存儲攝像頭拍下的圖片或者存儲從圖庫中選擇的圖片。
然後將它放在手機的根目錄下,我的手機是在內存設備的根目錄下,這個無所謂。然後調用Uri的fromFile()方法將File對象轉換成Uri對象。這個Uri對象標識著圖片的唯一地址。
如果點擊的是拍照,接著會構建出一個Intent對象,並將這個Intent的action指定為:MediaStZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcmUuQUNUSU9OX0lNQUdFX0NBUFRVUkWjrNTZtffTw0ludGVudLXEcHV0RXh0cmGjqKOpt723qNa4tqjNvMastcTK5LP2tdjWt6Os1eLA777NzO7I67jVuNW1w7W9tcRVcmm21M/zo6zX7rrztffTw3N0YXJ0QWN0aXZpdHlGb3JSZXN1bHSjqKOpwLTG9Lavu+62r6GjPC9wPg0K0vLOqsnPw+a1xLT6wuvKx8q508NzdGFydEFjdGl2aXR5Rm9yUmVzdWx0o6ijqcC0xvS2r7vutq+1xKOsy/nS1MXE1dWzybmmuvO74bvYtfdvbkFjdGl2aXR5UmVzdWx0o6ijqbe9t6ijrNKyvLTFxM3q1dW687vh09C94bn7t7W72LW9b25BY3Rpdml0eVJlc3VsdKOoo6m3vbeo1tCho8v50tTW2NC0uMO3vbeovs3E3LbUxcTV1brztcTNvMas1/a9+NK7sr21xLSmwO3By6Gjt723qMjnz8LL+cq+o7oNCjxwcmUgY2xhc3M9"brush:java;">
/**
* 在調用startActivityForResult的時候會回調該方法
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// 拍照
case TAKE_PHOTO:
if (resultCode == Activity.RESULT_OK) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, CROP_PHOTO);
}
break;
// 裁剪圖片
case CROP_PHOTO:
if (resultCode == Activity.RESULT_OK) {
try {
// 壓縮Bitmap對象
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inPurgeable = true;
options.inInputShareable = true;
bitmap=BitmapFactory.decodeStream(getActivity().getContentResolver().openInputStream(imageUri),null, options);
setImageData(bitmap);
if (bitmapEntities.size() == 1) {
adapter = new BitmapAdapter(context, bitmapEntities);
gv_Picture.setAdapter(adapter);
} else {
adapter.notifyDataSetChanged();
}
linear_Picture.addView(view_Picture, 1);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
}
}
上面說到如果用攝像頭拍照成功後會回調onActivityResult()方法,這時候會繼續構建Intent對象,把它的action指定為:
“com.android.camera.action.CROP”。
這個Intent是用於拍出的照片進行裁剪的。因為攝像頭比較大,而我們可能只希望截取其中的一小部分。然後給這個Intent設置上一些必要的屬性,並再調用startActivityForResult()來啟動裁剪程序。裁剪後的圖片同樣會輸出到手機根目錄下的圖片文件中。
===========================================
如果點擊的item選項是圖庫。那麼會調用系統的圖庫選擇圖片。在這裡,跟拍照時基本的操作沒有什麼太多的差別。這裡用到了一個小技巧,就是我們在調用startActivityForResult()方法的時候,給第二個參數傳入的值仍然是:CROP_PHOTO常量,這樣就可以復用之前調用攝像頭顯示圖片的邏輯了,不用再編寫第二遍顯示圖片的邏輯。
好了,以上的兩個item選項的操作都講完了,接下來就是關鍵的時刻了。
裁剪操作完成後,程序又會回調到onActivityResult方法中,這個時候就可以利用BItmapFactory的decodeStream()方法將存儲在手機根目錄下的圖片文件解析成Bitmap對象,然後把它設置到ImageView控件上顯示出來。
我在這裡用的是gridView控件顯示一些圖片。不過都是一樣的,在gridView設置adapter的時候,需要在自定義的Adapter中把Bitmap對象設置到ImageView控件上。一開始設置一兩張圖片的時候如下所示:
但是放的圖的一旦多一點,程序就直接崩潰了,看了一下logcat的錯誤日志。
一個醒目的Java.lang.OutOfMemoryError(內存溢出錯誤),最不想遇見的錯誤。說心裡話,蛋疼。困惑了有段時間,試了很多的方法,終於很好的做了一些有效的圖片壓縮方法優化內存溢出的問題,但是並不能徹底的解決內存溢出問題。所以有時候我們自己要對圖片的張數做一些限制。像釘釘的出差管理的圖片選擇最多允許選擇9張、微信發朋友圈發圖片最多允許9張。有時候需要一些限制才能解決一些無法避免的問題。
上面的發生內存溢出錯誤的代碼定位了一下,直接就定位到下面這一行,如下圖所示:
該行代碼如下:
bitmap=BitmapFactory.decodeStream(getActivity().getContentResolver().openInputStream(imageUri));
為什麼這行代碼會導致OOM呢?給大家講講:該行代碼的作用是用於從指定輸入流中解析、創建Bitmap對象。但是由於手機系統的內存比較小,如果不停的去解析、創建Bitmap對象,可能由於前面所創建的Bitmap所占用的內存還沒有回收,而導致程序運行時引發OutOfMemory錯誤。所以我們需要將Bitmap對象先進行壓縮,使用的時候可以降低對內存的占用,這樣就可以有效的解決這個問題。我的解決方法是將以上的代碼替換為下圖所示的代碼:
上圖所示的各行代碼解釋如下:
======
BitmapFactory.Options options = new BitmapFactory.Options();
該行代碼用來創建一個BitmapFactory.Options對象,且Options 只保存圖片尺寸大小,不保存圖片到內存。
======
options.inSampleSize = 8;
該行代碼是最關鍵的代碼。給大家點進去看一下源碼,源碼如下所示:
源碼的注釋給大家講講。
注釋說:如果該值設置為>1,就會請求解析器對原圖做二次抽樣,即二次解析,返回一個較小的圖片用來節省內存。二次抽樣樣本大小的像素尺寸,對應於一個解碼位圖的像素。舉個例子,如果inSampleSize == 4,會返回一個是原圖1/4高度和1/4寬度的圖像,和1/16像素的數量。對任何值< = 1的值都用=1來賦值。
以上源碼的注釋很好的說明了該行代碼的關鍵性。大家要有效避免OOM錯誤的話一定要記得加上哦!只有這樣,才能有效的節省Bitmap對象占用的內存。別忘記了!
======
options.inPreferredConfig = Bitmap.Config.RGB_565;
該行代碼是附加上圖片的Config參數,解析器或根據當前的參數配置進行對應的解析,這也可以有效減少加載的內存。
======
options.inPurgeable = true;
該行代碼作用:由此產生的位圖將分配它的像素,這樣他們可以被淨化系統需要回收的內存。
======
options.inInputShareable = true;
該行代碼的作用:inInputShareable屬性和inPurgeable 有關,當inPurgeable 屬性設置為false的時候,inInputShareable屬性就可以忽略。但是如果這兩個屬性都設置為true的時候,源碼的注釋這樣說:確定位圖可以共享一個參考輸入數據如果它必須深拷貝的話。好了這都不是什麼關鍵的,不設置也是可以的。
======
最後調用方法:
bitmap=BitmapFactory.decodeStream(getActivity().getContentResolver().openInputStream(imageUri),null, options);
該行代碼就是根據options的一些選項設置解析輸入流返回一個壓縮後的Bitmap對象。這時候使用bitmap的時候就可以有效的避免OOM了。下面附上我的項目的測試圖片給大家看,眼見為實嘛!如下圖:
好了,沒有報OOM的錯誤,9張圖片都成功的呈現在界面上。
小生做程序也有些許日子,從一個青澀的小白,慢慢的成長為了小有成就的程序猿,從不知名的碼農,到二三百人圈裡還有點小名氣的碼霸。 要說辛苦,可能每個程序心中都有各自的理解,大
Android:使用AppCompatAutoCompleteTextView:我們先看看實現的效果吧,也就是我們俗話說的自動提示功能。這裡我實現了點擊AppCompat
看到某些App裡面有讀取聯系人的功能,然後自己嘗試了一下。發現這個挺簡單的。然後自己就做了一個demo給大家,希望借這個demo可以讓大家學習一下怎麼實現讀取手機聯系人。
如今android N都已經出來了,作為一個android開發者如果還不知道如何使用android5.X的 RecyclerView未免有點說不過去了。RecyclerV