1. 程式人生 > >android呼叫系統相機和相簿上傳頭像

android呼叫系統相機和相簿上傳頭像

話說昨天的冰碴下得真心大,騎車回來的路上臉被打的生疼啊!清明小長假第一天,借這個時間把前兩天想記錄的一點內容補充上吧。

這篇文章主要記錄呼叫系統相機或者從系統相簿中選取照片然後上傳頭像,這是一個很平常的需求,網上的例子也很多,但是,(注意:前方高能預警!!!)我遇到了一個坑,選取的圖片在預覽框有時顯示,有時不顯示,這個怎麼破!網上的例子找遍了都不行,後來經過反覆測試,發現問題了,在跳轉到更改頭像頁面的時候我先通過網路獲取了一下之前的頭像,然後展示出來。問題就出在這裡,當之前沒有頭像的時候,這裡先通過glide顯示了一個error頭像代替,然後各種選取頭像在預覽框就不顯示了,但是如果之前有頭像併成功顯示了,那麼現在再選取圖片,預覽框是可以顯示的。這就很難搞了,不過最後還是找到了解決辦法,這裡先上一下其他的程式碼,不感興趣的直接看文末的解決辦法。

首先看一下佈局檔案:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:orientation="vertical">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize">
        <include layout="@layout/custom_actionbar"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center_vertical"
            android:padding="10dp"
            android:text="確定"
            android:textColor="@color/btn_blue_normal"
            android:layout_alignParentEnd="true"
            android:layout_marginRight="@dimen/activity_horizontal_margin"
            android:id="@+id/change_photo_tv_got" />
    </RelativeLayout>


    <ImageView
        android:id="@+id/change_photo_iv_scan"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:src="@drawable/user_name"/>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/divider_list"/>
    <Button
        android:id="@+id/change_photo_camera"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="拍一張"
        android:background="@drawable/btn_press_selector"
        android:layout_marginLeft="@dimen/activity_horizontal_margin"
        android:layout_marginRight="@dimen/activity_horizontal_margin"
        android:layout_marginTop="@dimen/activity_vertical_margin"/>
    <Button
        android:id="@+id/change_photo_pic"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="去相簿"
        android:background="@drawable/btn_press_selector"
        android:layout_marginLeft="@dimen/activity_horizontal_margin"
        android:layout_marginRight="@dimen/activity_horizontal_margin"
        android:layout_marginTop="@dimen/activity_vertical_margin"/>
</LinearLayout>

然後,在oncreate()方法中載入之前的頭像,我這裡是提前獲取了頭像存在了application中的實體類currentUser中

protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_change_photo);
        ButterKnife.bind(this);
        tvTitle.setText("更改頭像");
        tvGot.setVisibility(View.GONE);//先隱藏確定按鈕,當有新頭像輸入時才顯示
        //先從application獲取之前儲存好的user實體類的photo路徑,展示
        Glide.with(this)
                .load(TApplication.currentUser.getIvPhoto())
                .into(ivPhoto);
    }

下面是按鈕的點選事件:

@OnClick({R.id.change_photo_camera, R.id.change_photo_pic, R.id.iv_title_back, R.id.change_photo_tv_got})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.change_photo_camera:
                //呼叫系統相機,通過拍照獲取圖片
                takePictureByCamera(this, GET_PICTURE_BY_CAMRA);
                break;
            case R.id.change_photo_pic:
                //通過系統圖庫獲取圖片
                takePictureByPic(this,GET_PICTURE_BY_PIC);
                break;
            case R.id.change_photo_tv_got:
                //發起網路請求,將頭像存入資料庫
                //成功後顯示,並跳轉介面
                setPhoto(url, ivPhotoStr);
                break;
        }
    }

通過相簿獲取圖片:

    private void takePictureByPic(Context context, int requestCode) {
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            // 沒有獲得授權,申請授權
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
                // 返回值:
                //如果app之前請求過該許可權,被使用者拒絕, 這個方法就會返回true.
                //如果使用者之前拒絕許可權的時候勾選了對話方塊中”Don’t ask again”的選項,那麼這個方法會返回false.
                //如果裝置策略禁止應用擁有這條許可權, 這個方法也返回false.
                // 彈窗需要解釋為何需要該許可權,再次請求授權
                Toast.makeText(this, "請授權!", Toast.LENGTH_LONG).show();
                // 幫跳轉到該應用的設定介面,讓使用者手動授權
                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                Uri uri1 = Uri.fromParts("package", getPackageName(), null);
                intent.setData(uri1);
                startActivity(intent);
            } else {
                // 不需要解釋為何需要該許可權,直接請求授權
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STOORAGE_REQUEST_CODE);
            }
        } else {
            // 已經獲得授權,可以獲取圖片
            Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
            startActivityForResult(intent, requestCode);
        }
    }

