2010-01-27 58 views
14

內容提供者/解析器API提供了使用URI和openInputStream()openOutputStream()方法在進程間傳輸數據的複雜但穩健的方法。自定義內容提供商可以使用自定義代碼覆蓋openFile()方法,以便將URI有效解析爲Stream;然而,openFile()的方法簽名具有ParcelFileDescriptor返回類型,並且不清楚如何爲動態生成的內容生成適當的表示以從此方法返回。定製ContentProvider - openInputStream(),openOutputStream()

Returning a memory mapped InputStream from a content provider?

是否有實現用於在現有的代碼庫動態內容ContentProvider.openFile()方法的實例?如果不是,你可以建議源代碼或過程嗎?

回答

1

MemoryFile支持此功能,但公共API尚未完成。

+0

是否有計劃包括記憶文件和parcelfiledescriptor在未來?沿着這些線條的東西比用臨時文件具有未知生命時間的文件系統混亂/污染更好。 也許有一些方法可以檢測內容提供者內的流的關閉,這可以提供一種更安全的方式來清理自己? 我擔心發送附件到(gmail/standaed)電子郵件客戶端,雖然我確信還有其他地方可能會出現這些問題。 – hannasm 2010-01-29 03:18:09

+1

是的,MemoryFile.java目前有一個'public ParcelFileDescriptor getParcelFileDescriptor()'方法。這是甜甜圈的一部分,但正如傑夫所說,目前還沒有最終確定。 我已經證實,「概念」至少可以工作,而且目前可以使用反射來完成。這是非常骯髒的,但不建議:) 不幸的是,即使'ParcelFileDescriptor.fromSocket()'不能使用,因爲Memory.isMemoryFile()'拋出一個異常,因爲套接字既不是PFD也不是內存文件。 – Joe 2010-07-03 09:11:47

+1

小心MemoryFile。如果我理解正確,它會將文件的全部內容存儲在內存中,因此不能使用比可用內存大的文件。 – 2013-02-22 19:26:46

23

從總是樂於助人的CommonsWare中查看這個優秀的示例項目。它可以讓你創建你想在一邊不管的InputStream一個ParcelFileDescriptor管,而在另一側的接收應用程序:

https://github.com/commonsguy/cw-omnibus/tree/master/ContentProvider/Pipe

關鍵部位在openFile創建管:

public ParcelFileDescriptor openFile(Uri uri, String mode) 
                 throws FileNotFoundException { 
    ParcelFileDescriptor[] pipe=null; 

    try { 
     pipe=ParcelFileDescriptor.createPipe(); 
     AssetManager assets=getContext().getResources().getAssets(); 

     new TransferThread(assets.open(uri.getLastPathSegment()), 
         new AutoCloseOutputStream(pipe[1])).start(); 
    } 
    catch (IOException e) { 
     Log.e(getClass().getSimpleName(), "Exception opening pipe", e); 
     throw new FileNotFoundException("Could not open pipe for: " 
      + uri.toString()); 
    } 

    return(pipe[0]); 
    } 

然後創建一個線程,保持管道充滿:

static class TransferThread extends Thread { 
    InputStream in; 
    OutputStream out; 

    TransferThread(InputStream in, OutputStream out) { 
     this.in = in; 
     this.out = out; 
    } 

    @Override 
    public void run() { 
     byte[] buf = new byte[8192]; 
     int len; 

     try { 
      while ((len = in.read(buf)) > 0) { 
       out.write(buf, 0, len); 
      } 

      in.close(); 
      out.flush(); 
      out.close(); 
     } catch (IOException e) { 
      Log.e(getClass().getSimpleName(), 
        "Exception transferring file", e); 
     } 
    } 
} 
+3

完美正是我正在尋找的... – siliconeagle 2013-03-29 12:49:28

+0

我使用第三方庫通過內容提供程序請求文件,由於某種原因,另一端的數據以不同的方式到達(在這裏我一直在仔細地說) ParcelFileDescriptor以這種方式或使用像這樣的真實文件時:ParcelFileDescriptor.open(privateFile,ParcelFileDescriptor.MODE_READ_ONLY) – TacB0sS 2015-04-10 13:39:07

+1

任何想法爲什麼我有時使用此提供程序與更大量的請求時出現錯誤: java.io.IOException:寫入失敗:EPIPE(Broken pipe) at libcore.io.IoBridge.write(IoBridge.java:502) at java.io.FileOutputStream.write(FileOutputStream.java:186) – Malachiasz 2015-09-04 12:09:15