Android 4.4.2中缺少下载的文件

时间:2014-10-15 23:31:53

标签: android file android-download-manager android-external-storage

我们正在使用内置的DownloadManager从我们的服务器中获取文件。如果我们发现该文件有更新,我们会删除本地版本并从DownloadManager重新排队下载。这仅在您完全杀死并重新启动应用程序时运行(及时更新文件不是优先级,只是我们拥有所有文件,并且只要我们注意到它们就会更新)。这个系统适用于我所有的个人测试设备,但是,当在api 19模拟器或我的同事的HTC One上进行测试时,文件将下载然后消失(不再在应用程序的外部数据文件夹中)。我已经发现两者都是android的4.4.2版本(我的设备是4.4.4或4.0.4)。这很奇怪,因为他们会坚持一段时间,但随后的文件将会消失。

以下是一些代码:

AssetManager设置(输出文件夹的设置)

private AssetManager(Context activity){
    if(singleton != null&&IOUtils.hasExternalStorage() != IOUtils.ExtStorageState_OK){
        return;
    }
    context = activity;

    external = ContextCompat.getExternalFilesDirs(context, "")[0];

    external.mkdirs();

    imageFolder = new File(external,imagePath);

    imageFolder.mkdirs();

    singleton = this;
}

下载代码

private static class DownloadObject {
    public String ServerID;
    public String updated_at;
    public Uri image;

    public DownloadObject() {
        super();
    }

    public DownloadObject(String ServerID,String updated_at){
        super();
        this.ServerID = ServerID;
        this.updated_at = updated_at;
    }

    public DownloadObject(Cursor cursor){
        super();
        this.ServerID = cursor.getString(cursor.getColumnIndex(ObjectDao.Properties.ServerID.columnName));
        this.updated_at = cursor.getString(cursor.getColumnIndex(ObjectDao.Properties.UpdatedAt.columnName));
        String imageFile = cursor.getString(cursor.getColumnIndex(ObjectDao.Properties.Image.columnName));
        this.image = Uri.parse(AssetManager.getSingleton().getImageFolder().getPath()).buildUpon().appendPath(imageFile).scheme("file").build();
    }
}

//downloadObjectVector is the fresh list of all objects from the server
//existingObjects is the Cursor from the db that lists all existing object locally
private void SpinOffDownloads(final Vector<DownloadObject> downloadObjectVector,final Cursor existingObjects){
    new Thread(new Runnable() {
        @Override
        public void run() {
            int count = 0;
            if(existingObjects != null){
                count = existingObjects.getCount();
            }

            if (count>0){
                existingObjects.moveToFirst();
                do{
                    final DownloadObject obj = new DownloadObject(existingObjects);

                    DownloadObject notNeededObject = ArrayUtils.findFirst(downloadObjectVector,new ArrayUtils.Predicate<DownloadObject>() {
                        @Override
                        public boolean evaluate(DownloadObject downloadObject) {
                            return downloadObject.ServerID.equals(obj.ServerID)&&downloadObject.updated_at.compareTo(obj.updated_at) <= 0;
                        }
                    });
                    if (notNeededObject != null){
                        File imageTest = null;
                        if(notNeededObject.image != null) {
                            Uri out = Uri.parse(AssetManager.getSingleton().getImageFolder().getPath()).buildUpon().appendPath(notNeededObject.image.getLastPathSegment()).scheme("file").build();
                            imageTest = new File(out.getPath());
                        }else{
                            Log.v(CLASS_NAME,"object with null image:"+notNeededObject.ServerID);
                        }
                        if (imageTest == null||imageTest.exists()) {
                            downloadObjectVector.remove(notNeededObject);
                        }else{
                            if (imageTest != null&&imageTest.exists()&&SHOULD_REPLACE_FILE){
                                Log.v(CLASS_NAME,"DELETING FILE(missing image):"+imageTest.getAbsolutePath());
                                imageTest.delete();
                            }
                        }
                    }else{
                        File imageTest = null;
                        if(obj.image != null) {
                            imageTest = new File(obj.image.getPath());
                            if (imageTest != null&&imageTest.exists()&&SHOULD_REPLACE_FILE){
                                Log.v(CLASS_NAME,"DELETING FILE(image):"+imageTest.getAbsolutePath());
                                imageTest.delete();
                            }
                        }else{
                            Log.v(CLASS_NAME,"object with null image:"+obj.ServerID);
                        }
                    }
                }while(existingObjects.moveToNext());
            }

            if (existingObjects!= null){
                try{
                    existingObjects.close();
                }catch (Exception e){

                }
            }

            DownloadManager dm = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
            for (int i = 0; i < downloadObjectVector.size(); i++) {
                try {
                    DownloadObject dlObj = downloadObjectVector.get(i);
                    Uri in = dlObj.image;
                    Uri out = Uri.parse(AssetManager.getSingleton().getImageFolder().getPath()).buildUpon().appendPath(in.getLastPathSegment()).scheme("file").build();

                    dm.enqueue(new DownloadManager.Request(in).setDestinationUri(out).setTitle(in.getLastPathSegment()));

                }catch (Exception e){
                    Log.w(CLASS_NAME,"Error with Download queued:",e);
                }
            }
        }
    }).start();
}

