Android 調(diào)用系統(tǒng)功能實(shí)現(xiàn)圖片選擇器劣领,你可能會(huì)遇到的問(wèn)題匯總

圖片選擇器在手機(jī)應(yīng)用中屢見(jiàn)不鮮姐军,設(shè)置頭像、聊天傳圖等常見(jiàn)類(lèi)似場(chǎng)景都需要使用剖踊。為了保持不同設(shè)備上體驗(yàn)的一致性和較好的兼容性庶弃,比較穩(wěn)妥的做法是在應(yīng)用內(nèi)自實(shí)現(xiàn)相機(jī)拍照衫贬、相冊(cè)選圖和圖片裁剪功能德澈。但是,這個(gè)實(shí)現(xiàn)過(guò)程比較復(fù)雜固惯,費(fèi)時(shí)費(fèi)力梆造。更多時(shí)候陌知,或者說(shuō)在項(xiàng)目初期宝与,我們都會(huì)選擇直接調(diào)用系統(tǒng)提供的這些功能來(lái)完成一個(gè)圖片選擇器。然而厅目,由于安卓設(shè)備的多樣性贴捡,總會(huì)遇到各種各樣的兼容問(wèn)題忽肛。本文就來(lái)總結(jié)總結(jié),調(diào)用系統(tǒng)相機(jī)烂斋、相冊(cè)和裁剪功能實(shí)現(xiàn)圖片選擇器的過(guò)程中屹逛,我們需要注意的一些地方础废。

示例代碼


這里簡(jiǎn)單使用一個(gè)示例代碼,演示調(diào)用系統(tǒng)相機(jī)或相冊(cè)罕模,獲取圖片评腺,然后使用系統(tǒng)裁剪功能處理圖片,并顯示到一個(gè) ImageButton 視圖里面:

public class MainActivity extends FragmentActivity {

    public static final int REQUEST_CAMERA = 1;
    public static final int REQUEST_ALBUM = 2;
    public static final int REQUEST_CROP = 3;

    public static final String IMAGE_UNSPECIFIED = "image/*";

    private ImageButton mPictureIb;

    private File mImageFile;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mPictureIb = (ImageButton) findViewById(R.id.ib_picture);
    }

    public void onClickPicker(View v) {
        new AlertDialog.Builder(this)
                .setTitle("選擇照片")
                .setItems(new String[]{"拍照", "相冊(cè)"}, new OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        if (i == 0) {
                            selectCamera();
                        } else {
                            selectAlbum();
                        }
                    }
                })
                .create()
                .show();
    }
    
    private void selectCamera() {
        createImageFile();
        if (!mImageFile.exists()) {
            return;
        }

        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mImageFile));
        startActivityForResult(cameraIntent, REQUEST_CAMERA);
    }

    private void selectAlbum() {
        Intent albumIntent = new Intent(Intent.ACTION_PICK);
        albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED);
        startActivityForResult(albumIntent, REQUEST_ALBUM);
    }

    private void cropImage(Uri uri){
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, IMAGE_UNSPECIFIED);
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mImageFile));
        startActivityForResult(intent, REQUEST_CROP);
    }

    private void createImageFile() {
        mImageFile = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");
        try {
            mImageFile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(this, "出錯(cuò)啦", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (RESULT_OK != resultCode) {
            return;
        }
        switch (requestCode) {
            case REQUEST_CAMERA:
                cropImage(Uri.fromFile(mImageFile));
                break;

            case REQUEST_ALBUM:
                createImageFile();
                if (!mImageFile.exists()) {
                    return;
                }

                Uri uri = data.getData();
                if (uri != null) {
                    cropImage(uri);
                }
                break;

            case REQUEST_CROP:
                mPictureIb.setImageURI(Uri.fromFile(mImageFile));
                break;
        }
    }

}

效果如圖(不同設(shè)備淑掌,系統(tǒng)功能呈現(xiàn)有所不同):

看似完美蒿讥,你以為上述代碼就能結(jié)束了的話,那就大錯(cuò)特錯(cuò)啦抛腕!這里面還有一些兼容問(wèn)題要處理芋绸,還有一些地方需要特殊說(shuō)明。

拍照?qǐng)D片存儲(chǔ)問(wèn)題


