1

我们正在使用内置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();
}

如果您需要任何其他信息或代码,请告诉我!

编辑1

所以我决定通过我的测试来详细说明这个问题,以及这个问题是如何表现出来的,希望它能让画面更加清晰!

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

如果您想让我做任何测试,请告诉我!

文件观察员测试

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

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

我从中得到的唯一输出是“开始观看!!!”。所以我猜我一定做错了什么,因为我看到它正在下载/删除东西……至少它说的是。

4

3 回答 3

1

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

 setMimeType(application/octet-stream);

到 DownloadManager.Request(in) 或适合正在下载的文件的任何 mime 类型。希望这可以帮助。

于 2014-10-21T14:24:28.033 回答
1

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

在您getExternalFilesDirs使用的电话中"",尝试创建File/ 目录""可能会出现问题

在您的通话中使用null代替,""getExternalFilesDirs看看是否有帮助

代替

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

external = ContextCompat.getExternalFilesDirs(context, null)[0];
于 2014-10-18T17:35:23.453 回答
0

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

于 2017-01-15T01:47:53.710 回答