在后台线程中删除文件

Posted

技术标签:

【中文标题】在后台线程中删除文件【英文标题】:Delete files in a background thread 【发布时间】:2017-06-21 12:29:11 【问题描述】:

任务:我想在后台线程中从MediaStore 中删除文件,以便用户可以在线程工作时使用我的应用程序。

问题: 我知道每当一个进程完成时,它的线程也会完成它们的工作。因此,这意味着如果用户快速关闭应用程序,我将无法从MediaStore 中删除所有选定的文件,从而终止进程。

可能的解决方案:您认为将该过程作为一个单独的流程(任务)来实现是个好主意吗?例如,使用Service

代码

 Snackbar.make(findViewById(R.id.rootView),message)
                    .setAction("UNDO", new View.OnClickListener() 
                        @Override
                        public void onClick(View view) 
                           //restore data
                        
                    )
                    .addCallback(new BaseTransientBottomBar.BaseCallback<Snackbar>() 
                        @Override
                        public void onDismissed(Snackbar transientBottomBar, int event) 
                            super.onDismissed(transientBottomBar, event);
                            switch (event) 
                                case DISMISS_EVENT_SWIPE:
                                case DISMISS_EVENT_TIMEOUT:
                                    //delete the files using either a background thread, or a separate task
                                    break;
                            
                        
                    )
                    .show();

更新

 public static void deleteFile(Context context, File mediaFile) 
    if(!mediaFile.delete()) 
        Log.e(TAG, "Cannot delete file "+ mediaFile.getAbsoluteFile());

    
    String[] projection =  MediaStore.Images.Media._ID ;

    String selection = MediaStore.Images.Media.DATA + " = ?";
    String[] selectionArgs = new String[]  mediaFile.getAbsolutePath() ;

    Uri queryUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    ContentResolver contentResolver = context.getContentResolver();
    Cursor cursor = contentResolver.query(queryUri, projection, selection, selectionArgs, null);

    if(cursor!=null) 
        if (cursor.moveToFirst()) 
            long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
            Uri deleteUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
            contentResolver.delete(deleteUri, null, null);
        
        cursor.close();
    

谢谢!

【问题讨论】:

有多少个文件?这个过程需要很长时间? 视情况而定。它可以是 10 或 1000。基本上,用户可以删除整个文件夹的文件。 删除1000个文件需要很长时间吗?特别是放在一个文件夹里。我猜您不仅要删除MediaStore,还要更新MediaStore 够用了。如果我想删除 1000 个文件,然后我立即关闭应用程序,它将删除大约 10-20 个文件。 是的,没错,我也在更新MediaStore。我现在将发布此过程的代码。 【参考方案1】:

是的,这听起来像是 Service 的一个很好的候选者但是当你说“作为一个单独的进程(任务)”时,这不是 Service 的含义:

服务不是一个单独的进程。 Service 对象本身并不意味着它在自己的进程中运行;除非另有说明,否则它会在与其所属的应用程序相同的进程中运行。

服务不是线程。它本身并不是一种脱离主线程工作的方法(以避免 Application Not Responding 错误)。

https://developer.android.com/reference/android/app/Service.html#WhatIsAService

这是可行的,因为用户通常不会以终止进程的方式关闭应用程序。应用程序继续运行,即使所有活动都已关闭,甚至从最近的应用程序列表中滑出。

【讨论】:

是的,不是。但是,我可以将其指定为一个单独的过程,对吗?这正是我要问的,这样做值得吗? 不,这会更难,而且没有任何充分的理由。请参阅我的新编辑。您可以使用现有流程,因为它在活动结束后仍然存在,尤其是在有服务运行时。 如果我错了,最好有自己的进程,这显然是清单中的简单转换:***.com/a/38318003/360211 这支持了我的想法:***.com/a/9434268/360211 是的,当activity启动时,它可以显示任何正在运行的删除服务的进度,当然。在复制文件时,通知进度会像这个应用程序一样出色:play.google.com/store/apps/…

以上是关于在后台线程中删除文件的主要内容,如果未能解决你的问题,请参考以下文章

没有主线程可以存在后台线程吗?

c# 在后台线程中出现未经授权的错误

Core Data undo后台线程删除

在 UI 或后台线程上写入文件 [重复]

保存在后台线程未完成

InnoDB后台线程