Android從系統(tǒng)調(diào)用相冊O(shè)kHttp上傳到服務(wù)器(activity數(shù)據(jù)傳遞)

Android從系統(tǒng)調(diào)用相冊O(shè)kHttp上傳到服務(wù)器(activity數(shù)據(jù)傳遞)

想寫技術(shù)博客已經(jīng)好久,今天終于下定決心堅持一周一個小博客淑际,我是一名安卓工程師鹰霍,工作剛剛一個月,水平有限炊昆,此文章是結(jié)合郭霖大神的《第一行代碼》以及自己參考網(wǎng)絡(luò)大神上的一些參考代碼結(jié)合起來的,在自己項目中進行調(diào)用威根,雖然有些雜亂凤巨,但是也算是基本的實現(xiàn)了功能。

下面先來展示一下功能截圖

功能展示1.jpg
功能展示2.jpg

功能流程相信各位也都能看懂洛搀,在第一個注冊信息完成后點擊下一步后繼續(xù)完成第二個頁面的注冊信息敢茁,然后將注冊信息上傳到服務(wù)器。

我也是第一次工作第一次自己進行獨立開發(fā)留美,所以可能會走不少彎路彰檬,但是總算功能能夠?qū)崿F(xiàn)了。
下面來給大家展示一下代碼谎砾,我會著重將一些重要的代碼展示出來

牽扯到的知識點

  • Android調(diào)用系統(tǒng)相冊及相機(隱性intent)
  • ContentProvider
  • okHttp
  • popupWindow
  • Bundle

代碼講解

為了能夠更好的點擊btn彈出相機或者相冊逢倍,我自定義了一個popupWindow,這個如果你不想寫景图,可以百度得到较雕。

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_margin="10dp"
        android:orientation="vertical"
        android:paddingBottom="10dp">

        <Button
            android:id="@+id/btn_pop_album"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:background="#ffff"
            android:text="本地相冊"
            android:textSize="18sp" />

        <Button
            android:id="@+id/btn_pop_camera"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:background="#ffff"
            android:text="相機拍攝"
            android:textSize="18sp" />

        <Button
            android:id="@+id/btn_pop_cancel"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:layout_marginTop="10dp"
            android:background="#ffff"
            android:text="取消"
            android:textSize="18sp" />
    </LinearLayout>

</RelativeLayout>

>

點擊popupWindow調(diào)用相機或相冊


View popView = View.inflate(this, R.layout.popup_choose_pic, null);
        Button btnPopAlbum = (Button) popView.findViewById(R.id.btn_pop_album);
        Button btnPopCamera = (Button) popView.findViewById(R.id.btn_pop_camera);
        Button btnPopCancel = (Button) popView.findViewById(R.id.btn_pop_cancel);
        //獲取屏幕寬高
        int widthPixels = getResources().getDisplayMetrics().widthPixels;
        int heightPixels = getResources().getDisplayMetrics().heightPixels * 1 / 3;
        final PopupWindow popupWindow = new PopupWindow(popView, widthPixels, heightPixels);
        popupWindow.setAnimationStyle(R.style.anim_popup_dir);
        popupWindow.setFocusable(true);
        //點擊popup外部消失
        popupWindow.setOutsideTouchable(true);
        //消失時屏幕變?yōu)榘胪该?        popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                WindowManager.LayoutParams params = getWindow().getAttributes();
                params.alpha = 1.0f;
                getWindow().setAttributes(params);
            }
        });
        //出現(xiàn)時屏幕變?yōu)橥该?        WindowManager.LayoutParams params = getWindow().getAttributes();
        params.alpha = 0.5f;
        getWindow().setAttributes(params);
        popupWindow.showAtLocation(popView, Gravity.BOTTOM, 0, 50);
        btnPopAlbum.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                popupWindow.dismiss();
                //調(diào)用相機
                invokeAlbum();
            }
        });
        btnPopCamera.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                popupWindow.dismiss();
                //打開相機
                openCarema();
            }
        });
        btnPopCancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                popupWindow.dismiss();
            }
        });


