Android10 Retrofit圖片上傳

Android10文件存儲機(jī)制修改成了沙盒模式,應(yīng)用不能直接訪問除了沙盒文件和公共文件以外的文件,直接使用圖片絕對地址上傳圖片會出錯,可以通過圖片的Uri來上傳圖片

    private fun copyFromUri(uri:Uri,fileName:String,subscribe:Observer<String>){
        var cacheFile = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.absolutePath+File.separator+"cache")
        if(!cacheFile.exists())
            cacheFile.exists()
        cacheFile = File(cacheFile.absolutePath + File.separator + fileName)

        Observable.create<String>{
            val inStream:InputStream = contentResolver.openInputStream(uri)!!
            val outStream:OutputStream = FileOutputStream(cacheFile)
            val bytes = ByteArray(1024)
            var len = -1
            try {
                while ({len = inStream.read(bytes);len}()!=-1)
                    outStream.write(bytes,0,len)
            } catch (e: Exception) {
                it.onError(e)
            } finally {
                inStream.close()
                outStream.close()
            }
            it.onNext(cacheFile.path)
            it.onComplete()
        }
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(subscribe)
    }

上傳圖片

    private fun onUpload(path: String){
        if ( "" != path.trim() ){
            val file = File(path)
            val body = file.asRequestBody("application/octet-stream".toMediaTypeOrNull())
            val progressBody = ProgressRequestBody(body){
                progress.progress = it.toInt()
            }
            val part = MultipartBody.Part.createFormData("file",file.name,progressBody)
            getRetrofit().create(Api::class.java).onUpload(part)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object : Observer<ResponseBody> {
                    override fun onSubscribe(d: Disposable) {

                    }

                    override fun onNext(t: ResponseBody) {
                        Toast.makeText(this@MainActivity,"Success",Toast.LENGTH_SHORT).show()
                    }

                    override fun onError(e: Throwable) {
                        Toast.makeText(this@MainActivity,"Error!"+e.message,Toast.LENGTH_SHORT).show()
                    }

                    override fun onComplete() {
                        if(file.exists())
                            file.delete()
                    }
                })
        }
    }

網(wǎng)絡(luò)接口定義

@Multipart
    @POST("downloadApp/upload")
    fun onUpload(@Part part:MultipartBody.Part):Observable<ResponseBody>

實(shí)現(xiàn)進(jìn)度更新

class ProgressRequestBody(private val requestBody: RequestBody,private val listener:((Long)->Unit) ):RequestBody() {

    private var byteBufferSink:BufferedSink ?= null

    override fun contentType(): MediaType? {
        return requestBody.contentType()
    }

    override fun contentLength(): Long {
        return requestBody.contentLength()
    }

    override fun writeTo(sink: BufferedSink) {
        if (byteBufferSink == null)
            byteBufferSink = sink(sink).buffer()
        requestBody.writeTo(byteBufferSink!!)
        byteBufferSink?.flush()
    }

    private fun sink(sink:Sink) = object : ForwardingSink(sink) {

        private var count = 0L
        private var total = -1L

        @SuppressLint("CheckResult")
        override fun write(source: Buffer, byteCount: Long) {
            if (total ==-1L) total = contentLength()
            super.write(source, byteCount)
            count += byteCount
            val progress = count/total.toDouble() * 100
            Observable.just(count).observeOn(AndroidSchedulers.mainThread()).subscribe {
                listener.invoke(progress.toLong())
            }
        }
    }
}

