2

我正在使用Firebase来填充我的RecyclerView,但问题是每次打开应用程序时,都需要向下滑动以刷新,然后才能使用项目列表。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

从'retrieve'方法返回空'ArrayList'。您需要首先获取数据,然后使用该数据“RecyclerView”进行更新。使用调试器来了解发生了什么。 – Divers

+0

这是一个异步响应。 –

+0

@Divers能否请您详细说明我是相当新的android,谢谢 –

回答

1

问题是由于适配器不知道异步获取的数据。让我们试着去看看你的代码一步一步:

adapter = new MyAdapter(this, helper.retrieve());

helper.retrieve()将启动一个异步请求来从火力点数据并立即返回一个空的ArrayList(从火力的不是招数据尚未达到应用程序)。

rv.setAdapter(adapter);

该行设置适配器recyclerView,其中有一个空的ArrayList的数据,因此它不会显示在用户界面上任何东西。

从Firebase收到数据后,ArrayList<Spacecraft> spacecrafts会更新为新数据。但是适配器没有被通知这个新数据。理想情况下,在将新数据放入数组列表后,应调用adapter.notifyDataSetChanged()。

因此,当您在初始调用后刷卡刷新时,适配器将设置为回收站视图,导致内部调用notifyDataSetChanged(),并将新数据加载到UI。

最简单的解决方案是在从Firebase收到新数据时通知适配器。下面是它的伪代码 -

  • 创建OnFirebaseDataChanged的接口,并添加了一个方法void dataChanged();它。

  • MainAcitivty应该实现此接口和方法的实现应该调用adapter.notifyDataSetChanged()

  • helper = new FirebaseHelper(db);应改为helper = new FirebaseHelper(db, this);

  • FirebaseHelper的构造函数的类型应该是OnFirebaseDataChanged,应该将其保存在第2个参数一个名为dataChangeListener的字段。

  • 在firebaseHelper中的fetchData方法的末尾添加一行dataChangeListener.dataChanged();

理想的解决方案是以不同方式构建代码,但该主题不在此问题的范围之内。

+0

感谢您的解决方案,它的工作(标记为答案) –

相关问题