可以直接拷貝到xml里面看預(yù)覽圖

下面我們就著重講解點擊頭像這個功能邏輯

其實對于調(diào)用相冊以及相機這幾個功能,許多的API我也不是特別了解挚币,也不能詳細的跟大家解釋一下亮蒋,在這里我將我拷貝這些代碼的時候遇到的坑跟大家說下-------功能摘自《第一行代碼第二版》相機相冊那個章節(jié)。

調(diào)用相冊

private void invokeAlbum() {
        //動態(tài)申請危險時權(quán)限忘晤,運行時權(quán)限
        if (ContextCompat.checkSelfPermission(HgCompleteInfoActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
                PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(HgCompleteInfoActivity.this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        } else {
            openAlbum();
        }
    }
 private void openAlbum() {
        Intent intent = new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent, CHOOSE_PHOTO);
    }

在這里先進行了動態(tài)時權(quán)限宛蚓,這是6.0之后支持的激捏,具體的可以看郭霖的blog设塔,目前著重實現(xiàn)功能

/**
     * 動態(tài)獲取到的權(quán)限后的重寫
     *
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    openAlbum();
                } else {
                    Toast.makeText(HgCompleteInfoActivity.this, "you denied the permission", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }

這里是動態(tài)獲取到權(quán)限后的重寫方法,如果不夠理解,可以想一下
app安裝時軟件介紹會解釋獲取哪些權(quán)限闰蛔,那些權(quán)限是屬于manifests里注冊的痕钢,而動態(tài)獲取權(quán)限時,當(dāng)你第一次打開app時序六,比如需要獲取你的地理位置任连,你點了拒絕,會彈出上面方法里面case1-->else邏輯例诀。

  @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            
            case CHOOSE_PHOTO:
                if (resultCode == RESULT_OK) {
                    //判斷手機系統(tǒng)版本號
                    if (Build.VERSION.SDK_INT >= 19) {
                        handleImageOnKitKat(data);
                    } else {
                        handleImageBeforeKitKat(data);
                    }
                }
                break;
        }
    }
 private void handleImageBeforeKitKat(Intent data) {
        Uri uri = data.getData();
        String imagePath = getImagePath(uri, null);
        displayImage(imagePath);
    }

    private void handleImageOnKitKat(Intent data) {
        String imagePath = null;
        Uri uri = data.getData();
        //Log.i("uri", uri + "");
        if (DocumentsContract.isDocumentUri(HgCompleteInfoActivity.this, uri)) {
            //如果是document類型的uri随抠,則通過document id 處理
            String docId = DocumentsContract.getDocumentId(uri);
            Log.i("type of document", docId);
            if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
                String id = docId.split(":")[1];//解析出數(shù)字格式的id
                Log.i("type of document id", id);
                String selection = MediaStore.Images.Media._ID + "=" + id;
                Log.i("selection", selection);
                imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
            } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
                Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
                imagePath = getImagePath(contentUri, null);
            }
        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
            //如果是content類型的uri,就用普通方式處理
            imagePath = getImagePath(uri, null);
        } else if ("file".equalsIgnoreCase(uri.getScheme())) {
            //如果是file類型的Uri繁涂,直接獲取圖片路徑
            imagePath = uri.getPath();
        }
        displayImage(imagePath);
    }
private String getImagePath(Uri uri, String selection) {
        String path = null;
        //通過uri和selection來獲取真實的圖片路徑
        Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
        if (cursor != null) {
            if (cursor.moveToNext()) {
                path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
            }
            cursor.close();
        }
        return path;
    }
 private void displayImage(String imagePath) {
        if (imagePath != null) {
            bitmap = BitmapFactory.decodeFile(imagePath);
            headFile = saveMyBitmap(bitmap, "head");
            //保存file到sp
            saveFile(headFile.getName());
            Glide.with(this).asBitmap().load(headFile).thumbnail(0.1f).into(civHead);
        } else {
            Toast.makeText(HgCompleteInfoActivity.this, "failed to get image ", Toast.LENGTH_SHORT).show();
        }
    }
//將bitmap轉(zhuǎn)化為png格式
    public File saveMyBitmap(Bitmap mBitmap, String prefix) {
        File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
        File file = null;
        try {
            file = File.createTempFile(
                    prefix,  /* prefix */
                    ".jpg",         /* suffix */
                    storageDir      /* directory */
            );
            FileOutputStream fos = new FileOutputStream(file);
            mBitmap.compress(Bitmap.CompressFormat.JPEG, 10, fos);
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return file;
    }
    /**
     * 保存file到sp
     *
     * @param fileName
     */
    private void saveFile(String fileName) {
        SharedPreferences sp = getSharedPreferences("image", MODE_PRIVATE);
        SharedPreferences.Editor edit = sp.edit();
        edit.putString(HEAD_KEY, fileName);
        //提交edit
        edit.commit();
        Log.i(TAG, "saveFile: 保存成功" + sp.getString("head", null));
    }