調(diào)用系統(tǒng)相機(jī)實(shí)現(xiàn)拍照功能的核心代碼如下:

Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mImageFile));
startActivityForResult(cameraIntent, REQUEST_CAMERA);

其中 MediaStore.EXTRA_OUTPUT 數(shù)據(jù)表示兽埃,拍照所得圖片保存到指定目錄下的文件(一般會(huì)在 SD 卡中創(chuàng)建當(dāng)前應(yīng)用的目錄侥钳,并創(chuàng)建臨時(shí)文件保存圖片)。然后柄错,在 onActivityResult 方法中根據(jù)文件路徑獲取圖片舷夺。

如果不為 intent 添加該數(shù)據(jù)的話,將在 onActivityResult 的 intent 對(duì)象中返回一個(gè) Bitmap 對(duì)象售貌,通過(guò)如下代碼獲雀:

Bitmap bmp = data.getParcelableExtra("data");

值得注意的是,這里的 Bitmap 對(duì)象是拍照所得圖片的一個(gè)縮略圖颂跨,尺寸很懈疑臁!系統(tǒng)這么做也是充分考慮到應(yīng)用的內(nèi)存占用問(wèn)題恒削。試想一下池颈,如今手機(jī)設(shè)備中高清相機(jī)拍出來(lái)的照片,一張圖的大小高達(dá)十幾兆钓丰,如果返回這么大的圖片躯砰,內(nèi)存占用相當(dāng)嚴(yán)重,何況很多時(shí)候知識(shí)臨時(shí)使用而已携丁。所以琢歇,調(diào)用系統(tǒng)相機(jī)時(shí),一般都會(huì)添加 MediaStore.EXTRA_OUTPUT 參數(shù)梦鉴,避免返回 Bitmap 對(duì)象李茫。當(dāng)然,這么做也能保證應(yīng)用產(chǎn)生的數(shù)據(jù)肥橙,包括文件魄宏,都能存儲(chǔ)在應(yīng)用目錄下,方便清理緩存時(shí)統(tǒng)一清除存筏。

拍照?qǐng)D片旋轉(zhuǎn)問(wèn)題


部分手機(jī)宠互,比如三星手機(jī)塔次,調(diào)用系統(tǒng)相機(jī)拍照所得的照片可能會(huì)發(fā)生自動(dòng)旋轉(zhuǎn)問(wèn)題,常見(jiàn)為旋轉(zhuǎn) 90°名秀。所以励负,要求我們?cè)谂恼罩螅褂脠D片之前匕得,判斷圖片是否發(fā)生過(guò)旋轉(zhuǎn)继榆,如果是,要將照片旋轉(zhuǎn)回來(lái)汁掠。

這是獲取圖片旋轉(zhuǎn)角度的代碼:

/**
 * 獲取圖片旋轉(zhuǎn)角度
 * @param path 圖片路徑
 * @return
 */
private int parseImageDegree(String path) {
    int degree = 0;
    try {
        ExifInterface exifInterface = new ExifInterface(path);
        int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                degree = 90;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                degree = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                degree = 270;
                break;
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return degree;
}

這是根據(jù)指定角度旋轉(zhuǎn)圖片的代碼:

/**
 * 圖片旋轉(zhuǎn)操作
 *
 * @param bm 需要旋轉(zhuǎn)的圖片
 * @param degree 旋轉(zhuǎn)角度
 * @return 旋轉(zhuǎn)后的圖片
 */
private Bitmap rotateBitmap(Bitmap bm, int degree) {
    Bitmap returnBm = null;

    Matrix matrix = new Matrix();
    matrix.postRotate(degree);
    try {
        returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
    } catch (OutOfMemoryError e) {
    }
    if (returnBm == null) {
        returnBm = bm;
    }
    if (bm != returnBm) {
        bm.recycle();
    }
    return returnBm;
}

橫豎屏切換問(wèn)題


在部分手機(jī)略吨,調(diào)用系統(tǒng)拍照功能時(shí),可能會(huì)發(fā)生橫豎屏切換過(guò)程考阱,導(dǎo)致返回應(yīng)用時(shí)當(dāng)前 Activity 發(fā)生銷(xiāo)毀重建翠忠,各個(gè)生命周期又重新走了一遍。此時(shí)乞榨,一些應(yīng)用內(nèi)的變量數(shù)據(jù)可能丟失秽之,使用時(shí)容易發(fā)生空值異常,進(jìn)而導(dǎo)致 app 崩潰退出吃既。

為了避免這種現(xiàn)象考榨,我們需要在 AndroidManifest.xml 文件的對(duì)應(yīng) <activity> 標(biāo)簽中添加屬性:

android:configChanges="orientation|screenSize"

這樣,當(dāng)發(fā)生屏幕旋轉(zhuǎn)時(shí)鹦倚,不會(huì)導(dǎo)致 Activity 銷(xiāo)毀重建河质,而是執(zhí)行 onConfigurationChanged() 方法:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
}