web端的圖片上傳代碼

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");

        String realPath = userPath + "/upload/test";
        String cachePath = userPath + "/upload/cache";

        File realFile = new File(realPath);
        File cacheFile = new File(cachePath);

        System.out.println("上傳路徑是:"+realPath);
        if (!realFile.exists())
            realFile.mkdirs();
        if (!cacheFile.exists())
            cacheFile.mkdirs();

        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setRepository(cacheFile);

        ServletFileUpload upload = new ServletFileUpload(factory);
        upload.setHeaderEncoding("UTF-8");

        if (!ServletFileUpload.isMultipartContent(request))
            return;

        InputStream in = null;
        OutputStream out = null;
        List<String> files = new ArrayList<>();
        try {
            List<FileItem> items = upload.parseRequest(request);
            for (FileItem item:items){
                if (item.isFormField()){
                    System.out.println(item.getFieldName()+": "+item.getString("UTF-8"));
                }else {
                    String fileName = item.getName();
                    if (fileName.isEmpty()||"".equals(fileName.trim()))
                        continue;
                    fileName = fileName.substring(fileName.lastIndexOf("/")+1);
                    String downloadPath = realPath+"/"+fileName;
                    files.add(fileName);

                    in = item.getInputStream();
                    out = new FileOutputStream(downloadPath);

                    byte bt[] = new byte[1024];

                    int len = -1;

                    while ((len = in.read(bt))!=-1)
                        out.write(bt,0,len);
                }
                item.delete();
            }
        } catch (FileUploadException | IOException e) {
            System.out.println(e.getMessage());
            response.getWriter().write("ERROR");
        } finally {
            if (in!=null)
                in.close();
            if (out!=null)
                out.close();
        }
        response.getWriter().write("SUCCESS");
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末黑滴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子紧索,更是在濱河造成了極大的恐慌袁辈,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件齐板,死亡現(xiàn)場離奇詭異吵瞻,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)甘磨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門橡羞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人济舆,你說我怎么就攤上這事卿泽。” “怎么了滋觉?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵签夭,是天一觀的道長。 經(jīng)常有香客問我椎侠,道長第租,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任我纪,我火速辦了婚禮慎宾,結(jié)果婚禮上丐吓,老公的妹妹穿的比我還像新娘。我一直安慰自己趟据,他們只是感情好券犁,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著汹碱,像睡著了一般粘衬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咳促,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天稚新,我揣著相機(jī)與錄音,去河邊找鬼等缀。 笑死枷莉,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的尺迂。 我是一名探鬼主播笤妙,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼噪裕!你這毒婦竟也來了蹲盘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤膳音,失蹤者是張志新(化名)和其女友劉穎召衔,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祭陷,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡苍凛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了兵志。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片醇蝴。...
    茶點(diǎn)故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖想罕,靈堂內(nèi)的尸體忽然破棺而出悠栓,到底是詐尸還是另有隱情,我是刑警寧澤按价,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布惭适,位于F島的核電站,受9級特大地震影響楼镐,放射性物質(zhì)發(fā)生泄漏癞志。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一框产、第九天 我趴在偏房一處隱蔽的房頂上張望今阳。 院中可真熱鬧师溅,春花似錦、人聲如沸盾舌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽妖谴。三九已至,卻和暖如春酌摇,著一層夾襖步出監(jiān)牢的瞬間膝舅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工窑多, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仍稀,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓埂息,卻偏偏與公主長得像技潘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子千康,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評論 2 348

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,092評論 1 32
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程享幽,因...
    小菜c閱讀 6,365評論 0 17
  • 7.1 壓縮圖片 一、基礎(chǔ)知識 1拾弃、圖片的格式 jpg:最常見的圖片格式值桩。色彩還原度比較好,可以支持適當(dāng)壓縮后保持...
    AndroidMaster閱讀 2,496評論 0 13
  • 這節(jié)課是 Android 開發(fā)(入門)課程 的第四部分《數(shù)據(jù)與數(shù)據(jù)庫》的第三節(jié)課豪椿,導(dǎo)師依然是 Jessica Li...
    HsuJin閱讀 1,319評論 0 2
  • “轟”隨著一聲巨響奔坟,那本佇立在地面山峰瞬間土崩瓦解,那如煙霧般的塵土頃刻間便將天際覆蓋搭盾。 在那漫天遍野的土黃色...
    星顏月貌閱讀 200評論 0 2