45 votes

Créer et partager un fichier à partir du stockage interne

Mon but est de créer un fichier XML sur le stockage interne et ensuite l'envoyer par l'intermédiaire du partage de l'Intention.

Je suis en mesure de créer un fichier XML à l'aide de ce 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();

Je suis coincé à essayer de récupérer un Uri pour le fichier de sortie dans le but de le partager. J'ai d'abord essayé d'accéder au fichier en convertissant le fichier à un Uri

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

Cela renvoie file:///data/data/com.my.package/files/myfile.xml mais j'ai pas réussi à la joindre à un courriel, téléchargement, etc.

Si je vérifier manuellement la longueur du fichier, c'est bon et montre qu'il existe une taille de fichier raisonnable.

Ensuite, j'ai créé un fournisseur de contenu et essayé de référence le fichier et il n'est pas un descripteur valide pour le fichier. L' ContentProvider ne jamais être appelé à tout moment.

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

Cela renvoie content://com.my.package.provider/myfile.xml mais j'ai vérifier le fichier et c'est le zéro de la longueur.

Comment puis-je accéder à des fichiers correctement? Dois-je créer le fichier avec le fournisseur de contenu? Si oui, comment?

Mise à jour

Voici le code que j'utilise pour partager. Si j'ai choisi de Gmail, il montre un attachement, mais quand j'ai envoyer il donne une erreur ne Pouvait pas montrer de l'attachement et de l'e-mail qui arrive n'a pas de pièce jointe.

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;
    }
}

J'ai remarqué qu'il y a un Exception jetés ici à partir de l'intérieur de createChooser(...), mais je ne peux pas comprendre pourquoi il est jeté.

E/ActivityThread(572): Activité com.android.interne.app.ChooserActivity a fui IntentReceiver com.android.interne.app.ResolverActivity$1@4148d658 qui a été initialement inscrit ici. Êtes-vous en manque un à l'appel à unregisterReceiver()?

J'ai recherché cette erreur et ne peut pas trouver quelque chose d'évident. Ces deux liens suggèrent que j'ai besoin d'annuler l'inscription d'un récepteur.

J'ai un récepteur de l'installation, mais c'est pour un AlarmManager qui est défini ailleurs et ne nécessite pas l'application de s'inscrire / se désinscrire.

Code pour openFile(...)

Dans le cas où il est nécessaire, ici, est le fournisseur de contenu que j'ai créé.

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;
}

42voto

Rob Points 3027

Il est possible d'exposer un fichier stocké dans votre apps répertoire privé par l'intermédiaire d'un ContentProvider. Voici un exemple de code que j'ai faite montrant comment créer un fournisseur de contenu qui peut faire cela.

Manifeste

<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>

Dans votre ContentProvider remplacer openFile retour de la 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);
}

Assurez-vous que vous avez copié le fichier xml dans le répertoire de cache

    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
    }
}

Maintenant toutes les autres applications doivent être en mesure d'obtenir un InputStream pour votre fichier en utilisant le contenu d'uri (content://com.example.prov/myfile.xml)

Pour un simple test, appelez le fournisseur de contenu à partir d'une autre application similaire à la suivante

    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);
    }
}

-1voto

Fran Points 1

Mi código, probado y funciona

 try {
            File f = new File(getView().getContext().getExternalCacheDir()+"/prueba.txt");

            PrintStream printStream = new PrintStream(f);
            printStream.println("Probando la comparticion");
            printStream.close();

            Intent shareIntent = new Intent();
            shareIntent.setAction(Intent.ACTION_SEND);
            shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));
            shareIntent.setType("text/plain");

            startActivity(Intent.createChooser(shareIntent, "Enviar datos"));

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

la clave esta en getExternalCacheDir () ya que asi el fichero se creara en un entorno compartido y en Uri.fromFile (f) ya que ha putExtra hay que darle el fichero como de tipo File.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X