Java - Android:线程被调用(运行)两次

时间:2014-05-26 10:17:03

标签: android multithreading android-asynctask thread-safety

我想要一些关于Java的帮助 - Android MultiThreading

在学习以多线程方式开发我的应用程序以利用不断增长的多核设备市场份额(大多数设备现在是四核,有些甚至是octo-core)时,我跑了一个我的线程正在调用两次或运行两次的情况。

我不知道为什么以及如何。

[编辑3] 好吧,我缩小了问题范围:我从AsyncTask方法调用了onResume()。虽然我的应用程序没有失去焦点(这意味着调用onPause()然后在返回焦点时回到onResume(),在这种情况下我的线程将运行两次)在测试期间,我解决了问题将呼叫转移到FetchFriendsList到另一个地方。 到目前为止一切都那么好,但是因为在我的测试中应用程序没有松散焦点或者它确实没有,但我无法见证它(!),我认为还有另一个原因,所以我说我的问题没有完全解决..至少目前。它确实有效。也许我确实解决了这个问题,但我不知道如何:( [编辑结束3]

我正在实施最后一个Facebook SDK,我正在使用它来获取最终用户朋友列表,这似乎可以完成这项工作。 由于我在AsyncTask中运行此操作,因此我没有使用request.executeAsync()。 相反,我使用的是request.executeAndWait()。 Facebook JavaDoc确实声明只有在我不在主UI线程中才能使用此方法,否则我会得到NetworkOnMainThreadException

无论如何,这是奇怪的行为发生的地方。

private final ArrayList<GraphUser> userFriendsList = new ArrayList<GraphUser>(); 
public final void fetchFriendsList() {
    if (this.session != null && this.session.isOpened()) {
        final Request requestUserFriendsList = Request.newMyFriendsRequest(
                this.session, new Request.GraphUserListCallback()                                         
                    public final void onCompleted(final List<GraphUser> users, final Response response) {
                        if (users != null && users.size() > 0) {
                            Log.v("Retrieved Friends List -> ", String.valueOf(users.size()));
                            userFriendsList.addAll(users);
                        }
                    }
                }
        );
        if (this.asyncFlag)
            requestUserFriendsList.executeAsync();
        else
            requestUserFriendsList.executeAndWait();
    }
}

在我的情况下,asyncFlag设置为false,因为我需要按特定顺序同步执行任务:

  1. 获取用户好友列表(不在主(UI)线程上)
  2. 在设备上保存好友列表(单独的新主题)
  3. 在服务器上保存好友列表(单独的新主题)
  4. 遵循此模式,行userFriendsList.addAll(users);称为两次。 在logcat中,Log.v也显示两次,最后用调试器查看,用户朋友列表的内容由重复项组成。

    但并非全部......第2步和第3步确实是两个独立的线程,它们都是在同一个方法中创建和生成的:public final void asyncSaveFacebookFriendsList()

    猜猜看,这种方法甚至被称为两次

    为什么?

    一开始我正在调用第2步和第3步的方法:

    [...]
    userFriendsList.addAll(users);
    asyncSaveFacebookFriendsList(); // it was private before
    [...]
    

    这是问题的开始,因为两条线路都运行了两次。

    所以我想,好吧,我稍后会这样称呼它:

    [...]
    fetchFriendsList();
    asyncSaveFacebookFriendsList(); // it is now public
    [...]
    

    但问题仍然存在。 如果我不拨打public final void asyncSaveFacebookFriendsList(),则不会运行两次

    为什么会出现这个问题?有没有我在Java Threads中没有得到的东西?

    我不认为这与Facebook SDK有某种关系,因为遵循相同的模式(同时也是这样),我在获取和存储最终用户的Twitter好友列表时遇到了同样的问题。

    所以我确实相信我做错了什么。有人知道线程被调用两次的可能情况吗?

    注意:所有线程都以这种方式启动:thread.start()。我没有使用任何ThreadPoolExecutorService

    如果您需要更多背景背景: AsyncTask的内容:(无需想知道为什么Void和Long,我删除了与之无关的相关代码)

    private final class FetchFriendsLists extends AsyncTask<Long, Integer, Void> {
            protected final Void doInBackground(final Long... params) {
                if (params[0] != Long.valueOf(-1)) {
                    [...]
                    twitterAPI.fetchUserFriendsList();
                    publishProgress(1, -1);
                }
                if (params[1] == Long.valueOf(0)) {
                    [...]
                    facebookAPI.fetchFriendsList();
                    publishProgress(-1, 0);
                }
                return null;
            }
    
            protected final void onProgressUpdate(Integer... flags) {
                super.onProgressUpdate(flags);
                if (flags[0] != -1)
                    twitterAPI.asyncSaveFacebookFriendsList();
                if (flags[1] == 0)
                    facebookAPI.asyncSaveFacebookFriendsList();
            }
        }
    

    如您所见,我开始在主要UI线程上运行的onPublishProgress()中的第2步和第3步。在doInBackground()方法中出现问题:两种情况都会出现问题!

    [编辑] 经过进一步的测试,似乎任何类型的代码实际上都运行了两次。 我创建了一个名为test的简单方法,其中打印一个计数器。计数器也增加了两倍!

1 个答案:

答案 0 :(得分:1)

为什么使用onProgressUpdate?¿?

  

onProgressUpdate(进度......),[...]。此方法用于显示任何形式的进度   后台计算仍在执行时的用户界面。   例如,它可用于为进度条设置动画或显示登录   文本字段。

这不是在请愿结束时使用,而是在进展增加时使用。
阅读本文:
http://developer.android.com/reference/android/os/AsyncTask.html

您需要使用:

 protected void onPostExecute(Long result) {