【发布时间】:2016-09-27 13:07:20
【问题描述】:
我需要从正在进行事务的异步任务访问 Firebase 数据库。
所以我的设置是,我有一个 AsyncTask。在其doInBackground 方法中,我调用了另一个方法,其中包含我运行事务的逻辑。在事务的doTransaction 方法中,我需要从不同的路径访问数据并生成新数据(如一些统计信息)。
看起来像这样:
public class MyAsyncTask extends AsyncTask<String,Void,Void> {
@Override
protected Void doInBackground(String... params) {
String para1 = params[0];
String para2 = params[1];
performCalculations(para1,para2);
return null;
}
public void performCalculation(String para1, String para2) {
DatbaseReference ref = FirebaseDatabase.getInstance().getReference().child(para1);
// Run the transaction here
ref.runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData mutableData) {
TaskCompletionSource<DataSnapshot> taskCompletionSource = new TaskCompletionSource<>();
DatabaseReference ref2 = FirebaseDatabase.getInstance().getReference().child(param2);
ref2.addListenerForSingleValueEvent(new MyValueEventListener(taskCompletionSource));
try {
dataSnapshot = Tasks.await(taskCompletionSource.getTask());
// DOING SOME AWESOME THINGS HERE
// And updating the mutable Data
} catch (ExecutionException | InterruptedException e) {
Log.v(TAG, "Exception Catched");
e.printStackTrace();
}
mutableData.setValue(stats);
return Transaction.success(mutableData);
}
@Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
if (databaseError != null) {
Log.d(TAG, "onComplete: Error: " + databaseError.getMessage());
} else {
Log.d(TAG, "onComplete: Transaction was successful");
}
}
}
}
private class MyValueEventListener implements ValueEventListener {
private final TaskCompletionSource<DataSnapshot> taskSource;
public MyValueEventListener(TaskCompletionSource<DataSnapshot> taskSource) {
this.taskSource = taskSource;
}
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.v(TAG, "Looks like MyValueEventListener received the data");
taskSource.setResult(dataSnapshot);
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.v(TAG, "Looks like MyValueEventListener thrown an error");
taskSource.setException(databaseError.toException());
}
}
}
将日志放在各处,我遇到了它到达Tasks.await 语句。但是,onDataChanged 回调永远不会被调用。
它卡在那个点上。没有错误。没有例外。
最大的问题是,从那时起,它会停止整个应用程序的所有回调。我所有的活动都被阻止了,因为它从不调用onDataChanged。看起来它在内部崩溃或被线程阻塞。
发生了什么事?谢谢。
编辑:
因此,为了从事务中的 ref 获取最新数据,我将变量作为类的一部分。并将值事件侦听器附加到它。所以它会一直保持更新。但是,如果离线排队事务在触发值事件侦听器之前开始运行怎么办?离线一段时间后,上线后先执行什么优先级?
这是我更新的代码:
public class MyAsyncTask extends AsyncTask<String,Void,Void> {
DataSnapshot mDataSnapshot;
ValueEventListener mListener;
DatabaseReference ref2;
@Override
protected Void doInBackground(String... params) {
String para1 = params[0];
String para2 = params[1];
performCalculations(para1,para2);
return null;
}
public void performCalculation(String para1, String para2) {
TaskCompletionSource<DataSnapshot> taskCompletionSource = new TaskCompletionSource<>();
ref2 = FirebaseDatabase.getInstance().getReference().child(param2);
ref2.addListenerForSingleValueEvent(new MyValueEventListener(taskCompletionSource));
try {
// Get the data first time before you proceed
dataSnapshot = Tasks.await(taskCompletionSource.getTask());
} catch (ExecutionException | InterruptedException e) {
Log.v(TAG, "Exception Catched");
e.printStackTrace();
}
// Register the value event listener to keep the data updated
mListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
mDataSnapshot = dataSnapshot
Log.v(TAG, "Data updated");
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
};
ref2.addValueEventListener(mListener);
DatbaseReference ref = FirebaseDatabase.getInstance().getReference().child(para1);
// Run the transaction here
ref.runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData mutableData) {
// Perform some stuff based on mDataSanpshot
mutableData.setValue(stats);
return Transaction.success(mutableData);
}
@Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
if (databaseError != null) {
Log.d(TAG, "onComplete: Error: " + databaseError.getMessage());
} else {
Log.d(TAG, "onComplete: Transaction was successful");
ref2.removeEventListener(mListener);
}
}
}
}
// My value event listener here ...
}
【问题讨论】:
-
这就像您在后台任务中使用事务进程(后台线程)。为什么你想要 MyAsync 任务? performCalculation 方法已经在后台线程中执行任务
-
那么我可以阻塞事务线程直到它接收到来自 TaskCompletionSource 的数据吗?它不会影响我的 UI 线程吗?
-
我不这么认为!试一次!
-
天啊!我以前的结构只是performCalculation,但由于阻塞我将它转换为AsyncTask!我在努力。。
-
我检查了这个文档firebase.google.com/docs/database/android/save-data它是回调方法,所以它不会影响UI线程
标签: android firebase android-asynctask transactions firebase-realtime-database