I can't seem to reference a variable outside the onCreate method. Is there a way to overcome this? I'm a student and still learning. If anyone can help, that would be great. Thank you. I would like to reference the "url" variable to the "onItemClick" method, it says "Cannot resolve symbol".
Here is my code :
public class CominSoonActivity extends AppCompatActivity implements RecyclerViewClickItemInterface {
DatabaseReference reference;
RecyclerView recyclerView;
ArrayList<Event> list;
MyAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_comin_soon);
recyclerView = findViewById(R.id.myRecycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList<Event>();
adapter = new MyAdapter(CominSoonActivity.this, list, this);
recyclerView.setAdapter(adapter);
reference = FirebaseDatabase.getInstance().getReference().child("EventDisplay");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren())
{
Event e = dataSnapshot1.getValue(Event.class);
String url = (String) dataSnapshot1.child("website").getValue();
list.add(e);
adapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(CominSoonActivity.this, "Opps.... Something went wrong", Toast.LENGTH_SHORT).show();
}
});
//add back button
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
}
#Override
public void onItemClick(int position) {
//Uri uri = Uri.parse("http://fareezdanial19.wixsite.com/merlimaulibrary");
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
//taking the user back to the previous activity
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == android.R.id.home) {
Intent homeActivity = new Intent(getApplicationContext(), HomeActivity.class);
startActivity(homeActivity);
finish();
}
return super.onOptionsItemSelected(item);
}
}
You can do it like this,
public class CominSoonActivity extends AppCompatActivity implements RecyclerViewClickItemInterface {
DatabaseReference reference;
RecyclerView recyclerView;
ArrayList<Event> list;
MyAdapter adapter;
String url;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_comin_soon);
recyclerView = findViewById(R.id.myRecycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList<Event>();
adapter = new MyAdapter(CominSoonActivity.this, list, this);
recyclerView.setAdapter(adapter);
reference = FirebaseDatabase.getInstance().getReference().child("EventDisplay");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren())
{
Event e = dataSnapshot1.getValue(Event.class);
url = (String) dataSnapshot1.child("website").getValue();
list.add(e);
adapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(CominSoonActivity.this, "Opps.... Something went wrong", Toast.LENGTH_SHORT).show();
}
});
//add back button
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
}
#Override
public void onItemClick(int position) {
//Uri uri = Uri.parse("http://fareezdanial19.wixsite.com/merlimaulibrary");
if(!url.isEmpty()){
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
}
//taking the user back to the previous activity
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == android.R.id.home) {
Intent homeActivity = new Intent(getApplicationContext(), HomeActivity.class);
startActivity(homeActivity);
finish();
}
return super.onOptionsItemSelected(item);
}
}
Related
A video showing the problem:
video
public class ListActivity extends AppCompatActivity {
private ActivityListBinding binding;
private FirebaseAuth firebaseAuth;
private FirebaseFirestore firebaseFirestore;
PaketAdapter adapter;
ArrayList<Paket> paketArrayList;
String magaza;
String name;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityListBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
firebaseAuth = FirebaseAuth.getInstance();
firebaseFirestore = FirebaseFirestore.getInstance();
paketArrayList = new ArrayList<>();
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new PaketAdapter(paketArrayList);
binding.recyclerView.setAdapter(adapter);
Intent intent = getIntent();
magaza = intent.getStringExtra("magaza");
getData();
}
public void getData(){
firebaseFirestore.collection(magaza).addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot value, #Nullable FirebaseFirestoreException error) {
if (error!=null){
Toast.makeText(ListActivity.this,error.getLocalizedMessage(),Toast.LENGTH_LONG).show();
}else if (value!=null){
for (DocumentSnapshot documentSnapshot:value.getDocuments()){
Map<String,Object> data = documentSnapshot.getData();
name = (String) data.get("name");
String paketSayisi = (String) data.get("paketSayisi");
String angaryaSayisi = (String) data.get("angaryaSayisi");
//FieldValue tarih = (FieldValue) data.get("tarih");
//String magaza = (String) data.get("magaza");
Paket paket = new Paket(name,paketSayisi,angaryaSayisi);
paketArrayList.add(paket);
}
}
}
}); adapter.notifyDataSetChanged();
}
public void delete(View view){
for (int i=0;i<= paketArrayList.size();i++){
firebaseFirestore.collection(magaza).document(name).delete().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void unused) {
Toast.makeText(ListActivity.this,"SİLİNDİ",Toast.LENGTH_LONG).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(ListActivity.this,e.getLocalizedMessage(),Toast.LENGTH_LONG).show();
}
});
}
in the application I made, the user selects the store from the spinner and in the other activity, the package information from that store appears. However, when I log in and switch to other activity, the data is not coming. When I go back and go again, the data appears. Does anyone know where I went wrong or what I should do?
public class LoginActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
private ActivityLoginBinding binding;
FirebaseAuth firebaseAuth;
String magaza;
Intent intenttoList;
Intent intent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityLoginBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
intent = new Intent(LoginActivity.this,ListActivity.class);
Intent gelenintent = getIntent();
String email =gelenintent.getStringExtra("email");
if (email.equals("")){
}else {
binding.username.setText(email);
}
binding.spinner.setOnItemSelectedListener(this);
firebaseAuth = FirebaseAuth.getInstance();
intenttoList = new Intent(LoginActivity.this,ListActivity.class);
magaza="";
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,R.array.magazaList,R.layout.support_simple_spinner_dropdown_item);
binding.spinner.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
public void logIn(View view){
if (magaza.equals("çöp")){
Toast.makeText(LoginActivity.this,"MAĞAZA SEÇMENİZ GEREKMEKTEDİR",Toast.LENGTH_LONG).show();
}else{
String username = binding.username.getText().toString();
String password = binding.passWord.getText().toString();
firebaseAuth.signInWithEmailAndPassword(username,password).addOnSuccessListener(new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
startActivity(intent);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(LoginActivity.this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
}
});
}
}
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
if (adapterView.getItemAtPosition(i).toString().equals("MAĞAZA SEÇİN")){
Toast.makeText(LoginActivity.this,"MAĞAZA SEÇMENİZ GEREKLİDİR",Toast.LENGTH_LONG).show();
magaza ="çöp";
}else{
magaza =adapterView.getItemAtPosition(i).toString();
intent.putExtra("magaza",magaza);
}
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
}
Try this
firebaseAuth.signInWithEmailAndPassword(username,password).addOnSuccessListener(new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
Intent intent = new Intent(this, ListActivity.class)
intent.putExtra("magaza",magaza);
startActivity(intent);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(LoginActivity.this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
}
});
In the ListActivity.class call adapter.notifyDataSetChanged(); inside the addSnapshotListener callback.
firebaseFirestore.collection(magaza).addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot value, #Nullable FirebaseFirestoreException error) {
if (error!=null){
Toast.makeText(ListActivity.this,error.getLocalizedMessage(),Toast.LENGTH_LONG).show();
}else if (value!=null){
for (DocumentSnapshot documentSnapshot:value.getDocuments()){
Map<String,Object> data = documentSnapshot.getData();
name = (String) data.get("name");
String paketSayisi = (String) data.get("paketSayisi");
String angaryaSayisi = (String) data.get("angaryaSayisi");
//FieldValue tarih = (FieldValue) data.get("tarih");
//String magaza = (String) data.get("magaza");
Paket paket = new Paket(name,paketSayisi,angaryaSayisi);
paketArrayList.add(paket);
}
adapter.notifyDataSetChanged();
}
}
});
I am trying to work with ChildEventListener in Firebase to populate the listView with the "title" field of every child nodes. But it's not working properly. My first activity is AuthActivity, which contains googleSignIn Button, by which the user can log in or authenticate. After that, in MainActivity a listView supposes to populate with the data using ChildEventListener datasnapshot. But it remains blank.
The interesting part is, If I go back to the AuthActivity with the back button pressed and again click the login button, it agains taking me to the MainActivity and somehow this time it's shows the listView with the correct data. And after closing the app, the same error happens. I am not getting any errors in the Logcat.
Here is my AuthActivity File
public class AuthActivity extends AppCompatActivity {
public static final int RC_SIGN_IN = 100;
SignInButton signInButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_auth);
signInButton = findViewById(R.id.signInButton);
signInButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Choose authentication providers
List<AuthUI.IdpConfig> providers = Arrays.asList(
new AuthUI.IdpConfig.GoogleBuilder().build());
// Create and launch sign-in intent
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.build(),
RC_SIGN_IN);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_SIGN_IN) {
IdpResponse response = IdpResponse.fromResultIntent(data);
if (resultCode == RESULT_OK) {
Intent intent = new Intent(AuthActivity.this, MainActivity.class);
startActivity(intent);
} else {
Toast.makeText(this, "Login Failed! Please try again.", Toast.LENGTH_LONG).show();
}
}
}
}
And The MainActivity File
public class MainActivity extends AppCompatActivity {
public static final int RC_SIGN_IN = 100;
ListView listView;
ArrayList<String> titlesArray;
FirebaseDatabase database;
DatabaseReference databaseReference;
FirebaseUser user;
ChildEventListener childEventListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = findViewById(R.id.listView);
titlesArray = new ArrayList();
//Get the associated login user info
user = FirebaseAuth.getInstance().getCurrentUser();
//Write a message to the database
database = FirebaseDatabase.getInstance();
databaseReference = database.getReference().child("notes").child(user.getUid());
//Adding adapter to the list of titles
ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, titlesArray);
listView.setAdapter(adapter);
childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Note notes = dataSnapshot.getValue(Note.class);
titlesArray.add(notes.getTitle());
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(MainActivity.this, "Loading failed!", Toast.LENGTH_SHORT).show();
}
};
databaseReference.addChildEventListener(childEventListener);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.sign_out_menu:
AuthUI.getInstance()
.signOut(this);
return true;
case R.id.add_new:
Intent intent = new Intent(MainActivity.this, AddActivity.class);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
It is because you are not notifying adapter after getting data from firebase callback.
Just replace your listener like below.
childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Note notes = dataSnapshot.getValue(Note.class);
titlesArray.add(notes.getTitle());
adapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(MainActivity.this, "Loading failed!", Toast.LENGTH_SHORT).show();
}
};
I have a problem in my activity when I change a value in the database. I tried creating a new Activity with a toolbar, the toolbar's title is changed with a database value via ValueEventListener. The problem is that when I change the value in my DB, the activity reopens itself.
private static String eventKey;
private FirebaseAuth mAuth;
private DatabaseReference mDatabase;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_testing);
mAuth = FirebaseAuth.getInstance();
if (mAuth.getCurrentUser() == null) {
finishAffinity();
startActivity(new Intent(this, HomeScreenActivity.class));
}
eventKey = getIntent().getExtras().getString("eventKey");
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mDatabase = FirebaseDatabase.getInstance().getReference().child("Eventos").child(eventKey);
mDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
String titleValue = dataSnapshot.child("title").getValue().toString();
getSupportActionBar().setTitle(titleValue);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
This is the full code of the TestingActivity class.
Here you can see the previous activity (is too large). And here you can see the log when I change something in my DB.
Thanks!
By looking your code provided in the link, it seems you are launching the TestingActivity or EventSingleActivity.
This is the code from the link:
viewHolder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mDatabase.child(id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String eventTime = dataSnapshot.child("timeStamp").getValue().toString();
if(Integer.parseInt(nowTime) > Integer.parseInt(eventTime)){
Intent intent = new Intent(PrincipalActivity.this, TestingActivity.class);
intent.putExtra("eventKey", id);
startActivity(intent);
finish();
} else {
Intent intent = new Intent(PrincipalActivity.this, EventSingleActivity.class);
intent.putExtra("eventKey", id);
startActivity(intent);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
That's why every changes from the firebase db it will launch the activities I mentioned above.
To fix this you need to do the following:
mDatabase.child(id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
viewHolder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String eventTime = dataSnapshot.child("timeStamp").getValue().toString();
if(Integer.parseInt(nowTime) > Integer.parseInt(eventTime)){
Intent intent = new Intent(PrincipalActivity.this, TestingActivity.class);
intent.putExtra("eventKey", id);
startActivity(intent);
finish();
} else {
Intent intent = new Intent(PrincipalActivity.this, EventSingleActivity.class);
intent.putExtra("eventKey", id);
startActivity(intent);
}
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I have an activity for searching in firebase, it contains edittext for typing the text and button when I press the button The results supposed to appear in the recyclerview but when I press the button the first time nothing appears unless I press the button for the second time
the code of findDataActivity
public class FindDataActivity extends AppCompatActivity {
DatabaseReference db;
FirebaseHelper helper;
MyAdapter adapter;
RecyclerView rv;
EditText findETxt;
Button findBtn;
ArrayList<Paints> p;
String s;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_find_data);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if(actionBar != null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//SETUP RECYCLER
rv = (RecyclerView) findViewById(R.id.rvsearch);
rv.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
//INITIALIZE FIREBASE DB
db = FirebaseDatabase.getInstance().getReference("Database");
adapter = new MyAdapter(FindDataActivity.this, p);
rv.setAdapter(adapter);
findBtn = (Button) findViewById(R.id.find_btn);
helper = new FirebaseHelper(db);
}
public void search(View view) {
db.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
findETxt = (EditText) findViewById(R.id.findETxt);
s = findETxt.getText().toString();
p=helper.retrieveSearch(s);
adapter = new MyAdapter(FindDataActivity.this, p);
rv.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id=item.getItemId();
if(id == android.R.id.home){
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
}
the code of firebase
public class FirebaseHelper {
DatabaseReference db;
Boolean saved=null;
Boolean saved1=null;
ArrayList<Paints> paints=new ArrayList<>();
ArrayList<String> keys=new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//READ THEN RETURN ARRAYLIST FOR SEARCH ITEMS IN CASE OF SEARCHING ABOUT ITEM
public ArrayList<Paints> retrieveSearch(final String item) {
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchDataSearch(dataSnapshot,item);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchDataSearch(dataSnapshot,item);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return paints;
}
//IMPLEMENT FETCH DATA AND FILL ARRAYLIST FOR SEARCH
private void fetchDataSearch( DataSnapshot dataSnapshot,String item)
{
paints.clear();
//sorting and searching
final DatabaseReference myRef = db.child("items");
Query query = myRef.orderByChild("type").startAt(item)
.endAt(item + "\uf8ff");
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot messageSnapshot : dataSnapshot.getChildren()) {
Paints paint=messageSnapshot.getValue(Paints.class);
paints.add(paint);
//Toast.makeText(FindDataActivity.this, "found " + type + " unit: " + unit + " price " + price, Toast.LENGTH_LONG).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
In your MyAdapter class you must create a method like this:
public void updateAdapter(ArrayList<Paints> paint){
this.paint= paint;
notifyDataSetChanged();
}
In your search method replace adapter.notifyDataSetChanged(); for adapter.updateAdapter(p);
I'm using Firebase to populate my RecyclerView, but the problem is that every time I open the app, I need to swipe down to refresh and then the list of items is available.
Here is my code
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();
}
After Searching for a while, I found out that I should use notifyDataSetChanged(); but it doesn't work.
Here is my helper class where I'm fetching data:
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;
}
It'll be great if someone could help me out here. This is the last problem in my project.
The problem is due to the adapter not knowing about the data that has been fetched asynchronously. Let's try to look at your code step-by-step:
adapter = new MyAdapter(this, helper.retrieve());
helper.retrieve() will initiate an asynchronous request to fetch data from firebase and immediately returns an empty ArrayList (as the data from firebase hasn't reached the app yet).
rv.setAdapter(adapter);
This line sets the adapter to recyclerView, which has an empty arraylist as data, so it won't show anything on the UI.
After the data is received from firebase, ArrayList<Spacecraft> spacecrafts is updated with new data. But the adapter is not notified about this new data. Ideally, adapter.notifyDataSetChanged() should be called after new data is put into the array list.
Hence, when you swipe to refresh after the initial call, the adapter is set to recycler view, leading to an internal call to notifyDataSetChanged(), which in turn loads the new data on to the UI.
Easiest solution is to notify the adapter when new data is received from Firebase. Below is the pseudo code for it -
Create an interface OnFirebaseDataChanged and add a method void dataChanged(); to it.
MainAcitivty should implement this interface and the implementation of that method should call adapter.notifyDataSetChanged()
helper = new FirebaseHelper(db); should be changed to helper = new FirebaseHelper(db, this);
FirebaseHelper's constructor should have a 2nd parameter of type OnFirebaseDataChanged and should save it in a field called dataChangeListener.
Add a line at the end of fetchData method in FirebaseHelper dataChangeListener.dataChanged();
The ideal solution would be to architect the code differently, but that topic is out of scope of this question.