通過相機獲取圖片的方法:

    public void takePictureByCamera(Context context, int requestCode) {
        if (ContextCompat.checkSelfPermission(context,
                Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions((Activity) context,
                    new String[]{Manifest.permission.CAMERA},
                    TAKE_PHOTO_REQUEST_CODE);
        } else {
            Intent intent = new Intent(
                    MediaStore.ACTION_IMAGE_CAPTURE, null);
            startActivityForResult(intent, requestCode);
        }
    }

然後是回撥方法:

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        try {
            if (requestCode == GET_PICTURE_BY_PIC) {//從相簿選取的回撥方法
                Uri uri = data.getData();//content://media/external/images/media/72876
                Bitmap bitmap1 = null;
                if (uri != null) {
                    String path = getUriPath(uri);//上邊獲取的uri不是真實路徑,通過此方法轉換
                    try {
                        bitmap1 = BitmapFactory.decodeFile(path);
                        ivPhoto.setImageBitmap(bitmap1);//在預覽框顯示選擇的圖片,問題就在這裡,有時候顯示,有時候不顯示
                        ivPhotoStr = bitmapToBase64(bitmap1);//往伺服器上傳照片,將照片轉換成base64
                        tvGot.setVisibility(View.VISIBLE);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            if (requestCode == GET_PICTURE_BY_CAMRA) {//通過相機選取的回撥
                Uri uri = data.getData();
                if (uri == null) {
                    Bundle pBundle = data.getExtras(); //從intent物件中獲取資料,
                    if (pBundle != null) {
                        Bitmap mBitmap = (Bitmap) pBundle.get("data"); //get bitmap
                        ivPhoto.setImageBitmap(mBitmap);//在預覽框顯示選擇的圖片,問題就在這裡,有時候顯示,有時候不顯示
                        ivPhotoStr = bitmapToBase64(mBitmap);//往伺服器上傳照片,將照片轉換成base64
                        tvGot.setVisibility(View.VISIBLE);
                        Log.i("", "onActivityResult: bitmap" + ivPhotoStr);
                    } else {
                        Toast.makeText(getApplicationContext(), "error", Toast.LENGTH_LONG).show();
                        return;
                    }
                } else {
                    ImageCompress.CompressOptions options = new ImageCompress.CompressOptions();
                    options.maxHeight = 200;
                    options.maxWidth = 200;
                    options.uri = data.getData();

                    ImageCompress imageCompress = new ImageCompress();
                    Bitmap mBitmap = imageCompress.compressFromUri(this, options);
                    if (mBitmap != null) {
                        ivPhoto.setImageBitmap(mBitmap);//在預覽框顯示選擇的圖片,問題就在這裡,有時候顯示,有時候不顯示
                        ivPhotoStr = bitmapToBase64(mBitmap);//往伺服器上傳照片,將照片轉換成base64
                        tvGot.setVisibility(View.VISIBLE);
                        Log.i("", "onActivityResult: ivPhotoStr" + ivPhotoStr);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

看一下getUriPath()方法:

    private String getUriPath(Uri uri) {
        String data = null;
        if (null == uri)
            return null;
        final String scheme = uri.getScheme();
        if (scheme == null)
            data = uri.getPath();
        else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
            data = uri.getPath();
        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
            Cursor cursor = getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);
            if (null != cursor) {
                if (cursor.moveToFirst()) {
                    int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
                    if (index > -1) {
                        data = cursor.getString(index);
                    }
                }
                cursor.close();
            }
        }
        return data;
    }

然後把轉換成base64 的方法也貼一下吧:

 public static String bitmapToBase64(Bitmap bitmap) {
        String result = null;
        ByteArrayOutputStream baos = null;
        try {
            if (bitmap != null) {
                baos = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
                baos.flush();
                baos.close();

                byte[] bitmapBytes = baos.toByteArray();
                result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (baos != null) {
                    baos.flush();
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

最後,將選擇好的照片提交至伺服器:

    private void setPhoto(final String url, final String ivPhotoStr) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    OkHttpClient client = new OkHttpClient();
                    RequestBody requestBody = new FormBody.Builder()
                            .add("_id", TApplication.currentUser.get_id())
                            .add("photo", ivPhotoStr)
                            .build();
                    Request request = new Request.Builder()
                            .url(url)
                            .post(requestBody)
                            .build();

                    Response response = client.newCall(request).execute();
                    if (response.isSuccessful()) {
                        String s = response.body().string();
                        Log.i("", "run: setPhoto" + s);
                        Message message = handler.obtainMessage();
                        message.what = 1;
                        message.obj = s;
                        handler.sendMessage(message);
                    } else {
                        Log.i("", "run: setPhoto" + response.body().string());
                        Message message = handler.obtainMessage();
                        message.what = 0;
                        handler.sendMessage(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }).start();
    }

好了,程式碼很簡單,但就是這個程式碼,出現了文章開頭說的那個問題,經過反覆測試,問題是解決了,如下:

protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_change_photo);
        ButterKnife.bind(this);
        tvTitle.setText("更改頭像");
        tvGot.setVisibility(View.GONE);//先隱藏確定按鈕,當有新頭像輸入時才顯示
        //這裡是個大坑啊,寫滿了血淚史,
        // 如果之前沒有頭像的話,這裡就不用載入頭像了,如果載入了會導致後邊選擇圖片後不能預覽,不在ivPhoto顯示,具體原因不清楚
        //在這裡加入一個判斷來顯示之前的頭像,如果之前有則顯示
        if (!TApplication.currentUser.getIvPhoto().equals(Path.KEY_MAIN_PHOTO_PATH)){
            Glide.with(this)
                    .load(TApplication.currentUser.getIvPhoto())
                    .into(ivPhoto);
        }else {
            //之前沒有頭像,則這裡不顯示
        }
    }
問題是解決了,但是至於為什麼,一直沒有弄懂,如果有哪位大神明白,請留言告訴我,在此謝過了害羞