我正在使用Firebase来填充我的RecyclerView,但问题是,每次打开应用程序时,我都需要向下滑动以刷新,然后项目列表可用。
这是我的代码
public class MainActivity extends AppCompatActivity {
private static final int RC_PHOTO_PICKER = 2;
DatabaseReference db;
FirebaseHelper helper;
MyAdapter adapter;
RecyclerView rv;
EditText nameEditTxt,grpTxt,descTxt,linkTxt;
FirebaseAuth.AuthStateListener authListener;
SwipeRefreshLayout swipeRefresh;
Uri downloadUrl;
String Admin_code;
FirebaseStorage mfirebaseStorage;
private StorageReference mEventPhotoReference;
FloatingActionButton fab;
SharedPreferences sharedPreferences;
ProgressBar spinner;
static boolean calledAlready=false;
public MyAdapter adapter1;
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
spinner = (ProgressBar)findViewById(R.id.progressBar);
spinner.setVisibility(View.GONE);
mfirebaseStorage=FirebaseStorage.getInstance();
if(!calledAlready){
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
calledAlready=true;
}
swipeRefresh=(SwipeRefreshLayout)findViewById(R.id.swiperefresh);
//SETUP RECYCLER
rv = (RecyclerView) findViewById(R.id.rv);
rv.setLayoutManager(new LinearLayoutManager(this));
//INITIALIZE FIREBASE DB
db= FirebaseDatabase.getInstance().getReference();
mEventPhotoReference=mfirebaseStorage.getReference().child("Event Photos");
helper=new FirebaseHelper(db);
//ADAPTER
adapter=new MyAdapter(this,helper.retrieve());
rv.setAdapter(adapter);
adapter.notifyDataSetChanged();
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
rv.setAdapter(adapter);
swipeRefresh.setRefreshing(false);
}
});
sharedPreferences= PreferenceManager.getDefaultSharedPreferences(this);
Admin_code=sharedPreferences.getString(getString(R.string.Admin_code),getString(R.string.Admin_default_value));
Log.e("MainActivity","" + Admin_code);
fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
displayInputDialog();
}
});
fab.setVisibility(View.GONE);
showBtn();
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
protected void onResume() {
showBtn();
super.onResume();
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public void showBtn(){
Admin_code=sharedPreferences.getString(getString(R.string.Admin_code),getString(R.string.Admin_default_value));
if(Objects.equals(Admin_code, "28011996")){
fab.setVisibility(View.VISIBLE);
}
else
fab.setVisibility(View.GONE);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_logout) {
FirebaseAuth.getInstance().signOut();
startActivity(new Intent(MainActivity.this, LoginActivity.class));
return true;
}
if(id==R.id.settings){
Intent settingsIntent=new Intent(this,Settings.class);
startActivity(settingsIntent);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if ((requestCode& 0xffff) == RC_PHOTO_PICKER && resultCode == RESULT_OK) {
Uri selectedImageUri = data.getData();
StorageReference photoRef=mEventPhotoReference.child(selectedImageUri.getLastPathSegment());
photoRef.putFile(selectedImageUri)
.addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() {
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
// When the image has successfully uploaded, we get its download URL
downloadUrl = taskSnapshot.getDownloadUrl();
Toast.makeText(MainActivity.this,"Photo selected successfully",Toast.LENGTH_LONG).show();
}
}).addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(MainActivity.this,"there was a problem uploading photo",Toast.LENGTH_LONG).show();
}
});
}
}
//DISPLAY INPUT DIALOG
private void displayInputDialog()
{
Dialog d=new Dialog(this);
d.setTitle("Save To Firebase");
d.setContentView(R.layout.input_dialog);
nameEditTxt= (EditText) d.findViewById(R.id.nameEditText);
grpTxt= (EditText) d.findViewById(R.id.propellantEditText);
descTxt= (EditText) d.findViewById(R.id.descEditText);
Button saveBtn= (Button) d.findViewById(R.id.saveBtn);
Button photoBtn=(Button)d.findViewById(R.id.photoBtn);
linkTxt = (EditText) d.findViewById(R.id.linkEditText);
photoBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/jpeg");
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
startActivityForResult(Intent.createChooser(intent, "Complete action using"), RC_PHOTO_PICKER);
}
});
//SAVE
saveBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//GET DATA
String name=nameEditTxt.getText().toString();
String propellant=grpTxt.getText().toString();
String desc=descTxt.getText().toString();
String link=linkTxt.getText().toString();
Long tsLong = System.currentTimeMillis()/1000;
String ts = tsLong.toString();
//SET DATA
Spacecraft s=new Spacecraft();
s.setName(name);
s.setPropellant(propellant);
s.setDescription(desc);
s.setLink(link);
s.setImageUrl(downloadUrl.toString());
s.setTimestamp(ts);
//SIMPLE VALIDATION
if(name != null && name.length()>0)
{
//THEN SAVE
if(helper.save(s))
{
//IF SAVED CLEAR EDITXT
nameEditTxt.setText("");
grpTxt.setText("");
descTxt.setText("");
linkTxt.setText("");
downloadUrl=null;
adapter=new MyAdapter(MainActivity.this,helper.retrieve());
rv.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}else
{
Toast.makeText(MainActivity.this, "Name Must Not Be Empty", Toast.LENGTH_SHORT).show();
}
}
});
d.show();
}
搜索了一段时间后,我发现我应该使用notifyDataSetChanged();
,但它不起作用。
这是我正在获取数据的助手类:
public class FirebaseHelper {
DatabaseReference db;
Boolean saved=null;
ArrayList<Spacecraft> spacecrafts=new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//WRITE IF NOT NULL
public Boolean save(Spacecraft spacecraft)
{
if(spacecraft==null)
{
saved=false;
}else
{
try
{
db.child("Spacecraft").push().setValue(spacecraft);
saved=true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved=false;
}
}
return saved;
}
//IMPLEMENT FETCH DATA AND FILL ARRAYLIST
private void fetchData(DataSnapshot dataSnapshot)
{
spacecrafts.clear();
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Spacecraft spacecraft=ds.getValue(Spacecraft.class);
spacecrafts.add(spacecraft);
}
}
//READ THEN RETURN ARRAYLIST
public ArrayList<Spacecraft> retrieve() {
db.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
fetchData(dataSnapshot);
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
return spacecrafts;
}
如果有人可以帮助我,那就太好了。这是我项目中的最后一个问题。
答案 0 :(得分:1)
问题是由于适配器不知道异步提取的数据。让我们一步一步地看一下你的代码:
adapter = new MyAdapter(this, helper.retrieve());
helper.retrieve()将启动异步请求以从firebase获取数据并立即返回一个空的ArrayList(因为来自firebase的数据尚未到达应用程序)。
rv.setAdapter(adapter);
此行将适配器设置为recyclerView,它具有空的arraylist作为数据,因此它不会在UI上显示任何内容。
从firebase收到数据后,ArrayList<Spacecraft> spacecrafts
会更新新数据。但是不会通知适配器有关此新数据的信息。理想情况下,应在将新数据放入数组列表后调用adapter.notifyDataSetChanged()。
因此,当您在初始调用后滑动以刷新时,适配器将设置为recycleler视图,从而导致对notifyDataSetChanged()的内部调用,而后者又将新数据加载到UI。
最简单的解决方案是在从Firebase收到新数据时通知适配器。下面是它的伪代码 -
创建一个OnFirebaseDataChanged接口并向其添加方法void dataChanged();
。
MainAcitivty应该实现此接口,该方法的实现应该调用adapter.notifyDataSetChanged()
helper = new FirebaseHelper(db);
应更改为helper = new FirebaseHelper(db, this);
FirebaseHelper的构造函数应该具有OnFirebaseDataChanged类型的第二个参数,并且应该将其保存在名为dataChangeListener的字段中。
在FirebaseHelper中的fetchData方法末尾添加一行dataChangeListener.dataChanged();
理想的解决方案是以不同的方式构建代码,但该主题超出了这个问题的范围。