我使用Firebase来处理Android应用的Auth主题。 我还在Firebase上保存了一个用户个人资料,其中包含用户ID以及用户可以在Android应用中更新的额外选项。
启动时,应用程序会检查身份验证和身份验证。它重新加载用户配置文件(在Firebase上),然后在应用程序上更新我的userInstance。
Firebase在应用级别设置为离线功能。 userInstance POJO在日志时与Firebase同步,并在unlog时停止同步。
我的用户个人资料中有一个特殊参数,我可以更改(作为管理员)。
每次我在Firebase控制台上更新它时,当应用重新开始时,它会被之前的值替换。
这怎么可能发生?
BTW: 1 /基于合并数据的机制,如果多个客户端具有不同的本地值?这是更简单的代码,我尝试重现错误。 :
MyApplication.java
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Firebase.setAndroidContext(this);
Firebase.getDefaultConfig().setLogLevel(Logger.Level.DEBUG);
Firebase.getDefaultConfig().setPersistenceEnabled(true);
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
Firebase ref;
User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ref = new Firebase("https://millezim-test.firebaseIO.com").child("user");
ref.keepSynced(true);
Button br = (Button) findViewById(R.id.b_read);
Button bs = (Button) findViewById(R.id.b_save);
final TextView tv_r = (TextView) findViewById(R.id.tv_value_toread);
final EditText tv_s = (EditText) findViewById(R.id.tv_value_tosave);
user = new User();
bs.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!tv_s.getText().toString().equalsIgnoreCase(""))
user.setAge(Integer.valueOf(tv_s.getText().toString()));
ref.setValue(user);
}
});
br.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
if (u != null)
tv_r.setText(String.valueOf(u.getAge()));
else
tv_r.setText("Bad Value");
}
@Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
});
ref.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
u.setCounter(u.getCounter() + 1);
user = u;
saveUser();
}
@Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
public void saveUser() {
ref.setValue(user);
}
}
如果您只是更改了应用中的值,那么计数器包含直到应用停止:这是正常的。但是什么是股票是从旧到新的循环而不是停止的旧循环。
我觉得我的应用程序中的行为,没有循环,因为我没有计数器,但我无法更改管理客户端中的参数,我总是收回存储在移动设备中的先前值。
我只是Auth,然后我用AuthData更新我的UserInstance +从Firebase获取用户(可能是缓存的数据),然后我在Firebase下保存更新的用户(因为我可能有新的AuthData,我通常得到来自Firebase的最新用户)
2 /在这个简单的例子中,我看到如果我在start时读取值,它会获取应用程序中缓存的数据。我如何强制拥有在线数据?
答案 0 :(得分:10)
问题来自于您使用单值事件侦听器的磁盘持久性这一事实。当你这样做时:
ref.addListenerForSingleValueEvent(new ValueEventListener() {...
您要求该位置的单个值(您的情况下的用户)。如果Firebase在其本地缓存中具有该位置的值,则会立即触发该值。
解决此问题的最佳方法是不使用单值侦听器,而是使用常规事件侦听器。这样,您将获得两个事件:一个用于缓存版本,另一个用于从服务器返回的版本(如果不同)。
唯一的选择是不使用Firebase的磁盘持久性。如果没有这个,就不会有重新启动时读取数据的本地缓存。
Firebase邮件列表上有关于此组合的一些讨论。这是一个:https://groups.google.com/forum/#!msg/firebase-talk/ptTtEyBDKls/XbNKD_K8CQAJ
答案 1 :(得分:1)
消化后,我目前的策略是使用Firebase来保持数据持久性,而不再使用我自己的对象。 (在我必须同步UI,我的数据,firebase缓存和服务器数据之前)
现在,我使用
这意味着,当我更新数据时,它会转到服务器(或Firebase缓存层),直到它返回到UI。由于firebase处理这个缓存,如果速度足够快,这就是处理网络同步的Firebase。
答案 2 :(得分:0)
将@ frank-van-puffelen的(1)解决方案带入代码:
public class MainActivity extends AppCompatActivity {
Firebase ref;
User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ref = new Firebase("https://test.firebaseIO.com").child("user");
ref.keepSynced(true);
Button br = (Button) findViewById(R.id.b_read);
Button bs = (Button) findViewById(R.id.b_save);
final TextView tv_r = (TextView) findViewById(R.id.tv_value_toread);
final EditText tv_s = (EditText) findViewById(R.id.tv_value_tosave);
user = new User();
bs.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!tv_s.getText().toString().equalsIgnoreCase(""))
user.setAge(Integer.valueOf(tv_s.getText().toString()));
ref.setValue(user);
}
});
br.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ref.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
if (u != null)
tv_r.setText(String.valueOf(u.getAge()));
else
tv_r.setText("Bad Value");
}
@Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
});
ref.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
u.setCounter(u.getCounter() + 1);
user = u;
saveUser();
}
@Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
public void saveUser() {
ref.setValue(user);
}
}
然而,这种改变没什么,甚至是最糟糕的。现在看来每个值设置,保持为鬼值(由客户端/服务器请求保持),并且可以在设置的每个值中看到值切换!
修改强>
以下代码已经解决了! 拥有一个普通的ValueListener,你在再次保存一个值之前停止了,并在保存完成时启用了! (好吧,我以为这可以在Firebase框架中完成)。
public class MainActivity extends AppCompatActivity {
Firebase ref;
User user;
private ValueEventListener theListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ref = new Firebase("https://test.firebaseIO.com").child("user");
ref.keepSynced(false);
Button bs = (Button) findViewById(R.id.b_save);
final EditText tv_s = (EditText) findViewById(R.id.tv_value_tosave);
user = new User();
bs.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!tv_s.getText().toString().equalsIgnoreCase(""))
user.setAge(Integer.valueOf(tv_s.getText().toString()));
ref.setValue(user);
}
});
theListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
u.setCounter(u.getCounter() + 1);
user = u;
updateUI(u);
saveUser();
}
@Override
public void onCancelled(FirebaseError firebaseError) {
}
};
ref.addValueEventListener(theListener);
}
public void saveUser() {
ref.removeEventListener(theListener);
ref.setValue(user, new Firebase.CompletionListener() {
@Override
public void onComplete(FirebaseError firebaseError, Firebase firebase) {
ref.addValueEventListener(theListener);
}
});
}
public void updateUI(User user) {
TextView tv_r = (TextView) findViewById(R.id.tv_value_toread);
if (user != null)
tv_r.setText(String.valueOf(user.getAge()));
else
tv_r.setText("Bad Value");
}
}
修改强>
但是,这不允许更改管理页面上的值。设置年龄值,然后保持回到移动设备上保存的年龄值。
所以我成像然后唯一的解决方案是在系统级解决。请勿使用VALUELISTENER以获得应用程序可以保存并且可以由第三方APP保存的值。请建议/纠正这个假设!