当前位置: 首页 > 面试题库 >

ContentProvider insert()始终在UI线程上运行吗?

禄星腾
2023-03-14
问题内容

我有一个需要从服务器提取数据并将其插入到SQLite数据库中以响应用户输入的应用程序。我认为这将非常简单-
从服务器提取数据的代码是AsyncTask的一个非常简单的子类,并且它的工作原理完全符合我的预期,而无需挂起UI线程。我使用一个简单的接口为其实现了回调功能,并将其包装在静态类中,因此我的代码如下所示:

MyServerCaller.getFolderContents(folderId, new OnFolderContentsResponseListener() {
    @Override
    public void onFolderContentsResponse(final List<FilesystemEntry> contents) {
        // do something with contents
    }
}

一切还不错。即使服务器花费一个小时来检索数据,UI仍然可以平稳运行,因为getFolderContents中的代码在AsyncTask的doInBackground方法中运行(该方法位于与UI分开的线程中)。在getFolderContents方法的最后,调用onFolderContentsResponse并传递从服务器接收的FilesystemEntry的列表。我只是真的说了所有这些,以便希望可以清楚地知道我的问题不在getFolderContents方法或我的任何网络代码中,因为它从来没有发生过。

当我尝试通过onFolderContentsResponse方法中的ContentProvider的子类插入数据库时​​,就会出现问题。在执行该代码时,UI总是挂起,这使我相信,尽管从AsyncTask的doInBackground方法调用了该插入,但是它们仍在UI线程上运行。有问题的代码如下所示:

MyServerCaller.getFolderContents(folderId, new OnFolderContentsResponseListener() {
    @Override
    public void onFolderContentsResponse(final List<FilesystemEntry> contents) {
        insertContentsIntoDB(contents);
    }
}

insertContentsIntoDB方法:

void insertContentsIntoDB(final List<FilesystemEntry> contents) {
    for (FilesystemEntry entry : contents) {
        ContentValues values = new ContentValues();
        values.put(COLUMN_1, entry.attr1);
        values.put(COLUMN_2, entry.attr2);
        // etc.

        mContentResolver.insert(MyContentProvider.CONTENT_URI, values);
    }
}

其中mContentResolver先前已设置为getContentResolver()方法的结果。

我尝试将insertContentsIntoDB放在其自己的线程中,如下所示:

MyServerCaller.getFolderContents(folderId, new OnFolderContentsResponseListener() {
    @Override
    public void onFolderContentsResponse(final List<FilesystemEntry> contents) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                insertContentsIntoDB(contents);
            }
        }).run();
    }
}

我还尝试过在其自己的线程中运行每个单独的插入(MyContentProvider中的insert方法是同步的,因此不会在此处引起任何问题):

void insertContentsIntoDB(final List<FilesystemEntry> contents) {
    for (FilesystemEntry entry : contents) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                ContentValues values = new ContentValues();
                values.put(COLUMN_1, entry.attr1);
                values.put(COLUMN_2, entry.attr2);
                // etc.
                mContentResolver.insert(MyContentProvider.CONTENT_URI, values);
            }
        }).run();
    }
}

出于很好的考虑,我还在另一个AsyncTask的doInBackground方法中用相关代码尝试了这两种解决方案。最后,我在AndroidManifest.xml中将MyContentProvider明确定义为处于单独的进程中:

<provider android:name=".MyContentProvider" android:process=":remote"/>

它运行正常,但 似乎仍在UI线程中运行
。这就是我真正开始将头发撕掉的关键所在,因为这对我完全没有意义。无论我做什么,UI总是在插入过程中挂起。有什么办法让他们不要呢?


问题答案:

与其调用mContentResolver.insert(),请使用AsyncQueryHandler及其startInsert()方法。AsyncQueryHandler设计用于促进异步ContentResolver查询。



 类似资料:
  • 我有一个ScheduleTimer类,它可以处理日期数组。这是: 如果我像Java应用程序一样运行它,而不是像android一样运行,并且它在控制台中每隔一秒打印一次,那么它就可以正常工作。但是当在android环境中运行它时,它要么说UI线程不能从任何其他线程接触,要么它在类ScheduleTimer的方法中给了我null点异常。 我这样使用它:

  • 在UI线程中运行代码的观点中,以下两者之间有什么区别吗: 或 而且

  • 问题内容: 编辑:我现在确定问题与保存所有其他命令的循环有关, 因为我已将其注释掉,并且在部署应用程序时没有附加的异常。我不确定它有多重要,但是我的实现看起来像这样: 因此,现在该线程在部署应用程序时运行,但是由于注释了循环,因此它没有实际意义。 当我的应用程序加载时,我需要在后台运行一个线程,并不断(无超时)检查某个对象队列。当然,一旦有了对象,它就会“照顾它们”,然后继续检查队列。 目前,我正

  • 我有一个简单的Java代码: 文件夹结构为: 在文件夹中,有和文件。 null null 这里怎么了?

  • 问题内容: 在我的应用程序中,我对一些本机代码进行了包装,这是通过JNI桥调用的。此本地代码需要在单独的线程中执行(并行处理)。但是,问题在于代码有时“挂起”,因此线程需要“强制”终止。不幸的是,我还没有找到任何“微妙的”方法来这样做:一般建议是告诉线程中的代码正常退出,但是我无法使用此本地代码(以上均为第三方代码)来执行此操作。 我使用Java Concurrent API进行任务提交: 只会中