2017-06-13 129 views
0

随着android N的最新变化,我不得不升级我的代码以使用FileProvider来使用相机/文件管理器获取图像/文件。 代码在仿真器(genymotion)中正常工作,但在Moto G4 plus中抛出IO异常。阅读失败:从InputStream Nougat读取时读取EBADF(坏文件描述符)

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ 
       try { 
        ParcelFileDescriptor fcd = getContentResolver().openFileDescriptor(uriOrig,"r");// uriOrig is the uri returned from camera 
        if(fcd != null) { 
         InputStream inputStream = new FileInputStream(fcd.getFileDescriptor()); 
         uploadCall =RestService.getInstance().uploadFile(mimeType, name, size, 
           inputStream, defaultResponseCallback); 
        } 

       } catch (FileNotFoundException e) { 
        e.printStackTrace(); 
       } 
      } 

这里是上传文件的方法。

public Call<Attachment> uploadFile(final String mimeType, final String name, final long length,final InputStream is, final Callback<Attachment> callback) { 
final int byteCount = 8192; 
    if (length > 0) { 
     RequestBody fileBody = new RequestBody() { 

      @Override 
      public MediaType contentType() { 
       return !TextUtils.isEmpty(mimeType) ? MediaType.parse(mimeType) : null; 
      } 

      @Override 
      public long contentLength() throws IOException { 
       return length; 
      } 

      @Override 
      public void writeTo(BufferedSink sink) throws IOException { 
       final long fileLength = contentLength(); 
       byte[] buffer = new byte[byteCount]; 
       long uploaded = 0; 

       try { 
        final Handler handler = new Handler(Looper.getMainLooper(), new Handler.Callback() { 

         @Override 
         public boolean handleMessage(Message msg) { 
          if (callback instanceof Callback2) { 
           Callback2 callback2 = (Callback2) callback; 
           long uploaded = (long) msg.obj; 
           callback2.onProgress(uploaded, fileLength); 
          } 

          return true; 
         } 
        }); 

        int read; 
        while ((read = is.read(buffer)) != -1) { 
         uploaded += read; 
         sink.write(buffer, 0, read); 
         Log.d("write: ", "bytes: "+ new String(buffer)); 
         Log.e("writeTo: ", uploaded + " up fd->"); 
         // update progress on UI thread 
         handler.sendMessage(handler.obtainMessage(0, uploaded)); 
        } 

        is.close(); 
       } catch (IOException e) { 
        Log.e("file_upload", "Exception thrown while uploading", e); 
       } 
       Log.e("sink: "+uploaded + " bytes ", sink.toString(), new Exception("check")); 
      } 
     }; 

     String fileName = name; 
     int index = name.lastIndexOf("."); 
     if (index < 0) { 
      String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType); 
      fileName += "." + extension; 
     } 

     MultipartBody.Part part = MultipartBody.Part.createFormData("file", fileName, fileBody); 
     Call<Attachment> call = companyRestInterface.uploadFile(part); 
     call.enqueue(callback); 
     return call; 
    } 
} 

堆栈跟踪

java.io.IOException: read failed: EBADF (Bad file descriptor) 
                  at libcore.io.IoBridge.read(IoBridge.java:481) 
                  at java.io.FileInputStream.read(FileInputStream.java:252) 
                  at java.io.FileInputStream.read(FileInputStream.java:223) 
                  at xend.app.http.RestService$10.writeTo(RestService.java:767) 
                  at okhttp3.MultipartBody.writeOrCountBytes(MultipartBody.java:173) 
                  at okhttp3.MultipartBody.writeTo(MultipartBody.java:114) 
                  at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:62) 
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) 
                  at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45) 
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) 
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) 
                  at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93) 
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) 
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) 
                  at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93) 
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) 
                  at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120) 
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) 
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) 
                  at xend.app.http.MyInterceptor.intercept(MyInterceptor.java:51) 
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) 
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) 
                  at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185) 
                  at okhttp3.RealCall$AsyncCall.execute(RealCall.java:135) 
                  at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) 
                  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) 
                  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) 
                  at java.lang.Thread.run(Thread.java:761) 
                 Caused by: android.system.ErrnoException: read failed: EBADF (Bad file descriptor) 
                  at libcore.io.Posix.readBytes(Native Method) 
                  at libcore.io.Posix.read(Posix.java:169) 
                  at libcore.io.BlockGuardOs.read(BlockGuardOs.java:231) 
                  at libcore.io.IoBridge.read(IoBridge.java:471) 
                  at java.io.FileInputStream.read(FileInputStream.java:252)  
                  at java.io.FileInputStream.read(FileInputStream.java:223)  
                  at xend.app.http.RestService$10.writeTo(RestService.java:767)  
                  at okhttp3.MultipartBody.writeOrCountBytes(MultipartBody.java:173)  
                  at okhttp3.MultipartBody.writeTo(MultipartBody.java:114)  
                  at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:62)  
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)  
                  at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)  
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)  
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)  
                  at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)  
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)  
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)  
                  at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)  
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)  
                  at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)  
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)  
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)  
                  at xend.app.http.MyInterceptor.intercept(MyInterceptor.java:51)  
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)  
                  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)  
                  at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185)  
                  at okhttp3.RealCall$AsyncCall.execute(RealCall.java:135)  
                  at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)  
                  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)  
                  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)  
                  at java.lang.Thread.run(Thread.java:761)  

任何帮助将是非常赞赏。

EDIT

图像URI部分。

Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
      File externalCacheDir = getExternalCacheDir(); 
File extFile = new File(externalCacheDir, 
         String.valueOf(System.currentTimeMillis()) + ".jpg"); 
mImageCaptureUri = FileProvider.getUriForFile(DirectChatActivity.this, 
          BuildConfig.APPLICATION_ID + ".provider",extFile); 
        grantUriPermission("xend.app", mImageCaptureUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 
        cameraIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 
        cameraIntent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mImageCaptureUri); 

这个mImageCaptureUri后来被称为uriOrig。 采取了所有权限并相应地进行了工作。

+0

这是从公共或私人存储提取数据吗?你有足够的权限吗? – MeetTitan

+0

'uriOrig是从相机返回的uri' - 相机不返回'Uri'值。请显示uriOrig来自哪里。 – CommonsWare

+0

@MeetTitan,我编辑了这个问题来添加uri部分。对不起,可能是我以前没描述过。 – Debanjan

回答

0

问题在于ParcelFileDescriptor。它关闭输入流。因此,与

InputStream inputStream = getContentResolver().openInputStream(uriOrig); 
uploadCall =RestService.getInstance().uploadFile(mimeType, name, size, 
           inputStream, defaultResponseCallback); 

更换线

ParcelFileDescriptor fcd = getContentResolver().openFileDescriptor(uriOrig,"r");// uriOrig is the uri returned from camera 
        if(fcd != null) { 
         InputStream inputStream = new FileInputStream(fcd.getFileDescriptor()); 
         uploadCall =RestService.getInstance().uploadFile(mimeType, name, size, 
           inputStream, defaultResponseCallback); 
        } 

所做的工作。