在刷新之前,RecyclerView不显示数据

时间:2017-02-27 14:07:00

标签: android firebase firebase-realtime-database android-recyclerview recycler-adapter

我正在使用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;
    }

如果有人可以帮助我,那就太好了。这是我项目中的最后一个问题。

1 个答案:

答案 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();

理想的解决方案是以不同的方式构建代码,但该主题超出了这个问题的范围。