這是阻擾我時間最多的邏輯部分拱她,首先解釋一下這些代碼的邏輯

1.點擊獲取到的相冊顯示到我上圖中的CircleImageView(記得一定要壓縮,不然拍完照返回照片到ImageView會特別的慢扔罪,在這里我做的也不夠好秉沼,所以不展開講)
2.然后自己寫了兩個方法,savaFile和savaMyBitmap
3.在savaMyBitmap方法中矿酵,首先獲取了系統(tǒng)相冊的地址唬复,然后每次我拍下照片或者選擇照片時,都進行簡單的壓縮全肮,因為圖片要上傳到服務(wù)器進行審核管理敞咧,做成微信頭像之類的超級壓縮方法有損畫質(zhì),所以我只是進行了簡單的壓縮上傳最后寫成一個文件辜腺。(在第二個頁面的時候可能會有幾個問題妄均,三個ImageView即是三個bitmap,三個File文件哪自。如何判斷及正確的顯示丰包,我們可以定義成全局變量,因為都是點擊事件壤巷,所以bitmap會在點擊后修改邑彪,然后保存下來。
4.在savaFile中胧华,我靈機一動(哈哈)寄症,想到了SharedPreferences這個神奇功能,我們沒有必要用sp去存file矩动,因為沒有那個方法有巧,我們可以將名字存起來啊,edit.putString()中的HEAD_KEY就是我自己定的方法悲没。你可以把sp當(dāng)成一個map篮迎,key是不會變的,但是value會變,所以理論上不管我們點多少次都會改變甜橱。
5.這樣文件就保存在本地了(可是不知道為啥我找不到,但是上傳到服務(wù)器里可以顯示)逊笆。

調(diào)用相機

private void openCarema() {
        //創(chuàng)建File對象,用于存儲拍照后的照片
        File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
        if (outputImage.exists()) {
            outputImage.delete();
        }
        try {
            outputImage.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (Build.VERSION.SDK_INT >= 24) {
            imageUri = FileProvider.getUriForFile(HgCompleteInfoActivity.this, "com.qryl.qrylyh.activity.login.complete.fileprovider", outputImage);
        } else {
            imageUri = Uri.fromFile(outputImage);
        }
        //啟動相機程序
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        startActivityForResult(intent, TAKE_PHOTO);
    }

這里不多贅述岂傲,調(diào)用Uri的邏輯功能代碼都是郭霖的难裆,我是cv戰(zhàn)士。

 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case TAKE_PHOTO:
                if (resultCode == RESULT_OK) {
                    //將拍攝的圖片顯示出來
                    try {
                        bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                        headFile = saveMyBitmap(bitmap, "head");
                        //保存file到sp
                        saveFile(headFile.getName());
                        Glide.with(this).asBitmap().load(headFile).thumbnail(0.1f).into(civHead);
                        Log.i("wechat", "壓縮后圖片的大小" + ("字節(jié)碼:" + " 寬度為:" + bitmap.getWidth() + " 高度為:" + bitmap.getHeight()));
                        Log.i(TAG, "File:" + headFile.getName() + " 路徑:" + headFile.getAbsolutePath());
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }
                break;
                  }
    }


和上面的方法基本都一樣镊掖。

使用Bundle以及SharedPreferences的理由

因為我要把第一頁的數(shù)據(jù)全部保存下來乃戈,全部在第二個頁面點擊注冊時一起上傳,這樣的話只是請求一次服務(wù)器亩进,所以我想到了sp方法將文件名字存儲起來偏化,在第二個頁面直接調(diào)用File方法把文件取出來即可
而Bundle只是為了區(qū)別分開,本來我是打開實現(xiàn)serializable的一個Map工具類集合進行數(shù)據(jù)的傳遞镐侯,技術(shù)有限侦讨,老是異常,就想到了用File存儲的方法

其他注冊信息Bundle方法

  /**
     * 傳遞數(shù)據(jù)到下個頁面
     */
    private void putExtra() {
        Intent intent = new Intent(HgCompleteInfoActivity.this, CompletePicActivity.class);
        //傳遞數(shù)據(jù)
        Bundle bundle = new Bundle();
        //bundle.putByteArray("head", bytes);
        bundle.putString("name", ageDialogText);
        bundle.putString("identity", identityDialogText);
        bundle.putString("gender", genderDialogText);
        bundle.putString("age", ageDialogText);
        bundle.putString("workexperience", workExperienceDialogText);
        bundle.putString("begoodat", beGoodAtWorkDialogText);
        bundle.putString("localservice", null);
        intent.putExtras(bundle);
        startActivity(intent);
    }


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

        Bundle bundle = getIntent().getExtras();

        String name = (String) bundle.get("name");
        String indentity = (String) bundle.get("identity");
        String gender = (String) bundle.get("gender");
        String age = (String) bundle.get("age");
        String workexperience = (String) bundle.get("workexperience");
        String begoodat = (String) bundle.get("begoodat");
        String localservice = (String) bundle.get("localservice");

        //dataMap.put("head", head.toString());
        dataMap.put("name", name);
        dataMap.put("indentity", indentity);
        dataMap.put("gender", gender);
        dataMap.put("age", age);
        dataMap.put("workexperience", workexperience);
        dataMap.put("begoodat", begoodat);
        dataMap.put("localservice", localservice);

    }