調(diào)用系統(tǒng)裁剪問(wèn)題


示例中調(diào)用系統(tǒng)裁剪的代碼如下:

Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, IMAGE_UNSPECIFIED);
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mImageFile));
startActivityForResult(intent, REQUEST_CROP);

可以看出,調(diào)用系統(tǒng)裁剪功能震叙,需要設(shè)置一些 Extra 參數(shù)掀鹅,很多人容易在這里產(chǎn)生疑惑,不知如何取舍媒楼,如何設(shè)值乐尊。這里列舉一下常用的 Extra 名字、值類(lèi)型和作用:

  • crop:String 類(lèi)型數(shù)據(jù)匣砖,發(fā)送裁剪信號(hào)
  • aspectXaspectY:int 類(lèi)型數(shù)據(jù)科吭,設(shè)置裁剪框的 X 與 Y 值比例
  • outputXoutputY:int 類(lèi)型數(shù)據(jù)昏滴,設(shè)置裁剪輸出的圖片大小
  • scale:boolean 類(lèi)型數(shù)據(jù)猴鲫,設(shè)置是否支持裁剪縮放
  • return-data:boolean 類(lèi)型數(shù)據(jù),設(shè)置是否在 onActivityResult 方法的 intent 值中返回 Bitmap 對(duì)象
  • MediaStore.EXTRA_OUTPUT:Uri 類(lèi)型數(shù)據(jù)谣殊,設(shè)置是否將裁剪結(jié)果保存到指定文件中

需要注意的是:

第一拂共,設(shè)置 return-data 參數(shù)為 true 時(shí),返回的 Bitmap 對(duì)象也為縮略圖姻几,獲取方式與前面所述相機(jī)拍照獲取 Bitmap 的方式一致宜狐;

第二势告,調(diào)用系統(tǒng)相冊(cè)并裁剪時(shí),如果使用MediaStore.EXTRA_OUTPUT參數(shù)抚恒,Uri 盡量不要設(shè)置為源文件對(duì)應(yīng)的 Uri 值咱台,另做保存,不損壞系統(tǒng)相冊(cè)中的源圖文件俭驮;

第三回溺,根據(jù)經(jīng)驗(yàn),outputX 與 outputY 值設(shè)置太大時(shí)混萝,容易出現(xiàn)卡屏現(xiàn)象遗遵;

第四,可以不設(shè)置 outputX 與 outputY 參數(shù)逸嘀,使用戶(hù)根據(jù)自身按比例自由裁剪车要,就像示例代碼這樣。

setImageURI() 注意事項(xiàng)


你可能會(huì)用到 setImageURI() 方法給 ImageView 設(shè)置圖片內(nèi)容崭倘,這里也有一個(gè)地方需要注意翼岁。我們先看一下這個(gè)方法的源碼:

public void setImageURI(Uri uri) {
    if (mResource != 0 ||
            (mUri != uri &&
             (uri == null || mUri == null || !uri.equals(mUri)))) {
        updateDrawable(null);
        mResource = 0;
        mUri = uri;

        final int oldWidth = mDrawableWidth;
        final int oldHeight = mDrawableHeight;

        resolveUri();

        if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
            requestLayout();
        }
        invalidate();
    }
}

