Android:如何显示最近打开的文件列表?

时间:2015-06-05 09:22:19

标签: java android epublib

有人可以向我提供有关如何检索文件夹中最近打开的文件列表的指南吗?

在我的应用程序中,我有一个包含.epub个文件的文件夹。 我想显示用户最近阅读/打开的书籍的排序列表。

提前谢谢。

2 个答案:

答案 0 :(得分:1)

问题实际上并不是那么简单。 原因有两个-历史记录的持久性和IO阻止操作。

实际上,为了确保历史的持久性,我们可以使用一些解决方案:

  • 数据库(似乎最合理,但需要付出最大的努力)
  • 内部文件(应该是最简单的方法)
  • 共享的偏好

因此,我使用了第二种方法。在内存中,我只保留ArrayList<Uri>,然后将其保存到文件中,然后将其转换为List<String>,因为android.net.Uri不支持序列化。 在内部存储器中,我使用ObjectIOStream保存序列化的对象。

因此,请参见代码:

public class FileHistory {
    private static final String FILE_NAME = "file-history-v1";
    private static final int HISTORY_SIZE = 20;

    @NonNull
    private final Context mAppContext;
    // This is a executor where I can post any runnable
    // and all of them will be executed in one pipeline
    // keeping posting order.
    @NonNull
    private final OneThreadExecutor mExecutor;

    @Nullable
    private ArrayList<Uri> mInternalFilesHistory;
    @NonNull
    private MutableLiveData<List<Uri>> mFilesHistory = new MutableLiveData<>();

    public FileHistory(@NonNull final Context appContext,
                       @NonNull final OneThreadExecutor executor) {
        this.mAppContext = appContext;
        this.mExecutor = executor;
        loadHistory();
    }

    public void addEntry(@NonNull final Uri entry) {
        if (mInternalFilesHistory == null) {
            // The fileHistory is not ready yet.
            // Schedule adding entry as next task of serial executor.
            mExecutor.execute(() -> addEntry(entry));
            return;
        }

        // Remove entry if exists and add it as first element.
        CollectionUtils.removeFirst(mInternalFilesHistory, uri -> uri.equals(entry));
        mInternalFilesHistory.add(0, entry);
        if (mInternalFilesHistory.size() > HISTORY_SIZE) {
            ArrayList<Uri> trimmed = new ArrayList<>(HISTORY_SIZE + 1);
            trimmed.addAll(mInternalFilesHistory.subList(0, HISTORY_SIZE));
            mInternalFilesHistory = trimmed;
        }

        mExecutor.execute(this::rePostHistory);
        mExecutor.execute(this::saveToInternalStorage);
    }

    @NonNull
    public MutableLiveData<List<Uri>> getFilesHistory() {
        return mFilesHistory;
    }

    private void loadHistory() {
        mExecutor.execute(this::loadFromInternalStorage);
        mExecutor.execute(this::rePostHistory);
    }

    private void rePostHistory() {
        if (mInternalFilesHistory != null) {
            mFilesHistory.postValue(Collections.unmodifiableList(mInternalFilesHistory));
        }
    }

    @SuppressWarnings("unchecked")
    @WorkerThread
    private void loadFromInternalStorage() {
        try {
            FileInputStream fis = mAppContext.openFileInput(FILE_NAME);
            ObjectInputStream ois = new ObjectInputStream(fis);

            ArrayList<String> entries = (ArrayList<String>) ois.readObject();
            List<Uri> mapped = CollectionUtils.map(entries, Uri::parse);

            if (mInternalFilesHistory == null) {
                mInternalFilesHistory = new ArrayList<>(HISTORY_SIZE + 1);
            } else {
                mInternalFilesHistory.clear();
            }
            mInternalFilesHistory.addAll(mapped);

            fis.close();
            ois.close();
        } catch (Exception ex) {
            mInternalFilesHistory = new ArrayList<>(HISTORY_SIZE + 1);
        }
    }

    @WorkerThread
    private void saveToInternalStorage() {
        try {
            FileOutputStream fis = mAppContext.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
            ObjectOutputStream oos = new ObjectOutputStream(fis);

            if (mInternalFilesHistory == null) {
                mInternalFilesHistory = new ArrayList<>();
            }

            List<String> converted = CollectionUtils.map(mInternalFilesHistory, Uri::toString);
            oos.writeObject(converted);

            fis.close();
            oos.close();
        } catch (IOException ignored) {
        }
    }

}

如您所见,内部存储用于保留该文件。因此,无需添加任何其他权限。 通过使用执行程序来确保同步,该执行程序将一个接一个地执行所有请求,因此即使IO速度较慢或请求将被保存。

我们不会使用IO操作阻止线程,因为所有使用IO的操作都在WorkerThread上。关于结果,我们将通过LiveData的{​​{1}}通知我们

我认为这是最简单的解决方案。如果我们需要保留统计信息,日期等,则可以保存android.arch.,只要List<MyHistoryEntry>可以序列化即可。

作为一种更好的方法,我建议使用数据库(更轻松的迁移等)。

答案 1 :(得分:0)

我只是在分享我的想法。每当用户打开文件时,在ArrayList中添加文件名或ID。您可以轻松获取文件名,然后显示它。 ArrayList是其中一种方法。存储文件名的方法有很多种。

相关问题