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'を返します。最初にfetchDataを実行し、そのデータである「RecyclerView」で更新する必要があります。何が起きているのかを理解するには、デバッガを使用します。 – Divers

+0

これは非同期応答です。 –

+0

@ダイバーズあなたは、私はかなり新しいAndroidのですよ、どうもありがとうございます –

答えて

1

この問題は、アダプターが非同期にフェッチされたデータについて認識していないために発生します。のは、あなたのコードのステップバイステップを見てみましょう:

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

helper.retrieve()firebaseからデータをフェッチする非同期要求を開始してすぐに空のArrayListを返します(firebase hasnからのデータとなりますまだアプリには達していない)。

rv.setAdapter(adapter);

この行はデータとして、空のArrayListを持ってrecyclerView、にアダプタを設定し、それをUIには何も表示されません。

firebaseからデータを受信した後、ArrayList<Spacecraft> spacecraftsは新しいデータで更新されます。しかし、アダプターはこの新しいデータについて通知されません。理想的には、新しいデータを配列リストに入れた後でadapter.notifyDataSetChanged()を呼び出す必要があります。

したがって、最初の呼び出しの後にスワイプして更新すると、アダプターはリサイクラービューに設定され、notifyDataSetChanged()を内部的に呼び出すと、新しいデータがUIにロードされます。

最も簡単な解決策は、Firebaseから新しいデータを受信したときにアダプタに通知することです。

  • OnFirebaseDataChangedインターフェースを作成し、方法void dataChanged();を追加する - 以下そのための擬似コードです。

  • MainAcitivtyは、このインタフェースを実装する必要がありますし、そのメソッドの実装はFirebaseHelperのコンストラクタはOnFirebaseDataChangedタイプの2番目のパラメータを持つ必要がありますし、それを保存する必要がありhelper = new FirebaseHelper(db, this);

  • に変更する必要がありますadapter.notifyDataSetChanged()

  • helper = new FirebaseHelper(db);を呼び出す必要がありますdataChangeListenerというフィールド。

  • FirebaseHelperのfetchDataメソッドの最後に行を追加します。dataChangeListener.dataChanged();

理想的な解決策は、コードをさまざまに設計することですが、そのトピックはこの質問の範囲外です。

+0

解決していただきありがとうございます。 –

関連する問題