可以看到,這里的 uri 參數(shù)在內(nèi)部持有緩存變量司光,當(dāng)多次調(diào)用該方法而 uri 參數(shù)值不變時(shí)登澜,圖片展示內(nèi)容不變。問(wèn)題就在這飘庄,如果你多次拍照或裁剪保存的圖片文件路徑相同時(shí)脑蠕,雖然每次處理過(guò)后實(shí)際存儲(chǔ)的文件內(nèi)容發(fā)生變化,但由于路徑相同跪削,uri 參數(shù)一致谴仙,導(dǎo)致多次調(diào)用 setImageURI() 設(shè)置圖片內(nèi)容時(shí),ImageView 顯示內(nèi)容不變碾盐!這也是為什么示例代碼中我用時(shí)間戳處理圖片文件名的原因所在晃跺,保證每次存儲(chǔ)的圖片路徑不同。

根據(jù) Uri 獲取文件地址


有時(shí)候毫玖,我們需要根據(jù) Uri 獲取文件路徑掀虎。比如如果你不需要使用裁剪功能的話,調(diào)用系統(tǒng)相冊(cè)選擇圖片后返回的就是一個(gè) Uri 對(duì)象付枫,我們需要從這個(gè) Uri 對(duì)象中解析出對(duì)應(yīng)的圖片文件路徑烹玉,便于上傳至服務(wù)器等后續(xù)處理。

比如阐滩,這個(gè) Uri 對(duì)象可能是:

content://media/external/images/media/3066

很多朋友相信有過(guò)這樣的經(jīng)驗(yàn)二打,使用 toString() 或者 getPath() 方法獲取 Uri 對(duì)象所對(duì)應(yīng)的文件路徑,其實(shí)這是錯(cuò)誤的掂榔!通過(guò) getPath() 獲取的結(jié)果字符串是:

media/external/images/media/3066

而正確的獲取方式是:

private String parseFilePath(Uri uri) {
    String[] filePathColumn = { MediaStore.Images.Media.DATA };
    Cursor cursor = getContentResolver().query(uri, filePathColumn, null, null, null);
    cursor.moveToFirst();
    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
    String picturePath = cursor.getString(columnIndex);
    cursor.close();
    return picturePath;
}

其對(duì)應(yīng)的文件路徑應(yīng)該是這個(gè)樣子的:

/storage/emulated/0/Pictures/Screenshots/S70302-131606.jpg

Base64 文件編碼處理


現(xiàn)在很多網(wǎng)絡(luò)框架內(nèi)部都做了封裝處理继效,上傳圖片時(shí)只需要傳遞一個(gè)文件路徑即可症杏。但是,少數(shù)情況下瑞信,根據(jù)服務(wù)器需要厉颤,我們要對(duì)圖片文件字節(jié)流編碼后再上傳。這是使用 Base64 編碼并根據(jù)字節(jié)數(shù)組獲取字符串的處理過(guò)程:

