由于异步Firebase调用,主线程做了太多工作?

我的应用程序上一直出现错误,上面写着I/Choreographer: Skipped 252 frames! The application may be doing too much work on its main thread. I/Choreographer: Skipped 252 frames! The application may be doing too much work on its main thread. 我认为这会导致我的UI出现一些滞后,这是我不想要的。 我认为这是因为当我执行Firebase查询时,当我执行onDataChange() ,它似乎总是在主UI线程中执行。 我有大约5个类似于以下内容的Firebase查询。 因此,我尝试将我的代码从onDataChange()方法移动到AsyncTask并更新AsyncTask onPostExecute()方法上的UI线程。 但是,当我尝试这个时, onPostExecute()方法永远不会完成。 这是我的尝试:

 public void getPublicPosts(final View progressOverlay, final View fragmentView, final Context context) { //Need to do order by / equal to. Firebase postsRef = firebaseRef.child("Posts"); Query query = postsRef.orderByChild("privacy").equalTo("Public"); query.keepSynced(true); query.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { for (final DataSnapshot postSnapShot : dataSnapshot.getChildren()) { AsyncTask task = new AsyncTask() { @Override protected Long doInBackground(URL... params) { Post post = postSnapShot.getValue(Post.class); List publicPosts = application.getPublicAdapter().getPosts(); if (post.getPrivacy().equals("Public") && application.getPublicAdapter().containsId(publicPosts, post.getId()) == null) { application.getPublicAdapter().getPosts().add(0, post); } return null; } @Override protected void onProgressUpdate(Integer... progress) { } @Override protected void onPostExecute(Long result) { System.out.println("Finished executing public"); populateNewsFeedList(fragmentView, application.getPublicAdapter(), TabEnum.Public, context); if (progressOverlay.getVisibility() == View.VISIBLE) { System.out.println("getPublicPosts: DONE"); AndroidUtils.animateView(progressOverlay, View.GONE, 0, 200); fragmentView.findViewById(R.id.rv_public_feed).setVisibility(View.VISIBLE); } } }; `task.execute();` } } @Override public void onCancelled(FirebaseError firebaseError) { } }); } 

任何帮助都会有所帮助。 如果有人能帮助我,这将是伟大的。 谢谢!

编辑:添加函数以创建AsyncTask

 public AsyncTask asyncTaskWrapper(final DataSnapshot dataSnapshot, final View progressOverlay, final View fragmentView, final Context context) { AsyncTask task = new AsyncTask() { @Override protected Long doInBackground(URL... params) { for (final DataSnapshot postSnapShot : dataSnapshot.getChildren()) { Post post = postSnapShot.getValue(Post.class); List publicPosts = application.getPublicAdapter().getPosts(); if (post.getPrivacy() == PrivacyEnum.Public && application.getPublicAdapter().containsId(publicPosts, post.getId()) == null) { application.getPublicAdapter().getPosts().add(0, post); } } return null; } @Override protected void onProgressUpdate(Integer... progress) { } @Override protected void onPostExecute(Long result) { System.out.println("Finished executing public"); TabsUtil.populateNewsFeedList(fragmentView, application.getPublicAdapter(), TabEnum.Public, context); if (progressOverlay.getVisibility() == View.VISIBLE) { System.out.println("getPublicPosts: GONE"); AndroidUtils.animateView(progressOverlay, View.GONE, 0, 200); fragmentView.findViewById(R.id.rv_public_feed).setVisibility(View.VISIBLE); } } }; return task; } 

PublicPostsfunction:

 public void getPublicPosts(final View progressOverlay, final View fragmentView, final Context context) { //Need to do order by / equal to. Firebase postsRef = firebaseRef.child("Posts"); Query query = postsRef.orderByChild("privacy").equalTo(PrivacyEnum.Public.toString()); query.keepSynced(true); query.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { asyncTaskWrapper(dataSnapshot, progressOverlay, fragmentView, context); } @Override public void onCancelled(FirebaseError firebaseError) { TabsUtil.populateNewsFeedList(fragmentView, application.getPublicAdapter(), TabEnum.Public, context); } }); } 

您的主线程可能很慢,因为您正在运行包含许多对象的循环。 但是,不知道你究竟在执行什么,这只是猜测。

但是我的AsyncTask存在问题,我认为它不会与您发布的代码一起使用。

AsyncTask期待一系列URL。 你没有通过任何。 如果不需要URL作为输入,那么只需使用:

 AsyncTask task = new AsyncTask() 

你试着排除故障:

  AsyncTask task = new AsyncTask() { @Override protected Boolean doInBackground(URL... params) { for (final DataSnapshot postSnapShot : dataSnapshot.getChildren()) { Post post = postSnapShot.getValue(Post.class); List publicPosts = application.getPublicAdapter().getPosts(); if (post.getPrivacy() == PrivacyEnum.Public && application.getPublicAdapter().containsId(publicPosts, post.getId()) == null) { application.getPublicAdapter().getPosts().add(0, post); } } return true; } @Override protected void onPostExecute(Boolean result) { if(result){ System.out.println("Finished executing public"); TabsUtil.populateNewsFeedList(fragmentView, application.getPublicAdapter(), TabEnum.Public, context); if (progressOverlay.getVisibility() == View.VISIBLE) { System.out.println("getPublicPosts: GONE"); AndroidUtils.animateView(progressOverlay, View.GONE, 0, 200); fragmentView.findViewById(R.id.rv_public_feed).setVisibility(View.VISIBLE); } } } }; 

然后通过触发执行任务:

 URL[] urls = new URL[2]; urls[0] = new URL(...); urls[1] = new URL(...); task.execute(urls); 

使用IDE中的调试function,如果代码失败,则回发确切的位置。

你不是在你创建的AsyncTask上调用execute()所以它永远不会被触发。

在创建AsyncTask之后,在其上调用execute(URL … params)以便它将被执行。

此外,我看到你没有使用你传递的参数,所以你可以通过任何东西,它会工作。

您最好在IntentService上执行网络请求。 这很容易并且防止界面冻结和/或“应用程序可能在其主线程上做了太多工作”。

看一眼:

Android开发者文档中的IntentService

在你的代码中,你调用AsynTast n时间你应该调用一次for:for循环用于doinbackground()和onProgressUpdate()你可以更新UI而不是onPostExecute(),这将改善代码有点但不完全,你应该在onPreexecute上使用进度条并在onPostEcecute()中关闭进度条,只是为了你的想法我写了下面的代码,但是没有完全引用它,因为我没有测试过这个,但是形成这将获得一些想法。

 AsyncTask task = new AsyncTask() { @Override protected Long doInBackground(URL... params) { for (final DataSnapshot postSnapShot : dataSnapshot.getChildren()) { Post post = postSnapShot.getValue(Post.class); List publicPosts = application.getPublicAdapter().getPosts(); if (post.getPrivacy().equals("Public") && application.getPublicAdapter().containsId(publicPosts, post.getId()) == null) { application.getPublicAdapter().getPosts().add(0, post); } publishProgress((1); } return null; } @Override protected void onProgressUpdate(Integer... progress) { System.out.println("Finished executing public"); populateNewsFeedList(fragmentView, application.getPublicAdapter(), TabEnum.Public, context); if (progressOverlay.getVisibility() == View.VISIBLE) { System.out.println("getPublicPosts: DONE"); AndroidUtils.animateView(progressOverlay, View.GONE, 0, 200); fragmentView.findViewById(R.id.rv_public_feed).setVisibility(View.VISIBLE); } } } @Override protected void onPostExecute(Long result) { } } }; 

如果你创建了一个扩展AsyncTask的类并在你的ondatachange方法中调用它,它会更清晰,更容易维护:

 DoingStuff doTask = new DoingStuff(); doTask.execute(...); 

这样,您可以在工作线程中安全地执行Firebase连接,并使用您检索到的任何结果更新UI。

您可以尝试以下某些操作:

  • 而不是创建和执行多个N AsyncTasks,只需创建并执行一个内部有N个快照循环的单个。
  • 在onPostExecute()中检查populateNewsFeedList方法是否没有进行密集数据操作,如果是这样,您也可以在新的AsyncTask中执行它并在完成后更新UI。
  • 您还可以尝试通过将runnable传递给post方法来更新视图,这会将主要线程消息队列中的runnable排入队列。
  • 您可以在ServiceIntentService中运行长时间运行的操作,并通过ContentProviderBroadcasts更新UI。

希望有所帮助。

建议:

  1. 从UI主线程中删除繁重的工作,在其他线程中执行它们。

2.当其他线程完成繁重的工作时,如果需要更新UI,请使用Handler将msg发送到UI主线程,然后在主线程上更新UI。