Android 在另一个线程上运行Firebase回调会阻塞UI

Android 在另一个线程上运行Firebase回调会阻塞UI,android,multithreading,firebase,firebase-realtime-database,Android,Multithreading,Firebase,Firebase Realtime Database,我知道这个问题可能看起来是重复的,我像其他十条线索一样读过同样的东西,但我找不到问题所在 我在我的活动中使用了以下方法: public void saveResponse(final Response studentResponse, final Content content) fb.getReference("...").addListenerForSingleValueEvent(new ValueEventListener() { @Override

我知道这个问题可能看起来是重复的,我像其他十条线索一样读过同样的东西,但我找不到问题所在

我在我的活动中使用了以下方法:

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();
        }
        ...
    });
}
public void saveResponse(最终响应studentResponse,最终内容)
fb.getReference(“…”).addListenerForSingleValueEvent(新的ValueEventListener(){
@凌驾
公共无效onDataChange(最终数据快照数据快照){
新线程(newrunnable()){
@凌驾
公开募捐{
Map responseMap=newhashmap();
响应映射put(“结束日期”,studentResponse.end\u日期);
响应映射put(“开始日期”,studentResponse.start\u日期);
响应映射放置(“时间”,studentResponse.time);
响应映射放置(“点”,studentResponse.points);
响应映射放置(“最大点数”,学生响应最大点数);
响应映射看跌期权(“选定选项”,studentResponse.selected\u选项);
如果(!TextUtils.isEmpty(studentResponse.free_text))
响应映射put(“自由文本”,学生响应自由文本);
DataSnapshot contentRef=DataSnapshot.child(“/sections/”+currentSection+“/sections/”+currentSubsection+“/contents/”+content.id);
final int oldPoints=contentRef.hasChild(“点”)?contentRef.child(“点”).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(“点”).getRef().setValue(subSectionPoints);
int indexOf=currentContents.indexOf(content)+1;
if(indexOf>0&&indexOf0?(双)完成/(双)总内容:0;
dataSnapshot.child(“进度”).getRef().setValue(进度);
}
}.start();
}
...
});
}
在单击处理程序中,我调用此方法,然后更改片段(使用自定义动画)

问题是,片段转换不是平滑的,它冻结了一点,如果我对runnable中的所有内容进行注释,那么它就会平滑运行。我也尝试过使用AsyncTask,同样的情况也会发生

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


另一件奇怪的事情是,如果我在run()中设置断点,它也会顺利运行。

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

侦听器onDataChange()是活动的,它将响应数据的任何更改。我的意思是,如果在onDataChange()方法中更改数据,则每次使用(dataSnapshot.child(“item”).getRef().setValue(x))设置值时都会调用它,因此,它类似于不退出的“递归”调用

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

mDatabase=FirebaseDatabase.getInstance().getReference(); mDatabase.child(“key”).child(“item”).setValue(x)


检查更多信息

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

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

每次调用onDataChange方法都会创建一个新线程,奇怪的是:“如果我在run()中放置了一个断点,它也可以顺利工作。”
可能您应该检查是否创建了太多线程。

可能是Android处理程序而不是创建新线程?“当您想在UI线程中执行操作时,应该使用Handler.post()”,我不想在UI线程中执行此操作,这就是我创建另一个线程的原因。请更新此post以将代码包含在
run()
方法中。@qbix在
run()
method
saveResponse()中添加了代码
参数
响应
未使用。你发的代码是不是有错?是否应该是
studentResponse
currentSection
curre在哪里