通过意图共享后删除文件

发布于 2024-10-10 09:23:18 字数 292 浏览 3 评论 0原文

我试图在通过 Android 的 Intent.ACTION_SEND 功能共享临时文件后删除该文件。现在我正在启动活动以获取结果,并在 OnActivityResult 中删除该文件。不幸的是,这只在我使用断点调试它时才有效,但是当我让它自由运行并说通过电子邮件发送文件时,电子邮件没有附件。

我认为发生的情况是我的活动正在通过电子邮件发送文件之前删除该文件。我不明白的是为什么 onActivityResult 不应该只在其他活动完成后调用?

我也尝试过删除 onResume 中的文件,但没有成功。

有更好的方法吗?

I'm trying to delete a temporary file after sharing it via android's Intent.ACTION_SEND feature. Right now I am starting the activity for a result and in OnActivityResult, I am deleting the file. Unfortunately this only works if I am debugging it with a breakpoint, but when I let it run freely and say, email the file, the email has no attachment.

I think what is happening is my activity is deleting the file before it had been emailed. What I don't get is why, shouldn't onActivityResult only be called AFTER the other activity is finished?

I have also tried deleting the file in onResume, but no luck.

Is there a better way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

感悟人生的甜 2024-10-17 09:23:18

我注意到采用类似方法的相同行为。在查看 logcat 错误时,我看到 gmail 抱怨找不到附件。所以,是的,似乎意图在 gmail 实际读取附件文件之前返回。

我还没有找到解决方案,但可能会是这样的:

  • 将文件移动到某个目录,这样我就知道这是我决定发送的文件,
  • 通过 ACTION_SEND 将其作为附件发送
  • 在下一个 onResume 开始屏幕活动时 ,删除“已发送”目录中的文件早于某个时间范围,该时间范围足够长,足以使发送实际发生

选择适当的时间范围可能很棘手,因为 gmail(或其他 ACTION_SEND 提供程序)可能不会实际读取该时间范围文件,直到有网络连接。我认为 24​​ 小时应该是合理的,就我而言,我正在处理诊断日志,因此如果用户已经长时间离线,那么过早删除日志并没有真正的危害。

如果文件的内容是文本并且不是太大,更简单的方法可能是读取文件的内容并使用 Intent.putExtra(android.content.Intent.EXTRA_TEXT, yourText) 将其内联到消息正文中。

I noticed the same behavior with a similar approach. While watching logcat for errors I saw gmail complaining that it couldnt find the attachment. So, yes, it seems the intent returns BEFORE gmail has actually read the file for attachment.

I havent gotten around to a solution yet but it's likely going to be something like:

  • move the file to some directory so I know it's one I've decided to send
  • send it as attachment via ACTION_SEND
  • at next onResume for my start screen activity, delete files in the "sent" directory that are older than some time frame that's reasonably long enough for the send to actually have happened

Choosing an appropriate time frame might be tricky since it's probably the case that gmail (or other ACTION_SEND providers) dont actually read the file until it has a network connection. I'm thinking 24 hours should be reasonable and in my case I'm dealing with diagnostic logs so there's no real harm in deleting one too soon if the user has been off network for a long period of time.

If the content of your file is text and it's not obscenely large a simpler approach may be to read the contents of the file and use Intent.putExtra(android.content.Intent.EXTRA_TEXT, yourText) to inline it into the body of the message.

避讳 2024-10-17 09:23:18

我所做的如下。

我使用了:

myfile.deleteOnExit();

但是,正如 DR 在下面的评论中提到的正确答案,这并不能保证文件删除。这就是为什么我也在共享活动返回后删除该文件。如果文件存在,我删除该文件。因为应用有时会崩溃,所以我将其放入 try{} 中并且它可以工作。

我不知道为什么它对你不起作用,但对我来说它至少适用于 Gmail 附件、TextSecure、Hangouts。

在类声明中:

static File file;

