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

感謝您的解決方案,它的工作(標記爲答案) –

相關問題