這沒啥好說的苟翻,第二個頁面直接取出來韵卤,我為了以后后期方便維護,定義了一個HashMap,如果沒有此需求可以直接取出來當(dāng)成全局變量進行調(diào)用即可崇猫。

調(diào)用圖片上傳的拓展

不知道大家是不是還記得第二個頁面有三個上傳照片的圖片沈条,在剛才我也提過,如何在正確的相框中實現(xiàn)正確的圖片诅炉,是一個不難但是挺啰嗦的事情

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case TAKE_PHOTO:
                if (resultCode == RESULT_OK) {
                    //將拍攝的圖片顯示出來
                    try {
                        bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                        if (choosed_image == R.id.sfz_image) {//身份證
                            //保存file到sp
                            sfzFile = saveMyBitmap(bitmap, "sfz");
                            saveFile(SFZ_KEY, sfzFile.getName());
                            Glide.with(this).asBitmap().load(sfzFile).thumbnail(0.1f).into(sfzImage);
                        } else if (choosed_image == R.id.jkz_image) {//健康證
                            jkzFile = saveMyBitmap(bitmap, "jkz");
                            //保存file到sp
                            saveFile(JKZ_KEY, jkzFile.getName());
                            Glide.with(this).asBitmap().load(jkzFile).thumbnail(0.1f).into(jkzImage);
                        } else if (choosed_image == R.id.zgz_image) {//從業(yè)資格證
                            zgzFile = saveMyBitmap(bitmap, "zgz");
                            //保存file到sp
                            saveFile(ZGZ_KEY, zgzFile.getName());
                            Glide.with(this).asBitmap().load(zgzFile).thumbnail(0.1f).into(zgzImage);
                        }
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }
                break;
            case CHOOSE_PHOTO:
                if (resultCode == RESULT_OK) {
                    //判斷手機系統(tǒng)版本號
                    if (Build.VERSION.SDK_INT >= 19) {
                        handleImageOnKitKat(data);
                    } else {
                        handleImageBeforeKitKat(data);
                    }
                }
                break;
        }
    }