在调用 Intent 的方法中:

        Intent share = new Intent(Intent.ACTION_SEND);
        share.setType("image/png");

        // Compress the bitmap to PNG
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, bytes);

        // Temporarily store the image to Flash
        File sdCard = Environment.getExternalStorageDirectory();
        File dir = new File (sdCard.getAbsolutePath() + "/FolderName");
        dir.mkdirs();

        // This file is static.
        file = new File(dir, "FileName.png");

        try {
            file.createNewFile();
            FileOutputStream fo = new FileOutputStream(file);
            fo.write(bytes.toByteArray());
            fo.flush();
            fo.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Share compressed image
        share.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:///"+file.getPath()));

        /** START ACTIVITY **/
        startActivityForResult(Intent.createChooser(share,"Share Image"),1);

        // Delete Temporary file
        file.deleteOnExit();     // sometimes works

在额外的方法中:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {   
        // Because app crashes sometimes without the try->catch 
        try {
            // if file exists in memory
            if (file.exists()) {
                file.delete();
            }
        } catch (Exception e) {
            Log.d(LOG,"Some error happened?");
        }

    }

What I did is the following.

I used the:

myfile.deleteOnExit();

However, as D.R. mentioned in the comment below correct answer, this does not guarantee the file deletion. This is why I am also deleting the file after the Shared Activity returns. I delete the file if file exists. Because the app crashed sometimes, I put it inside try{} and it works.

I do not know why it does not work for you, but for me it works at least for Gmail attachement, TextSecure, Hangouts.

In class delcaration:

static File file;

In method that calles the Intent:

        Intent share = new Intent(Intent.ACTION_SEND);
        share.setType("image/png");

        // Compress the bitmap to PNG
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, bytes);

        // Temporarily store the image to Flash
        File sdCard = Environment.getExternalStorageDirectory();
        File dir = new File (sdCard.getAbsolutePath() + "/FolderName");
        dir.mkdirs();

        // This file is static.
        file = new File(dir, "FileName.png");

        try {
            file.createNewFile();
            FileOutputStream fo = new FileOutputStream(file);
            fo.write(bytes.toByteArray());
            fo.flush();
            fo.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Share compressed image
        share.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:///"+file.getPath()));

        /** START ACTIVITY **/
        startActivityForResult(Intent.createChooser(share,"Share Image"),1);

        // Delete Temporary file
        file.deleteOnExit();     // sometimes works

In an extra method:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {   
        // Because app crashes sometimes without the try->catch 
        try {
            // if file exists in memory
            if (file.exists()) {
                file.delete();
            }
        } catch (Exception e) {
            Log.d(LOG,"Some error happened?");
        }

    }
牛↙奶布丁 2024-10-17 09:23:18

我已经设法让它工作:

File tbd = new File(sharePath);
tbd.deleteOnExit();

这似乎会在活动关闭时删除文件。

I have managed to get it to work with:

File tbd = new File(sharePath);
tbd.deleteOnExit();

This seems to delete the file when the activity closes.

时光沙漏 2024-10-17 09:23:18

这是我的工作解决方案。在 startActivity() 执行此操作之前:

    FileObserver fo = new FileObserver(file,FileObserver.CLOSE_NOWRITE) {
        @Override
        public void onEvent(int event, @Nullable String path) {
            if(event==FileObserver.CLOSE_NOWRITE) {
                file.delete();
                this.stopWatching();
                // HERE: remove the saved reference to 'fo'
            }
        }
    };
    fo.startWatching();
    // HERE: save a reference to 'fo'

重要提示:您应该保存对“fo”的引用,以便 FileObserver 不会被垃圾收集。

This is my working solution. Before startActivity() execute this:

    FileObserver fo = new FileObserver(file,FileObserver.CLOSE_NOWRITE) {
        @Override
        public void onEvent(int event, @Nullable String path) {
            if(event==FileObserver.CLOSE_NOWRITE) {
                file.delete();
                this.stopWatching();
                // HERE: remove the saved reference to 'fo'
            }
        }
    };
    fo.startWatching();
    // HERE: save a reference to 'fo'

Important: You should save the reference to 'fo' so that the FileObserver is not garbage-collected.

山川志 2024-10-17 09:23:18

另一个可能的答案是,当您的应用程序恢复时创建一个新线程,立即标记当前时间,让线程休眠您认为发送文件合理的时间,并且当线程恢复时,仅删除在该线程之前创建的文件。之前标记的时间。这将使您能够仅删除应用程序恢复时存储位置中的内容,同时也给 Gmail 有时间来取出电子邮件。代码片段:(我正在使用 C#/Xamarin,但您应该明白)

public static void ClearTempFiles()
{
    Task.Run(() =>
    {

        try
        {
            DateTime threadStartTime = DateTime.UtcNow;
            await Task.Delay(TimeSpan.FromMinutes(DeletionDelayMinutes));
            DirectoryInfo tempFileDir = new DirectoryInfo(TempFilePath);
            FileInfo[] tempFiles = tempFileDir.GetFiles();
            foreach (FileInfo tempFile in tempFiles)
            {
                if (tempFile.CreationTimeUtc < threadStartTime)
                {
                    File.Delete(tempFile.FullName);
                }
            }
        }
        catch { }
    });
}

@Martijn Pieters 这个答案是处理多个问题的不同解决方案。如果有的话,我发布的其他问题应该标记为重复,因为它们是同一问题。我在每个问题上都贴了帖子,以确保遇到此问题的人都能找到解决方案。

Another potential answer would be to create a new thread when your app resumes, immediately mark the current time, sleep the thread for however long you feel is reasonable for the file to be sent, and when the thread resumes, only delete files created before the previously marked time. This will give you the ability to only delete what was in the storage location at the time your app was resumed, but also give time to gmail to get the email out. Code snippet: (I'm using C#/Xamarin, but you should get the idea)

public static void ClearTempFiles()
{
    Task.Run(() =>
    {

        try
        {
            DateTime threadStartTime = DateTime.UtcNow;
            await Task.Delay(TimeSpan.FromMinutes(DeletionDelayMinutes));
            DirectoryInfo tempFileDir = new DirectoryInfo(TempFilePath);
            FileInfo[] tempFiles = tempFileDir.GetFiles();
            foreach (FileInfo tempFile in tempFiles)
            {
                if (tempFile.CreationTimeUtc < threadStartTime)
                {
                    File.Delete(tempFile.FullName);
                }
            }
        }
        catch { }
    });
}

@Martijn Pieters This answer is a different solution that handles multiple questions. If anything, the other questions that I posted on, should be marked as duplicates because they are the same question. I posted on each of them to ensure that whoever has this problem, can find the solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文