在另一个线程上运行Firebase回调阻止了用户界面

时间:2017-03-06 22:10:39

标签: android multithreading firebase firebase-realtime-database

我知道这个问题可能看似重复,我已经读过十条关于同样事情的其他帖子,但我找不到问题

我的活动中有这个方法:

public void saveResponse(final Response studentResponse, final Content content)
    fb.getReference("...").addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(final DataSnapshot dataSnapshot) {

           new Thread(new Runnable() {
               @Override
               public void run() {
                    Map<String, Object> responseMap = new HashMap<>();
                    responseMap.put("end_date", studentResponse.end_date);
                    responseMap.put("start_date", studentResponse.start_date);
                    responseMap.put("time", studentResponse.time);
                    responseMap.put("points", studentResponse.points);
                    responseMap.put("max_points", studentResponse.max_points);
                    responseMap.put("selected_options", studentResponse.selected_options);
                    if (!TextUtils.isEmpty(studentResponse.free_text))
                        responseMap.put("free_text", studentResponse.free_text);

                    DataSnapshot contentRef = dataSnapshot.child("/sections/" + currentSection + "/sections/" + currentSubsection + "/contents/" + content.id);
                    final int oldPoints = contentRef.hasChild("points") ? contentRef.child("points").getValue(int.class) : 0;
                    contentRef.getRef().setValue(responseMap);
                    contentRef.getRef().setPriority(ServerValue.TIMESTAMP);

                    DataSnapshot subSectionRef = dataSnapshot.child("/sections/" + currentSection + "/sections/" + currentSubsection);
                    long subSectionPoints = (subSectionRef.hasChild("points") ? subSectionRef.child("points").getValue(long.class) : 0) + studentResponse.points - oldPoints;
                    subSectionRef.child("points").getRef().setValue(subSectionPoints);

                    int indexOf = currentContents.indexOf(content) + 1;
                    if(indexOf > 0 && indexOf < currentContents.size()) {
                        CourseContent content = currentContents.get(indexOf);
                        subSectionRef.child("currentPosition").getRef().setValue(content.order);
                    }

                    DataSnapshot sectionRef = dataSnapshot.child("/sections/" + currentSection);
                    long sectionPoints = (sectionRef.hasChild("points") ? sectionRef.child("points").getValue(long.class) : 0) + studentResponse.points - oldPoints;
                    sectionRef.child("points").getRef().setValue(sectionPoints);

                    long coursePoints = (dataSnapshot.hasChild("points") ? dataSnapshot.child("points").getValue(long.class) : 0) + studentResponse.points - oldPoints;
                    dataSnapshot.child("points").getRef().setValue(coursePoints);
                    dataSnapshot.getRef().setPriority(MAX_SAFE_INTEGER - coursePoints);

                    int completed = 0;
                    for (DataSnapshot sect : dataSnapshot.child("sections").getChildren()) {
                        for (DataSnapshot subSect : sect.child("sections").getChildren()) {
                            int currPos = subSect.hasChild("currentPosition") ? subSect.child("currentPosition").getValue(int.class) : 0;
                            completed += currPos;
                        }
                    }

                    double progress = totalContents > 0 ? (double) completed / (double) totalContents : 0;
                    dataSnapshot.child("progress").getRef().setValue(progress);
               }
           }.start();
        }
        ...
    });
}
单击处理程序中的

我调用此方法,然后更改片段(使用自定义动画)。

问题是,片段转换不顺畅,它会冻结一点,如果我在runnable中评论所有内容,那么它会顺利运行。我也尝试过AsyncTask,同样的事情发生了。

在runnable中,我只是查询dataSnapshot及其子节点,并设置一些值(dataSnapshot.child("item").getRef().setValue(x)

另一个奇怪的事情是,如果我在run()中放置一个断点,它也可以顺利运行。

3 个答案:

答案 0 :(得分:0)

我认为问题在于你的方法的逻辑。

侦听器onDataChange()处于活动状态,它将响应数据的任何更改。我的意思是如果您更改onDataChange()方法中的数据,每次使用(dataSnapshot.child(&#34; item&#34;)。getRef()。setValue(x)))设置值时都会调用它,所以,它类似于做一个&#34;递归&#34;打电话没有退出。

为了解决此问题,您应该在点击事件中获取要更改的内容的密钥,然后使用

mDatabase = FirebaseDatabase.getInstance()。getReference(); mDatabase.child(&#34;键&#34)。子(&#34;项目&#34)。的setValue(X);

查看https://firebase.google.com/docs/database/android/read-and-write了解详情

答案 1 :(得分:0)

生成的线程继承创建它的线程的优先级。尝试降低工作线程的优先级,以防止它与UI线程竞争:

@Override
public void onDataChange(final DataSnapshot dataSnapshot) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            ...
        }).start();

答案 2 :(得分:0)

每次调用onDataChange方法都会创建一个新的线程,并且奇怪的是:&#34;如果我在run()中放置一个断点,它也可以顺利运行。&#34; 可能是你应该检查是否创建了太多的线程。