ContentProvider insert()总是在UI线程上运行?

我有一个应用程序需要从服务器提取数据,并将其插入SQLite数据库以响应用户input。 我认为这将是非常简单的 – 从服务器获取数据的代码是AsyncTask的一个相当简单的子类,它的工作原理与我预期的一样,不需要挂接UI线程。 我用一个简单的接口为它实现了callback函数,并将其封装在一个静态类中,所以我的代码如下所示:

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方法或任何我的networking代码,因为它不会发生在那里。

当我尝试通过onFolderContentsResponse方法内的ContentProvider的子类插入到数据库时出现问题; 用户界面总是挂起,而代码执行,导致我相信,尽pipe从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放在自己的Thread中,像这样:

 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中的插入方法是同步的,所以这不应该导致任何问题):

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

只是为了好的措施,我也尝试了这两个解决scheme与另一个AsyncTask的doInBackground方法中的相关代码。 最后,我明确地将MyContentProvider定义为在我的AndroidManifest.xml中的一个单独的进程中:

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

它运行良好,但似乎仍然在UI线程中运行 。 那就是我真的开始把头发撕掉的地步,因为这对我来说根本没有任何意义。 无论我做什么,UI都会在插入过程中挂起。 有没有办法让他们不要?

不要调用mContentResolver.insert() ,而应使用AsyncQueryHandler及其startInsert()方法。 AsyncQueryHandler旨在促进asynchronousContentResolver查询。

我认为你原来的问题可能是你正在你的新线程上调用run方法(这导致执行在当前线程上继续),而不是调用start方法。 我认为这就是Bright Great在他/她的回答中所要expression的意思。 请参阅运行和启动线程之间的区别 。 这是一个常见的错误。

男人,放松自己,而且看起来会更好。 首先,启动一个线程是Func启动不是Func运行,如果你想启动新线程,不仅可以调用func运行。

 new Thread(Runnable runnable).start(); 

那么我敢打赌,使用Handler有时会比AsyncTask更好。

您可以在doInBackground(Integer int)重写方法中运行查询,并更新onPostExecute(Integer int)方法的主UI。