主线程因asynchronousFirebase调用而做了太多工作?

我一直在我的应用程序上出现错误,说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. 我认为这会导致我的用户界面,我不想要一些滞后。 我认为这是因为当我执行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<URL, Integer, Long>() { @Override protected Long doInBackground(URL... params) { Post post = postSnapShot.getValue(Post.class); List<Post> 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) { } }); } 

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

编辑:添加函数来创buildAsyncTask

 public AsyncTask asyncTaskWrapper(final DataSnapshot dataSnapshot, final View progressOverlay, final View fragmentView, final Context context) { AsyncTask task = new AsyncTask<URL, Integer, Long>() { @Override protected Long doInBackground(URL... params) { for (final DataSnapshot postSnapShot : dataSnapshot.getChildren()) { Post post = postSnapShot.getValue(Post.class); List<Post> 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; } 

公共邮政function:

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

Solutions Collecting From Web of "主线程因asynchronousFirebase调用而做了太多工作?"

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

但是我的AsyncTask存在一个问题,我认为它不能和你发布的代码一起工作。

AsyncTask需要一个URL数组。 你没有通过任何。 如果不需要URL作为input,那么只需使用:

 AsyncTask task = new AsyncTask<Void, Boolean, Boolean>() 

你如何尝试排除故障:

  AsyncTask task = new AsyncTask<URL, Boolean, Boolean>() { @Override protected Boolean doInBackground(URL... params) { for (final DataSnapshot postSnapShot : dataSnapshot.getChildren()) { Post post = postSnapShot.getValue(Post.class); List<Post> 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中的debuggingfunction并回传确切位置。

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

在创buildAsyncTask之后,调用execute(URL … params)就可以执行了。

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

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

看一眼:

Android开发者文档中的IntentService

在你的代码中,你调用了AsynTast n次,你应该调用它一次。for:每个循环用于doinbackground()和onProgressUpdate(),你可以更新UI而不是onPostExecute(),这会改善代码有点但不完全,你应该在onPreexecute上使用进度条,并closuresonPostEcecute()的进度条,只是为了你的想法我写了下面的代码,但不要完全引用它,因为我还没有testing过,但forms这将得到一些想法。

 AsyncTask task = new AsyncTask<URL, Integer, Long>() { @Override protected Long doInBackground(URL... params) { for (final DataSnapshot postSnapShot : dataSnapshot.getChildren()) { Post post = postSnapShot.getValue(Post.class); List<Post> 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) { } } }; 

如果你已经创build了一个扩展一个AsyncTask的类并且在你的ondatachange方法中调用它,那将会更加简洁和容易。

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

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

你可以尝试下面的一些:

  • 而不是创build和执行多个N的AsyncTasks,只需创build并执行一个N快照循环里面。
  • 在onPostExecute()检查populateNewsFeedList方法是不是在做密集的数据操作,如果是的话,你也可以在新的AsyncTask中执行它,并在完成后更新UI。
  • 你也可以尝试通过传递一个可运行的post方法来更新视图,这将使主线程消息队列中的runnables排队。
  • 您可以在ServiceIntentService中运行长时间运行的操作,并通过ContentProviderBroadcasts更新您的UI。

希望有所帮助。

build议:

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

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