這些代碼看著很繁瑣蜡歹,其實東西沒多少,只是比上面的邏輯多了個if涕烧,在這里我定義了一個全局的int變量月而,將三個相冊區(qū)別開來,R.id.sfz_image就是一個int值不是嗎议纯。這樣看起來更加具像化父款,最好不用數(shù)字區(qū)分開富腊。savaFile一樣梳凛。

這樣基本的上傳照片基本完成撇吞,我們可以點擊注冊把數(shù)據(jù)整合起來直接上傳到服務(wù)器了辅甥,在這里我用了okHttp框架

在第一行代碼里,okHttp只是簡單的展示了一下方法栋艳,大家可以百度一下各種okHttp方法抓谴,因為我們這個項目钧椰,定的統(tǒng)一是post請求蛛壳,而且因為數(shù)據(jù)類型可能不同(File,String,int)杏瞻,所以我經(jīng)過半天的不懈努力所刀,看到了一個nb的API:addFormDataPart()

 /**
     * 向服務(wù)器發(fā)送請求
     */
    private void postData() {
        SharedPreferences pref = getSharedPreferences("image", Context.MODE_PRIVATE);
        String headImage = pref.getString(HEAD_KEY, null);
        String sfzImage = pref.getString(SFZ_KEY, null);
        String jkzImage = pref.getString(JKZ_KEY, null);
        String zgzName = pref.getString(ZGZ_KEY, null);
        //Log.i(TAG, "postData: 頭像圖片名字" + imageName);
        OkHttpClient client = new OkHttpClient();
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
        File headFile = new File(storageDir, headImage);
        File sfzFile = new File(storageDir, sfzImage);
        File jkzFile = new File(storageDir, jkzImage);
        File zgzFile = new File(storageDir, zgzName);
        if (headFile != null) {
            // MediaType.parse() 里面是上傳的文件類型。
            RequestBody body = RequestBody.create(MediaType.parse("image/*"), headFile);
            // 參數(shù)分別為伐憾, 請求key ,文件名稱 赫模, RequestBody
            builder.addFormDataPart("txImg", headFile.getName(), body);
        }
        if (sfzFile != null) {
            // MediaType.parse() 里面是上傳的文件類型树肃。
            RequestBody body = RequestBody.create(MediaType.parse("image/*"), sfzFile);
            // 參數(shù)分別為, 請求key 瀑罗,文件名稱 胸嘴, RequestBody
            builder.addFormDataPart("sfzImg", sfzFile.getName(), body);
        }
        if (jkzFile != null) {
            // MediaType.parse() 里面是上傳的文件類型。
            RequestBody body = RequestBody.create(MediaType.parse("image/*"), jkzFile);
            // 參數(shù)分別為斩祭, 請求key 劣像,文件名稱 , RequestBody
            builder.addFormDataPart("jkzImg", jkzFile.getName(), body);
        }
        if (zgzFile != null) {
            // MediaType.parse() 里面是上傳的文件類型摧玫。
            RequestBody body = RequestBody.create(MediaType.parse("image/*"), zgzFile);
            // 參數(shù)分別為耳奕, 請求key ,文件名稱 诬像, RequestBody
            builder.addFormDataPart("zgzImg", zgzFile.getName(), body);
        }
        builder.addFormDataPart("loginId", "1");
        //builder.add("sfzImg", "1");
        //builder.add("zgzImg", "1");
        //builder.add("jkzImg", "1");
        builder.addFormDataPart("realName", "sdfdf");
        builder.addFormDataPart("gender", "0");
        builder.addFormDataPart("age", "10");
        builder.addFormDataPart("workYears", "10");
        builder.addFormDataPart("introduce", "sdfsdfsf");
        MultipartBody requestBody = builder.build();
        Request request = new Request.Builder().url("服務(wù)器地址").post(requestBody).build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.i(TAG, "onFailure: 失敗");
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.i(TAG, "onResponse: 成功 " + response.body().string());
            }
        });
    }