如果您需要任何其他信息或代码,请与我们联系!

EDIT1

因此,我决定对此进行详细阐述,以及该问题如何表现在希望它将使图片更加清晰!

我首先通过Android Studio加载应用程序并让它运行足够长时间以便知道所有下载完成后再浏览应用程序以查看哪些图像存在且哪些图像丢失。大多数图像都是正常的。接下来我退出应用程序并使用android任务管理器完全杀死它。然后我通过Android Studio重新启动应用程序。然后我等待确保下载完成并观看LogCat以查看哪些文件被手动删除(通常最多一次)。然后我浏览应用程序,看看哪些图像仍然存在/已添加。似乎每次出现新图像并且新图像消失......通常被标记为手动删除的图像实际上通过正确下载(即“未消失”)被替换。

如果您想要我做任何测试,请告诉我们。

文件观察者测试

首先,这是我第一次使用FileObserver,所以如果我做了一些愚蠢的事情,请指出。这是我的观察员代码:

external = ContextCompat.getExternalFilesDirs(context, null)[0];

    external.mkdirs();

    fileObserver = new FileObserver(external.getPath(),FileObserver.ALL_EVENTS) {
        @Override
        public void onEvent(final int event, final String relPath) {
            String msg = "???";
            switch (event){
                case FileObserver.DELETE:
                    msg = "FILEOB DELETE relPath:"+relPath;
                    break;
                case FileObserver.DELETE_SELF:
                    msg = "FILEOB DELETE_SELF relPath:"+relPath;
                    break;
                case FileObserver.MODIFY:
                    msg = "FILEOB MODIFY relPath:"+relPath;
                    break;
                case FileObserver.MOVE_SELF:
                    msg = "FILEOB MOVE_SELF relPath:"+relPath;
                    break;
                case FileObserver.MOVED_TO:
                    msg = "FILEOB MOVED_TO relPath:"+relPath;
                    break;
                case FileObserver.MOVED_FROM:
                    msg = "FILEOB MOVED_FROM relPath:"+relPath;
                    break;
                case FileObserver.ATTRIB:
                    msg = "FILEOB ATTRIB relPath:"+relPath;
                    break;
                case FileObserver.CREATE:
                    msg = "FILEOB CREATE relPath:"+relPath;
                    break;

                default:
                    msg = "Unknown event:"+event+" at relPath:"+relPath;
            }
            fileObserverHandler.publish(new LogRecord(Level.INFO,msg));
            fileObserverHandler.flush();
        }

        @Override
        public void startWatching() {
            super.startWatching();
            fileObserverHandler.publish(new LogRecord(Level.INFO,"START WATCHING!!!!"));
            fileObserverHandler.flush();
            Log.v("FileObserver","START WATCHING!!!");
        }
    };
    fileObserver.startWatching();

我正在使用处理程序,因为起初我没有startWatching()覆盖并且根本没有得到任何日志记录,并且文档说onEvent发生在它自己的线程上,因此你应该使用处理程序。在课堂上就是这个:

public static Handler fileObserverHandler = new ConsoleHandler();

我从中获得的唯一输出是“START WATCHING !!!”。所以我猜我一定做错了,因为我看到它下载/删除的东西......至少它说它是。

3 个答案:

答案 0 :(得分:1)

您描述的行为听起来像系统正在清理像缓存这样的文件。

在致电getExternalFilesDirs时,您使用"",尝试creating a File/directory with "" can be problematic

Use null instead of "" in your call to getExternalFilesDirs看看是否有帮助

替换

external = ContextCompat.getExternalFilesDirs(context, "")[0];

external = ContextCompat.getExternalFilesDirs(context, null)[0];

答案 1 :(得分:1)

似乎此问题可能与版本4.4.2无关。在一遍又一遍地查看下载代码后,我注意到下载请求没有setMimeType设置。有时似乎DownloadManager在完成时删除了文件,而在某些情况下没有将mime类型设置为下载请求。默认情况下,服务器将文件作为其内容类型发送为application / x-download。尝试添加类似

的内容
 setMimeType(application/octet-stream);

到DownloadManager.Request(in)或适合下载文件的mime类型。希望这会有所帮助。

答案 2 :(得分:0)

我认为这不是与应用程序逻辑相关的问题,而是您正在测试的设备。我有一个平板电脑有同样的问题,我疯了...内部存储(我保存文件)可能会被损坏......