创建和共享从内部存储文件文件

2023-09-11 20:35:22 作者:敢不敢和我来一个天长地久

我的目标是创建内部存储XML文件,然后通过共享意图发送。

我能够用这个code创建一个XML文件

 的FileOutputStream的OutputStream = context.openFileOutput(文件名,Context.MODE_WORLD_READABLE);
为PrintStream PrintStream的=新的PrintStream(的OutputStream);
XML字符串= this.writeXml(); //获取XML在这里
printStream.println(XML);
printStream.close();
 

我卡试图检索的URI的输出文件,以便分享。我第一次尝试通过文件转换成一个URI

要访问该文件

 文件不过outFile = context.getFileStreamPath(文件名);
返回Uri.fromFile(不过outFile);
 

这将返回的文件:///data/data/com.my.package/files/myfile.xml 的,但我不能出现这种附加到电子邮件,上传等。

会声会影11旋转后怎么保存到电脑里啊

如果我手动检查文件的长度,这是正确的,并显示有一个合理的文件大小。

接下来,我创建了一个内容提供商,并试图引用文件,这是不是一个有效的句柄到文件中。该的ContentProvider 不以往任何时候都似乎被称为任意点。

 开放的URI = Uri.parse(内容://+ CachedFileProvider.AUTHORITY +/+文件名);
返回的URI;
 

这将返回的内容://com.my.package.provider/myfile.xml 的,但是我检查文件,它的长度为零

我如何访问文件是否正确?我需要创建与内容提供商的文件吗?如果是这样,怎么样?

更新

下面是code我使用分享。如果我选择的Gmail,它只表示作为附件,但是当我把它给了一个错误的无法显示附件和到达没有附件。电子邮件

 公共无效的onClick(视图查看){
    Log.d(TAG的onClick+ view.getId());

    开关(view.getId()){
        案例R.id.share_cancel:
            的setResult(RESULT_CANCELED,getIntent());
            完();
            打破;

        案例R.id.share_share:

            与myXML XML =新与myXML();
            乌里URI;
            尝试 {
                的uri = xml.writeXmlToFile(getApplicationContext(),myfile.xml中);
                // URI是文件:///data/data/com.my.package/files/myfile.xml
                Log.d(TAG,分享URI:+ uri.toString()+路径:+ uri.getPath());

                文件F =新的文件(uri.getPath());
                Log.d(TAG,文件长度:+ f.length());
                //显示了一个有效的文件大小

                意图shareIntent =新意图();
                shareIntent.setAction(Intent.ACTION_SEND);
                shareIntent.putExtra(Intent.EXTRA_STREAM,URI);
                shareIntent.setType(text / plain的);
                startActivity(Intent.createChooser(shareIntent,「股份」));
            }赶上(FileNotFoundException异常E){
                e.printStackTrace();
            }

            打破;
    }
}
 

我注意到,有一个异常这里扔从里面的 createChooser(...)的,但我想不通为什么它的抛出。

  

E / ActivityThread(572):活动   com.android.internal.app.ChooserActivity渗漏IntentReceiver   com.android.internal.app.ResolverActivity$1@4148d658这是   原本在这里注册。是否缺少调用   unregisterReceiver()?

我已经研究了这个错误并不能找到任何明显。这两个环节的建议,我需要注销接收器。

选配活动泄漏 - Android的 Why并Intent.createChooser()需要一个BroadcastReceiver,以及如何实现?

我有一个接收器的设置,但它是一个 AlarmManager 在其他位置设置,并不需要的应用程序,以注册/注销。

code为中openFile(...)

在情况下,它需要的,这里是我创建的内容提供商。

 公共ParcelFileDescriptor中openFile(URI URI,字符串模式)抛出FileNotFoundException异常{
    串fileLocation =的getContext()getCacheDir()+/+ uri.getLastPathSegment()。

    ParcelFileDescriptor PFD = ParcelFileDescriptor.open(新文件(fileLocation),ParcelFileDescriptor.MODE_READ_ONLY);
    返回PFD;
}
 

解决方案

有可能通过公开ContentProvider的存储在您的应用程序专用目录中的文件。下面是一些例子code我做了演示如何创建一个内容供应商,可以做到这一点。

清单

 <舱单的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
  包=com.example.providertest
  安卓版code =1
  机器人:VERSIONNAME =1.0>

  <使用-SDK安卓的minSdkVersion =11机器人:targetSdkVersion =15/>

  <应用机器人:标签=@字符串/ APP_NAME
    机器人:图标=@可绘制/ ic_launcher
    机器人:主题=@风格/ AppTheme>

    <活动
        机器人:名称=。MainActivity
        机器人:标签=@字符串/ APP_NAME>
        <意向滤光器>
            <作用机器人:名称=android.intent.action.MAIN/>
            <类机器人:名称=android.intent.category.LAUNCHER/>
        &所述; /意图滤光器>
    < /活性GT;

    <供应商
        机器人:名称=MYPROVIDER
        机器人:当局=com.example.prov
        机器人:出口=真
        />
  < /用途>
< /舱单>
 

在你的ContentProvider覆盖中openFile返回ParcelFileDescriptor

  @覆盖
公共ParcelFileDescriptor中openFile(URI URI,字符串模式)抛出FileNotFoundException异常{
     文件cacheDir =的getContext()getCacheDir()。
     文件privateFile =新的文件(cacheDir,file.xml);

     返回ParcelFileDescriptor.open(privateFile,ParcelFileDescriptor.MODE_READ_ONLY);
}
 

请确保您已复制XML文件到缓存目录

 私人无效copyFileToInternal(){
    尝试 {
        InputStream的是= getAssets()开(file.xml)。

        文件cacheDir = getCacheDir();
        文件不过outFile =新的文件(cacheDir,file.xml);

        的OutputStream OS =新的FileOutputStream(outFile.getAbsolutePath());

        byte []的BUFF =新的字节[1024];
        INT LEN;
        而((LEN = is.​​read(浅黄色))大于0){
            os.write(BUFF,0,len个);
        }
        os.flush();
        os.close();
        is.close();

    }赶上(IOException异常E){
        e.printStackTrace(); // TODO:应关闭流适当位置
    }
}
 

现在任何其他应用程序应该能够得到一个InputStream为您的私人文件使用内容URI(内容://com.example.prov/myfile.xml)

对于一个简单的测试,呼叫从一个单独的应用程序中的内容提供商类似于以下

 私有类MyTask的扩展AsyncTask的<字符串,整数,字符串> {

    @覆盖
    保护字符串doInBackground(字符串... PARAMS){

        开放的我们的uri = Uri.parse(内容://com.example.prov/myfile.xml);
        InputStream的是= NULL;
        StringBuilder的结果=新的StringBuilder();
        尝试 {
            是= getApplicationContext()getContentResolver()openInputStream(URI)。。;
            BufferedReader中R =新的BufferedReader(新InputStreamReader的(是));
            串线;
            而((行= r.readLine())!= NULL){
                result.append(线);
            }
        }赶上(FileNotFoundException异常E){
            e.printStackTrace();
        }赶上(IOException异常E){
            e.printStackTrace();
        } 最后 {
            尝试{如果(是!= NULL)is.close(); }赶上(IOException异常E){}
        }

        返回result.toString();
    }

    @覆盖
    保护无效onPostExecute(字符串结果){
        Toast.makeText(CallerActivity.this,结果,Toast.LENGTH_LONG).show();
        super.onPostExecute(结果);
    }
}
 

My goal is to create a XML file on internal storage and then send it through the share Intent.

I'm able to create a XML file using this code

FileOutputStream outputStream = context.openFileOutput(fileName, Context.MODE_WORLD_READABLE);
PrintStream printStream = new PrintStream(outputStream);
String xml = this.writeXml(); // get XML here
printStream.println(xml);
printStream.close();

I'm stuck trying to retrieve a Uri to the output file in order to share it. I first tried to access the file by converting the file to a Uri

File outFile = context.getFileStreamPath(fileName);
return Uri.fromFile(outFile);

This returns file:///data/data/com.my.package/files/myfile.xml but I cannot appear to attach this to an email, upload, etc.

If I manually check the file length, it's proper and shows there is a reasonable file size.

Next I created a content provider and tried to reference the file and it isn't a valid handle to the file. The ContentProvider doesn't ever seem to be called a any point.

Uri uri = Uri.parse("content://" + CachedFileProvider.AUTHORITY + "/" + fileName);
return uri;

This returns content://com.my.package.provider/myfile.xml but I check the file and it's zero length.

How do I access files properly? Do I need to create the file with the content provider? If so, how?

Update

Here is the code I'm using to share. If I select Gmail, it does show as an attachment but when I send it gives an error Couldn't show attachment and the email that arrives has no attachment.

public void onClick(View view) {
    Log.d(TAG, "onClick " + view.getId());

    switch (view.getId()) {
        case R.id.share_cancel:
            setResult(RESULT_CANCELED, getIntent());
            finish();
            break;

        case R.id.share_share:

            MyXml xml = new MyXml();
            Uri uri;
            try {
                uri = xml.writeXmlToFile(getApplicationContext(), "myfile.xml");
                //uri is  "file:///data/data/com.my.package/files/myfile.xml"
                Log.d(TAG, "Share URI: " + uri.toString() + " path: " + uri.getPath());

                File f = new File(uri.getPath());
                Log.d(TAG, "File length: " + f.length());
                // shows a valid file size

                Intent shareIntent = new Intent();
                shareIntent.setAction(Intent.ACTION_SEND);
                shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
                shareIntent.setType("text/plain");
                startActivity(Intent.createChooser(shareIntent, "Share"));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }

            break;
    }
}

I noticed that there is an Exception thrown here from inside createChooser(...), but I can't figure out why it's thrown.

E/ActivityThread(572): Activity com.android.internal.app.ChooserActivity has leaked IntentReceiver com.android.internal.app.ResolverActivity$1@4148d658 that was originally registered here. Are you missing a call to unregisterReceiver()?

I've researched this error and can't find anything obvious. Both of these links suggest that I need to unregister a receiver.

Chooser Activity Leak - Android Why does Intent.createChooser() need a BroadcastReceiver and how to implement?

I have a receiver setup, but it's for an AlarmManager that is set elsewhere and doesn't require the app to register / unregister.

Code for openFile(...)

In case it's needed, here is the content provider I've created.

public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
    String fileLocation = getContext().getCacheDir() + "/" + uri.getLastPathSegment();

    ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(fileLocation), ParcelFileDescriptor.MODE_READ_ONLY);
    return pfd;
}

解决方案

It is possible to expose a file stored in your apps private directory via a ContentProvider. Here is some example code I made showing how to create a content provider that can do this.

Manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.providertest"
  android:versionCode="1"
  android:versionName="1.0">

  <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="15" />

  <application android:label="@string/app_name"
    android:icon="@drawable/ic_launcher"
    android:theme="@style/AppTheme">

    <activity
        android:name=".MainActivity"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <provider
        android:name="MyProvider"
        android:authorities="com.example.prov"
        android:exported="true"
        />        
  </application>
</manifest>

In your ContentProvider override openFile to return the ParcelFileDescriptor

@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {       
     File cacheDir = getContext().getCacheDir();
     File privateFile = new File(cacheDir, "file.xml");

     return ParcelFileDescriptor.open(privateFile, ParcelFileDescriptor.MODE_READ_ONLY);
}

Make sure you have copied your xml file to the cache directory

    private void copyFileToInternal() {
    try {
        InputStream is = getAssets().open("file.xml");

        File cacheDir = getCacheDir();
        File outFile = new File(cacheDir, "file.xml");

        OutputStream os = new FileOutputStream(outFile.getAbsolutePath());

        byte[] buff = new byte[1024];
        int len;
        while ((len = is.read(buff)) > 0) {
            os.write(buff, 0, len);
        }
        os.flush();
        os.close();
        is.close();

    } catch (IOException e) {
        e.printStackTrace(); // TODO: should close streams properly here
    }
}

Now any other apps should be able to get an InputStream for your private file by using the content uri (content://com.example.prov/myfile.xml)

For a simple test, call the content provider from a seperate app similar to the following

    private class MyTask extends AsyncTask<String, Integer, String> {

    @Override
    protected String doInBackground(String... params) {

        Uri uri = Uri.parse("content://com.example.prov/myfile.xml");
        InputStream is = null;          
        StringBuilder result = new StringBuilder();
        try {
            is = getApplicationContext().getContentResolver().openInputStream(uri);
            BufferedReader r = new BufferedReader(new InputStreamReader(is));
            String line;
            while ((line = r.readLine()) != null) {
                result.append(line);
            }               
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try { if (is != null) is.close(); } catch (IOException e) { }
        }

        return result.toString();
    }

    @Override
    protected void onPostExecute(String result) {
        Toast.makeText(CallerActivity.this, result, Toast.LENGTH_LONG).show();
        super.onPostExecute(result);
    }
}

 
精彩推荐
图片推荐