可以忽略那些沒用的提取數(shù)據(jù)代碼

寫到后面也比較懶了屋群,因為是周末,晚上還有極限挑戰(zhàn)哈哈坏挠,所以要抓緊
在這client的回調(diào)我覺得用過okHttp的人都能看懂芍躏,重要的newCall方法里面的參數(shù),在這里我是用MultipartBody類降狠,大家可以看上面那一段代碼的第12行開始

MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);

這段代碼是定義的這是上傳的表單類型

RequestBody body = RequestBody.create(MediaType.parse("image/*"), headFile);
            // 參數(shù)分別為对竣, 請求key ,文件名稱 榜配, RequestBody
            builder.addFormDataPart("txImg", headFile.getName(), body);

image/*是因為否纬,我的圖片文件是.jpg格式。
在這里蛋褥,我打了詳細的注釋,幫助大家也幫助自己理解烦味。這樣,我們在兩個頁面進行實現(xiàn)注冊頁面壁拉,用了一次請求就將數(shù)據(jù)上傳到了服務(wù)器谬俄。其實上傳的方式有很多種,用流的方式上傳圖片也是可以的弃理。

第一次博客溃论,因為自己本身是一個剛工作一個月的菜鳥,自己一個人搞安卓端的開發(fā)痘昌,也算是獨立開發(fā)了钥勋。所以要多走不少彎路炬转,實現(xiàn)一個功能可能會麻煩不少。希望以后好好做一個cv戰(zhàn)士算灸。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末扼劈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子菲驴,更是在濱河造成了極大的恐慌荐吵,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赊瞬,死亡現(xiàn)場離奇詭異先煎,居然都是意外死亡,警方通過查閱死者的電腦和手機巧涧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門薯蝎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谤绳,你說我怎么就攤上這事占锯。” “怎么了缩筛?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵烟央,是天一觀的道長。 經(jīng)常有香客問我歪脏,道長疑俭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任婿失,我火速辦了婚禮钞艇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘豪硅。我一直安慰自己哩照,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布懒浮。 她就那樣靜靜地躺著飘弧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪砚著。 梳的紋絲不亂的頭發(fā)上次伶,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天,我揣著相機與錄音稽穆,去河邊找鬼冠王。 笑死,一個胖子當(dāng)著我的面吹牛舌镶,可吹牛的內(nèi)容都是我干的柱彻。 我是一名探鬼主播豪娜,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼哟楷!你這毒婦竟也來了瘤载?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤卖擅,失蹤者是張志新(化名)和其女友劉穎鸣奔,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體磨镶,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡溃蔫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年健提,在試婚紗的時候發(fā)現(xiàn)自己被綠了琳猫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡私痹,死狀恐怖脐嫂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情紊遵,我是刑警寧澤账千,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站暗膜,受9級特大地震影響匀奏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜学搜,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一娃善、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瑞佩,春花似錦聚磺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至稠炬,卻和暖如春焕阿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背首启。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工捣鲸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人闽坡。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓栽惶,卻偏偏與公主長得像愁溜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子外厂,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,139評論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫冕象、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,104評論 4 62
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理汁蝶,服務(wù)發(fā)現(xiàn)渐扮,斷路器,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • 我是他第一百個新娘掖棉,他很誠實地告訴我墓律。 “之前的女孩兒們都怎么了?” “那時候我還不成熟,也有遇到不合適的幔亥,就都離...
    沉芙閱讀 823評論 2 2
  • 麥肯錫前顧問大島祥譽寫的一本小冊子耻讽,把該作者在麥肯錫公司工作期間的一些方法、習(xí)慣匯集起來帕棉,一共有39點针肥。通讀...
    讀書做更好的自己閱讀 723評論 0 0