public static String fileToBase64String(String filePath) {
    File photoFile = new File(filePath);
    try {
        FileInputStream fis = new FileInputStream(photoFile);
        ByteArrayOutputStream baos = new ByteArrayOutputStream(10000);
        byte[] buffer = new byte[1000];
        while (fis.read(buffer)!=-1) {
            baos.write(buffer);
        }
        baos.close();
        fis.close();
        return Arrays.toString(Base64.encode(baos.toByteArray(), Base64.DEFAULT));
    }catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

zip 壓縮文件處理


當(dāng)上傳多張圖片至服務(wù)器時(shí)凡简,為了提升傳輸效率走芋,往往會(huì)采用 zip 格式壓縮處理。這里提供一個(gè)遞歸壓縮代碼潘鲫,方便大家有需要的時(shí)候借鑒參考:

public String zipCompass(String filePath){
    File zipFile = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".zip");
    try{
        //指定了兩個(gè)待壓縮的文件翁逞,都在assets目錄中  
        String[] filenames = new String[]{ "activity_main.xml", "strings.xml" };
        FileOutputStream fos = new FileOutputStream(zipFile);
        ZipOutputStream zos = new ZipOutputStream(fos);
        int i = 1;
        //枚舉filenames中的所有待壓縮文件  
        while (i <= filenames.length){
            //從filenames數(shù)組中取出當(dāng)前待壓縮的文件名,作為壓縮后的名稱(chēng)溉仑,以保證壓縮前后文件名一致  
            ZipEntry zipEntry = new ZipEntry(filenames[i - 1]);
            //打開(kāi)當(dāng)前的zipEntry對(duì)象  
            zos.putNextEntry(zipEntry);

            FileInputStream is = new FileInputStream(filePath);
            byte[] buffer = new byte[8192];
            int count = 0;
            //寫(xiě)入數(shù)據(jù)  
            while ((count = is.read(buffer)) >= 0){
                zos.write(buffer, 0, count);
            }
            zos.flush();
            zos.closeEntry();
            is.close();
            i++;

        }
        zos.finish();
        zos.close();
        return zipFile.getAbsolutePath();
    }
    catch (Exception e){
        Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
        return null;
    }
}

添加系統(tǒng)權(quán)限


說(shuō)了這么多挖函,別忘了在 AndroidManifest.xml 文件中添加系統(tǒng)權(quán)限(前面示例代碼中沒(méi)有考慮到 Android 6.0 運(yùn)行時(shí)權(quán)限的問(wèn)題,實(shí)際使用時(shí)注意添加處理):

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末浊竟,一起剝皮案震驚了整個(gè)濱河市怨喘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌振定,老刑警劉巖必怜,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異后频,居然都是意外死亡梳庆,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)卑惜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)膏执,“玉大人,你說(shuō)我怎么就攤上這事露久「祝” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵毫痕,是天一觀的道長(zhǎng)征峦。 經(jīng)常有香客問(wèn)我,道長(zhǎng)消请,這世上最難降的妖魔是什么栏笆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮梯啤,結(jié)果婚禮上竖伯,老公的妹妹穿的比我還像新娘存哲。我一直安慰自己因宇,他們只是感情好七婴,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著察滑,像睡著了一般打厘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贺辰,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天户盯,我揣著相機(jī)與錄音,去河邊找鬼饲化。 笑死莽鸭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吃靠。 我是一名探鬼主播硫眨,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼巢块!你這毒婦竟也來(lái)了礁阁?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤族奢,失蹤者是張志新(化名)和其女友劉穎姥闭,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體越走,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡棚品,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了廊敌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片南片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖庭敦,靈堂內(nèi)的尸體忽然破棺而出疼进,到底是詐尸還是另有隱情,我是刑警寧澤秧廉,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布伞广,位于F島的核電站,受9級(jí)特大地震影響疼电,放射性物質(zhì)發(fā)生泄漏嚼锄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一蔽豺、第九天 我趴在偏房一處隱蔽的房頂上張望区丑。 院中可真熱鬧,春花似錦、人聲如沸沧侥。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)宴杀。三九已至癣朗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間旺罢,已是汗流浹背旷余。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扁达,地道東北人正卧。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像跪解,于是被迫代替她去往敵國(guó)和親穗酥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線程惠遏,因...
    小菜c閱讀 6,373評(píng)論 0 17
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,846評(píng)論 25 707
  • 如以上DEMO截圖所示效果节吮,我們對(duì)于這種類(lèi)似的功能肯定不算陌生抽高,因?yàn)檫@可以說(shuō)是實(shí)際開(kāi)發(fā)中一類(lèi)非常常見(jiàn)的功能需求了。...
    Machivellia閱讀 2,029評(píng)論 1 13
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理透绩,服務(wù)發(fā)現(xiàn)翘骂,斷路器,智...
    卡卡羅2017閱讀 134,637評(píng)論 18 139
  • 你走了帚豪, 如風(fēng)一般碳竟。 留下了深深的遺憾, 帶走了深深的...
    仰望星空腳踏實(shí)地abc閱讀 229評(píng)論 0 0