just a quick explanation of my project before I get to my question so you can get the gist of everything.
I'm currently working on this real-estate application with android and Firebase. I have been using Firebase to store my data of my app and to authenticate users.
I can add real estate objects to the database and retrieve the all the added real estates in a list view. When I click on one list item I'm getting a more detailed version of the real estate. The details of the real estates are shown in four different tabs. In one of the tabs I give the user the oppertunity to add attachments like pictures to the real estate.
I added the functionality to add the pictures just fine. They are stored in the database as shown in the following screenshot.
The eBncv5ke05ZxR32AiRoP9gSyPkO2 is the user_id and the
"-L38Qe8GEo33i5roKOCi" the Realestate id. the keys are the name of the image and the values the urls.
Here is the code that shows how I add the pictures to the database:
private void saveImage() {
// get the expose id
bundle = getArguments();
immoID = bundle.getString("exposeID");
Toast.makeText(getContext(), immoID, Toast.LENGTH_SHORT).show();
// get an reference to the current user and his id
user = FirebaseAuth.getInstance().getCurrentUser();
user_id = user.getUid();
imageName = imageNameInput.getText().toString();
if (!TextUtils.isEmpty(imageName)) {
//displaying progress dialog while image is uploading
final ProgressDialog progressDialog = new ProgressDialog(getContext());
progressDialog.setTitle("Bild wird hochgeladen");
progressDialog.show();
// uploading the Picture
pictureStorageRef = FirebaseStorage.getInstance().getReference(user_id).child(Constants.STORAGE_PATH_UPLOADS).child(immoID);
pictureDataRef = FirebaseDatabase.getInstance().getReference(Constants.DATABASE_PATH_UPLOADS).child(user.getUid()).child(immoID);
//checking if file is available
if (filePath != null) {
//getting the storage reference
StorageReference sRef = pictureStorageRef.child(Constants.STORAGE_PATH_UPLOADS + System.currentTimeMillis() + "." + getFileExtension(filePath));
//adding the file to reference
sRef.putFile(filePath)
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
String imageName = imageNameInput.getText().toString().trim();
String imageDownloadURL = taskSnapshot.getDownloadUrl().toString();
//creating the upload object to store uploaded image details
PictureUpload upload = new PictureUpload(imageName, imageDownloadURL);
//adding an upload to firebase database
pictureDataRef.child(imageName).setValue(imageDownloadURL);
string_immo_image_url = imageDownloadURL;
//dismissing the progress dialog
progressDialog.dismiss();
changeFragment();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
progressDialog.dismiss();
Toast.makeText(getContext(), exception.getMessage(), Toast.LENGTH_LONG).show();
}
})
.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
#Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
//displaying the upload progress
double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
progressDialog.setMessage(((int) progress) + "% wurden hochegeladen");
}
});
}
}else{
imageNameInput.setError("Geben Sie einen Namen ein");
imageNameInput.requestFocus();
}
}
Now I'm trying to show the pictures using Glide inside my Fragment in a ListView. Therefore I added an adapter for my ListView AttachmentList
public class AttachmentList extends ArrayAdapter <PictureUpload> {
List <PictureUpload> pictureUploads;
DatabaseReference pictureDatabase;
FirebaseUser user;
String userid;
private Activity context;
// Constructor
public AttachmentList (Activity context, List<PictureUpload> pictureUploads){
super (context, R.layout.layout_expose_list, pictureUploads);
this.context = context;
this.pictureUploads = pictureUploads;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
// inflate the custom layout for the listitems
LayoutInflater inflater= context.getLayoutInflater();
final View listViewItem = inflater.inflate(R.layout.layout_expose_list, null, true);
// get the data item for this position
PictureUpload pictureUpload = pictureUploads.get(position);
user = FirebaseAuth.getInstance().getCurrentUser();
userid = user.getUid();
// get references to the view elements in the layout for populating the data
TextView textViewTitle = listViewItem.findViewById(R.id.imageNameDisplay);
ImageView attachmentImage = listViewItem.findViewById(R.id.attachmentImage);
// set the most relevant information of the immo object to the textviews
textViewTitle.setText(pictureUpload.getName());
Glide.with(getContext()).load(pictureUpload.getUrl()).into(attachmentImage);
// return the listview item to render
return listViewItem;
}
}
The PictureUpload class looks like the following:
public class PictureUpload {
public String name;
public String url;
// Default constructor required for calls to
// DataSnapshot.getValue(User.class)
public PictureUpload() {
}
public PictureUpload(String name, String url) {
this.name = name;
this.url = url;
}
public String getName() {
return name;
}
public String getUrl() {
return url;
}
}
And here is the code to the Fragment where I'm trying to display the list:
package com.webgalaxie.blischke.bachelortakesix.fragments.tabfragments;
public class AttachmentTabFragment extends Fragment {
private static final String TAG = "ATTACHMENT_TAB";
FirebaseUser user;
String user_id;
Bundle bundle, newBundle;
String immoID;
// Button to add Attachments to the Expose
Button addAtachments;
private DatabaseReference immoDataRef, pictureDataRef, contactDataRef;
private StorageReference pictureStorageRef;
ListView show_all_attachments_list;
List<PictureUpload> pictureUploads;
public AttachmentTabFragment() {
// Required empty public constructor
}
// Inflate the view for the fragment based on layout XML
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_attachment_tab, container, false);
// get reference to the view elements
addAtachments = view.findViewById(R.id.addAtachments);
show_all_attachments_list = view.findViewById(R.id.show_all_attachments_list);
// get the current user
user = FirebaseAuth.getInstance().getCurrentUser();
user_id = user.getUid();
// get the expose id
bundle = getArguments();
immoID = bundle.getString("exposeID");
// set the on ClickListener to the addAttachments Button
addAtachments.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// change the fragment
Fragment addAttachmentFragment = new AddAttachmentFragment();
FragmentManager manager = getFragmentManager();
newBundle = new Bundle();
newBundle.putString("exposeID", immoID);
addAttachmentFragment.setArguments(newBundle);
manager.beginTransaction().replace(R.id.content_frame, addAttachmentFragment).addToBackStack(null).commit();
}
});
// get reference to the database and storage
immoDataRef = FirebaseDatabase.getInstance().getReference(Constants.DATABASE_PATH_IMMOBILIEN).child(user_id).child(immoID);
pictureDataRef = FirebaseDatabase.getInstance().getReference(Constants.DATABASE_PATH_UPLOADS).child(user_id).child(immoID);
contactDataRef = FirebaseDatabase.getInstance().getReference(Constants.DATABASE_PATH_CONTACTS).child(user_id).child(immoID);
pictureStorageRef = FirebaseStorage.getInstance().getReference(user_id).child(Constants.STORAGE_PATH_UPLOADS);
//return the view
return view;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.showexposemenu, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
final FragmentManager manager = getFragmentManager();
// get the expose id
bundle = getArguments();
immoID = bundle.getString("exposeID");
switch (item.getItemId()) {
case R.id.edit_expose:
Toast.makeText(getContext(), "Expose bearbeiten geklickt.", Toast.LENGTH_SHORT).show();
// put the immoID into new Bundle
newBundle = new Bundle();
newBundle.putString("exposeID", immoID);
// get a new instance of editExposeFragment
Fragment editExpose = new EditExposeFragment();
// set the newBundle as Arguments to the fragement
editExpose.setArguments(newBundle);
// switch the fragment
manager.beginTransaction().replace(R.id.content_frame, editExpose).commit();
break;
case R.id.delete_expose:
Toast.makeText(getContext(), "Expose wurde gelöscht.", Toast.LENGTH_SHORT).show();
immoDataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
immoDataRef.removeValue();
pictureDataRef.removeValue();
contactDataRef.removeValue();
Fragment showAllExpose = new ShowAllExposeFragment();
manager.beginTransaction().replace(R.id.content_frame, showAllExpose).commit();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
break;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onStart() {
super.onStart();
// attaching the ValueEventListener
pictureDataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// check if there are values in the database
if (dataSnapshot.getValue() != null) {
// clear the list of immos
pictureUploads.clear();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
// getting the immo
PictureUpload pictureUpload = postSnapshot.getValue(PictureUpload.class);
// adding the immo to the list
pictureUploads.add(pictureUpload);
}
// creating the List Adapter and add him to the Listview
final AttachmentList attachmentAdapter = new AttachmentList((Activity) getContext(), pictureUploads);
show_all_attachments_list.setAdapter(attachmentAdapter);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
when I try to run my app on my device I'm always getting the following error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.webgalaxie.blischke.bachelortakesix, PID: 14901
java.lang.NullPointerException: Attempt to invoke interface method 'void java.util.List.clear()' on a null object reference
at com.webgalaxie.blischke.bachelortakesix.fragments.tabfragments.AttachmentTabFragment$3.onDataChange(AttachmentTabFragment.java:191)
at com.google.android.gms.internal.zzegf.zza(Unknown Source)
at com.google.android.gms.internal.zzeia.zzbyc(Unknown Source)
at com.google.android.gms.internal.zzeig.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6682)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
Does anyone have an idea why this happens. I'm a bit stuck on this issue.
Thank you very much for your help. If you need more information on the project do not hesitate to ask.
I also have the code to the project on GitHub if you need more information.
Link to GitHub: https://github.com/BexxBl/BachelorTakeSix
That's because in your onStart() method you're calling clear() on a list that hasn't been initialized yet. You should initialize it instead of clearing it:
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// check if there are values in the database
if (dataSnapshot.getValue() != null) {
// clear the list of immos
pictureUploads = new ArrayList();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
// getting the immo
PictureUpload pictureUpload = postSnapshot.getValue(PictureUpload.class);
// adding the immo to the list
pictureUploads.add(pictureUpload);
}
// creating the List Adapter and add him to the Listview
final AttachmentList attachmentAdapter = new AttachmentList((Activity) getContext(), pictureUploads);
show_all_attachments_list.setAdapter(attachmentAdapter);
}
}
EDIT: The value of your snapshot is a String. You need to get the key as well and pass it to your PictureUpload class.
String val = postSnapshot.getValue(String.class);
PictureUpload pictureUpload = new PictureUpload(postSnapshot.getKey(), val);
pictureUploads.add(pictureUpload);
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am new to android i have made a project to store members information in one activity and in another activity i display members in listView and on onlong clicking listview i open another activity to update members information but when i click on update button it adds that record instead of Updating.
My Firebase Structure :
My activity for storing :
public class MainActivity extends AppCompatActivity {
EditText txtname,txtage,txtheight,txtphone;
Button btnsave,btnRead;
Member member;
DatabaseReference reff;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtname = findViewById(R.id.txtname);
txtage =findViewById(R.id.txtage);
txtphone =findViewById(R.id.txtphone);
txtheight =findViewById(R.id.txtheight);
btnsave = (Button)findViewById(R.id.btnsave);
btnRead =(Button)findViewById(R.id.btnRead);
btnRead.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openActivity();
}
private void openActivity() {
Intent intent = new Intent(MainActivity.this, Retreivedata.class);
startActivity(intent);
}
});
member = new Member();
reff = FirebaseDatabase.getInstance().getReference().child("Member");
btnsave.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AddUsers();
}
});
}
private void AddUsers(){
String name = txtname.getText().toString().trim();
String age = txtage.getText().toString().trim();
String phone = txtphone.getText().toString().trim();
String ht = txtheight.getText().toString().trim();
if(!TextUtils.isEmpty(name)) {
String id = reff.push().getKey();
Member member = new Member(id, name, age, phone, ht);
reff.child(id).setValue(member);
Toast.makeText(this,"User Inserted Successfully",Toast.LENGTH_LONG).show();
txtheight.setText("");
txtphone.setText("");
txtage.setText("");
txtname.setText("");
}else {
txtname.setError("Enter Name");
}
}
}
My activity for displaying records in listview:
public class Retreivedata extends AppCompatActivity {
ListView listView;
FirebaseDatabase database;
DatabaseReference ref;
ArrayList<Member> list;
ArrayAdapter<Member> adapter;
Member member;
Button btnDlt;
Boolean a=false;
String val="";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_retreivedata);
member = new Member();
listView =(ListView)findViewById(R.id.listView);
btnDlt = (Button) findViewById(R.id.btnDlt);
database = FirebaseDatabase.getInstance();
ref = database.getReference("Member");
list = new ArrayList<>();
adapter = new ArrayAdapter<Member>(this,R.layout.list_white_text,R.id.userInfo, list);
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot dts: dataSnapshot.getChildren())
{
member = dts.getValue(Member.class);
list.add(member);
}
listView.setAdapter(adapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
btnDlt.setEnabled(false);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Boolean a=true;
Member member=adapter.getItem(position);
Toast.makeText(Retreivedata.this,"Do u want to delete this record!!",Toast.LENGTH_LONG).show();
if (a==true)
{
btnDlt.setEnabled(true);
}else{
btnDlt.setEnabled(false);
}
}
});
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Member member= adapter.getItem(position);
Intent intent = new Intent(Retreivedata.this, Update.class);
intent.putExtra("tem", member);
startActivity(intent);
return false;
}
});
btnDlt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ref.child(member.getMemberId()).removeValue();
Toast.makeText(Retreivedata.this, "Record deleted Successfully",
Toast.LENGTH_LONG).show();
adapter.remove(member);
adapter.clear();
}
});
}
}
My activity for updating record:
public class Update extends AppCompatActivity {
EditText EditTxtName,EditTxtAge,txtPhone,txtHeight;
Member member;
FirebaseDatabase db;
DatabaseReference reff;
Button btnUpdate;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_update);
EditTxtName = (EditText)findViewById(R.id.EditTxtName);
EditTxtAge = (EditText)findViewById(R.id.EditTxtAge);
txtPhone = (EditText)findViewById(R.id.txtPhone);
txtHeight = (EditText)findViewById(R.id.txtHeight);
btnUpdate = (Button)findViewById(R.id.btnUpdate);
final Member member= (Member) getIntent().getSerializableExtra("tem");
EditTxtName.setText(member.getName());
EditTxtAge.setText(member.getAge());
txtPhone.setText(member.getPhone());
txtHeight.setText(member.getHeight());
reff = db.getInstance().getReference().child("Member");
btnUpdate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Update();
}
});
}
private void Update(){
final String mnam = EditTxtName.getText().toString().trim();
final String mage = EditTxtAge.getText().toString().trim();
final String mph = txtPhone.getText().toString().trim();
final String mhei = txtHeight.getText().toString().trim();
final String ID = reff.getKey();
if(TextUtils.isEmpty(mnam)) {
EditTxtName.setText("Plz enter name");}
if(TextUtils.isEmpty(mage)) {
EditTxtName.setText("Plz enter age");}
else{
final Member member = new Member(ID,mnam,mage,mph,mhei);
reff.child("Member").child(ID).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
reff = FirebaseDatabase.getInstance().getReference();
reff.child("Member").child(ID).child("name").setValue(mnam);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Toast.makeText(Update.this,"Updated",Toast.LENGTH_LONG).show();
txtHeight.setText("");
txtPhone.setText("");
EditTxtName.setText("");
}
}
}
But after updating record it creates another record.Suggest me what changes has to be done on update button click.
Thnaks!!
First I assume that you implement Serializable for your Member class:
class Member implements Serializable{
.............
.............
.............
}
Since you are passing the member object to the update activity, why not use the ID in it to update the data:
//the update activity
public class Update extends AppCompatActivity {
//this is the member that you pass
Member member;
......
......
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
.........
.........
//this is how you retrieve it
member= (Member) getIntent().getSerializableExtra("tem");
//this is your ref
reff = db.getInstance().getReference().child("Member");
........
........
}
//when you update
private void Update(){
final String mnam = EditTxtName.getText().toString().trim();
final String mage = EditTxtAge.getText().toString().trim();
final String mph = txtPhone.getText().toString().trim();
final String mhei = txtHeight.getText().toString().trim();
//update the name field
reff.child(member.getMemberId()).child("name").setValue(mnam);
}
Your problem is this line of code final String ID = reff.getKey()
That call generates a new ID which you then use in your update of the db. You need to replace the call to getKey with the ID of the member you want to update.
I am developing a location based chat application as a final assignment, but have one bug that I cannot figure out how to fix by myself. Currently, I intend to load all profiles within a certain radius into a recyclerview, and display only these profiles to the current user.
The recycler view is working fine and displays every user in my Firebase database, until I add the GeoFire query to limit the users that appear only to those within the 2km radius. All user latitudes and longitudes are being updated successfully to the database, so I don't think that this is where the problem originates.
When i run the app and it crashes, I get this exception in the LogCat:
"java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference"
This is confusing me, as none of the current users in my database have a null value stored for either their longitude or latitude.
So my main question is, how can I get only the users within 2km of the current user to populate my recyclerview, without the application crashing?
Database structure
The current source code:
public class FindChatters extends Fragment {
private RecyclerView mUsersList;
private View mMainView;
private DatabaseReference mUsersDatabase;
private FirebaseUser mCurrentUser;
private LatLng myCurrentLocation;
private String mUserFound;
private static final int RADIUS = 2;
Location mLastLocation;
public FindChatters() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
mMainView = inflater.inflate(R.layout.fragment_find_chatters, container, false);
mUsersDatabase = FirebaseDatabase.getInstance().getReference().child("Users");
mCurrentUser = FirebaseAuth.getInstance().getCurrentUser();
mUsersList = (RecyclerView) mMainView.findViewById(R.id.users_list);
mUsersList.setHasFixedSize(true);
mUsersList.setLayoutManager(new LinearLayoutManager(getContext()));
return mMainView;
}
//RETRIEVE DATA IN REALTIME
#Override
public void onStart() {
super.onStart();
startListening();
}
public void startListening() {
Query query = FirebaseDatabase.getInstance().getReference().child("Users").limitToLast(50);
FirebaseRecyclerOptions<Users> options = new FirebaseRecyclerOptions.Builder<Users>().setQuery(query, Users.class).build();
FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter<Users, UserViewHolder>(options) {
#Override
public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// CREATE NEW INSTANCE OF VIEWHOLDER, USING CUSTOM LAYOUT (R.LAYOUT.MESSAGE)
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.users_single_layout, parent, false);
return new UserViewHolder(view);
}
#Override
protected void onBindViewHolder(final UserViewHolder holder, final int position, final Users model) {
// // //
//RETRIEVE CURRENT USERS LAT/LONG TO FIND USERS NEARBY
String userID = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference myLoc = FirebaseDatabase.getInstance().getReference().child("Geo");
final GeoFire geoFire = new GeoFire(myLoc);
geoFire.setLocation(userID, new GeoLocation(mLastLocation.getLatitude(), mLastLocation.getLongitude()));
myCurrentLocation = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude());
//RETRIEVE USERS ONLY FROM WITHIN A SPECIFIED RADIUS TO THE CURRENT USER
DatabaseReference findNearby = FirebaseDatabase.getInstance().getReference().child("Geo");
GeoFire geoFire2 = new GeoFire(findNearby);
//QUERY ALL NEARBY USERS IN THE DATABASE WITHIN 2KM OF CURRENT USER LAT/LONG
final GeoQuery geoQuery = geoFire2.queryAtLocation(new GeoLocation(myCurrentLocation.latitude, myCurrentLocation.longitude), RADIUS);
//QUERY TO RETRIEVE CLOSET USERS
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
//IF ANY USERS FOUND WITHIN RADIUS - ON KEY ENTERED IS CALLED
#Override
public void onKeyEntered(String key, GeoLocation location) {
if (geoQuery != null) {
mUserFound = key;
//BIND CHAT OBJECT TO CHATHOLDER
holder.setName(model.name);
holder.setUserStatus(model.status);
holder.setUserOnline(model.online);
holder.setUserImage(getContext(), model.image);
//CLICK ON A USER PROFILE TO ACCESS THEIR INFORMATION OR INITIATE CHAT
final String user_id = getRef(position).getKey();
//RETRIEVE CURRENT USER ID
String current_uid = mCurrentUser.getUid();
//PREVENT USER FROM BEING ABLE TO INITIATE A CONVERSATION WITH THEMSELF
if (!user_id.equals(current_uid)) {
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent profileIntent = new Intent(getActivity(), ProfileActivity.class);
profileIntent.putExtra("user_id", user_id);
startActivity(profileIntent);
}
});
} else {
holder.setName("You");
holder.setUserStatus("Tap someone to say hello!");
}
} else {
//CREATE TEXTVIEW TO INFORM USER THAT NO NEARBY USERS ARE PRESENT
}
}
#Override
public void onKeyExited(String key) {
}
#Override
public void onKeyMoved(String key, GeoLocation location) {
}
#Override
public void onGeoQueryReady() {
}
#Override
public void onGeoQueryError(DatabaseError error) {
}
});
// // //
}
};
mUsersList.setAdapter(adapter);
adapter.startListening();
}
I am still pretty new to coding, so I really appreciate any replies or help. Thanks!
Android Studio v3.1.3
Make sure you initialise mLastLocation. I can see that you are retrieving lat and lng from it but was never initialised
Here is my situation.
In this screen, I click the comments button.
The Comment activity opens and I type what I want.
The comment is added successfully in firebase and it takes me back in detail activity.
So far everything is great! Now let's add another comment. Now you see I get duplicate comments.
I hope you see that too. Now in the DetailActivity I have a method called queryFirebaseDb() and that method is called inside both onCreate() and onResume() methods. If I don't use the onResume() method the data will not be display after clicking the back button from the CommentActivity. You see where I am going now right? The question is how to avoid duplicate data after coming back from CommentActivity. Here is my code.
public class DetailActivity extends AppCompatActivity {
ArrayList<Comment> commentArrayList;
ImageView mImageView;
TextView mTitle;
TextView mDate;
TextView mDescription;
TextView mAuthor;
ToggleButton mFavBtn;
private TextView noCommentsTextView;
private TextView commentsTextView;
private ImageButton imageButton;
private FloatingActionButton mShareBtn;
private String newsTitle;
private String newsImage;
private String newsDate;
private String newsDescription;
private static String NEWS_SHARE_HASHTAG = "#EasyNewsApp";
private String date1;
private String date2;
private String newsUrl;
private String newsAuthor;
private Cursor favoriteCursor;
private DatabaseReference mDatabase;
private static Bundle bundle = new Bundle();
private Uri uri;
private RecyclerView mRecyclerView;
private DisplayCommentsAdapter displayCommentsAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
Toolbar toolbar = (Toolbar) findViewById(R.id.detail_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Intent i = getIntent();
mAuthor = (TextView) findViewById(R.id.detail_author);
mImageView = (ImageView) findViewById(R.id.detail_image_view);
mTitle = (TextView) findViewById(R.id.detail_title);
mDate = (TextView) findViewById(R.id.detail_publish_date);
mDescription = (TextView) findViewById(R.id.detail_description);
noCommentsTextView = (TextView)findViewById(R.id.noCommentsTextView);
commentsTextView = (TextView)findViewById(R.id.commentsTextView);
mShareBtn = (FloatingActionButton) findViewById(R.id.share_floating_btn);
mFavBtn = (ToggleButton) findViewById(R.id.fav_news_btn);
imageButton = (ImageButton)findViewById(R.id.detail_comment_image_btn);
mRecyclerView = (RecyclerView)findViewById(R.id.recycler_comments);
LinearLayoutManager manager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.addItemDecoration(new SimpleDividerItemDecoration(this));
commentArrayList = new ArrayList<>();
mDatabase = FirebaseDatabase.getInstance().getReference();
mFavBtn.setTextOn(null);
mFavBtn.setText(null);
mFavBtn.setTextOff(null);
newsAuthor = i.getStringExtra("author");
newsImage = i.getStringExtra("image");
newsTitle = i.getStringExtra("newsTitle");
newsDate = i.getStringExtra("date");
newsDescription = i.getStringExtra("description");
newsUrl = i.getStringExtra("url");
date1 = newsDate.substring(0, 10);
date2 = newsDate.substring(11, 19);
Picasso.with(this).load(newsImage)
.placeholder(R.drawable.ic_broken_image)
.into(mImageView);
mTitle.setText(newsTitle);
mAuthor.setText("Author: " + newsAuthor);
mDescription.setText(newsDescription);
mDate.setText(date2 + ", " + date1);
mShareBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent shareIntent = createShareNewsIntent();
startActivity(shareIntent);
}
});
imageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent commentIntent = new Intent(DetailActivity.this, CommentActivity.class);
commentIntent.putExtra("newsTitle",newsTitle);
startActivity(commentIntent);
}
});
/**
* Handling the add/remove news part. We check if the specific news article
* exists in favourite.db.
*/
favoriteCursor = getContentResolver().query(FavouriteContract.FavouriteEntry.CONTENT_URI,
null,
FavouriteContract.FavouriteEntry.COLUMN_NEWS_TITLE + "=?",
new String[]{newsTitle},
null);
/**
* If yes then set the toggle button to true
*/
if (favoriteCursor.getCount() > 0) {
try {
mFavBtn.setChecked(true);
} finally {
favoriteCursor.close();
}
}
/**
* Else click the toggle button to add the news article as favourite
*/
mFavBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, final boolean isChecked) {
/**
* If checked the add the news article as favourite.
*/
if (isChecked) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... voids) {
ContentValues contentValues = new ContentValues();
contentValues.put(FavouriteContract.FavouriteEntry.COLUMN_NEWS_TITLE, newsTitle);
contentValues.put(FavouriteContract.FavouriteEntry.COLUMN_NEWS_AUTHOR, newsAuthor);
contentValues.put(FavouriteContract.FavouriteEntry.COLUMN_NEWS_DESCRIPTION, newsDescription);
contentValues.put(FavouriteContract.FavouriteEntry.COLUMN_NEWS_URL, newsUrl);
contentValues.put(FavouriteContract.FavouriteEntry.COLUMN_NEWS_URL_TO_IMAGE, newsImage);
contentValues.put(FavouriteContract.FavouriteEntry.COLUMN_NEWS_PUBLISHED_AT, newsDate);
//The actual insertion in the db.
uri = getContentResolver().insert(FavouriteContract.FavouriteEntry.CONTENT_URI, contentValues);
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Toast.makeText(DetailActivity.this, "Article with title: " + newsTitle + " was added", Toast.LENGTH_SHORT).show();
}
}.execute();
} else {
/**
* If you uncheck the toggle button then delete the news article from the favourite db.
*/
Uri newsTitleOfFavNews = FavouriteContract.FavouriteEntry.buildNewsUriWithTitle(newsTitle);
//String title = uri.getPathSegments().get(1);// Get the task ID from the URI path
getContentResolver().delete(
newsTitleOfFavNews,
null,
null);
Toast.makeText(DetailActivity.this, "News article deleted from favourites ", Toast.LENGTH_SHORT).show();
}
}
});
queryFirebaseDb();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.detail_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
if(item.getItemId() == R.id.detail_browser_btn){
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(newsUrl));
startActivity(browserIntent);
} if(item.getItemId() == android.R.id.home){
NavUtils.navigateUpFromSameTask(this);
return true;
}
return true;
}
private Intent createShareNewsIntent() {
Intent shareIntent = ShareCompat.IntentBuilder.from(this)
.setType("text/plain")
.setText(NEWS_SHARE_HASHTAG + "\n\n\n" + newsTitle
+ "\n\n\n" + newsDescription
+ "\n\n\n" + newsDate)
.getIntent();
return shareIntent;
}
#Override
protected void onStart() {
super.onStart();
//queryFirebaseDb();
}
#Override
protected void onRestart() {
super.onRestart();
queryFirebaseDb();
//displayCommentsAdapter.notifyDataSetChanged();
}
public void queryFirebaseDb(){
/**
* Querying the database to check if the specific article has comments.
*/
mDatabase = FirebaseDatabase.getInstance().getReference();
Query query = mDatabase.child("comments").orderByChild("newsTitle").equalTo(newsTitle);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
for(DataSnapshot dataSnapshots : dataSnapshot.getChildren()){
Comment comment = dataSnapshots.getValue(Comment.class);
//mUserDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(userId);
commentArrayList.add(comment);
displayCommentsAdapter = new DisplayCommentsAdapter(this,commentArrayList);
mRecyclerView.setAdapter(displayCommentsAdapter);
displayCommentsAdapter.setCommentsData(commentArrayList);
//Log.d(LOG_TAG, String.valueOf(commentArrayList.size()));
}
noCommentsTextView.setVisibility(View.GONE);
//commentsTextView.setVisibility(View.VISIBLE);
}else{
//Toast.makeText(DisplayComments.this,"There are no comments posted",Toast.LENGTH_LONG).show();
noCommentsTextView.setVisibility(View.VISIBLE);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
/*
#Override
protected void onPause() {
super.onPause();
bundle.putBoolean("ToggleButtonState", mFavBtn.isChecked());
}
#Override
public void onResume() {
super.onResume();
mFavBtn.setChecked(bundle.getBoolean("ToggleButtonState",false));
}
*/
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mFavBtn.setChecked(savedInstanceState.getBoolean("ToggleButtonState",false));
savedInstanceState.putParcelableArrayList("newsList",commentArrayList);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("ToggleButtonState",mFavBtn.isChecked());
outState.getParcelableArrayList("newsList");
}
}
and
public class CommentActivity extends AppCompatActivity {
private static final String REQUIRED = "Required";
private static final String TAG = CommentActivity.class.getSimpleName();
Toolbar toolbar;
DatabaseReference mDatabase;
EditText titleEt;
EditText bodyEt;
Button commentBtn;
String newsTitle;
Intent i;
String name;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_comment);
toolbar = (Toolbar) findViewById(R.id.comment_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle("Add comment");
mDatabase = FirebaseDatabase.getInstance().getReference();
titleEt = (EditText) findViewById(R.id.comment_title);
bodyEt = (EditText) findViewById(R.id.comment_body);
commentBtn = (Button) findViewById(R.id.comment_btn);
i = getIntent();
newsTitle = i.getStringExtra("newsTitle");
commentBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
submitPost();
}
});
}
private void submitPost() {
final String title = titleEt.getText().toString();
final String body = bodyEt.getText().toString();
// Title is required
if (TextUtils.isEmpty(title)) {
titleEt.setError(REQUIRED);
return;
}
// Body is required
if (TextUtils.isEmpty(body)) {
bodyEt.setError(REQUIRED);
return;
}
// Disable button so there are no multi-posts
setEditingEnabled(false);
Toast.makeText(this, "Posting...", Toast.LENGTH_SHORT).show();
// [START single_value_read]
final String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
mDatabase.child("Users").child(userId).addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get user value
User user = dataSnapshot.getValue(User.class);
// [START_EXCLUDE]
if (user == null) {
// User is null, error out
Log.e(TAG, "User " + userId + " is unexpectedly null");
Toast.makeText(CommentActivity.this,
"Error: could not fetch user.",
Toast.LENGTH_SHORT).show();
} else {
// Write new post
name = dataSnapshot.child("name").getValue().toString();
Calendar c = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
String strDate = sdf.format(c.getTime());
writeNewPost(userId,strDate,name,newsTitle, title, body);
}
// Finish this Activity, back to the stream
setEditingEnabled(true);
finish();
// [END_EXCLUDE]
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "getUser:onCancelled", databaseError.toException());
// [START_EXCLUDE]
setEditingEnabled(true);
// [END_EXCLUDE]
}
});
// [END single_value_read]
}
private void writeNewPost(String userId,String date,String
commentAuthor, String newsTitle, String commentTitle, String
commentBody){
String key = mDatabase.child("comments").push().getKey();
Comment comment = new Comment(userId, date,
commentAuthor,newsTitle,commentTitle,commentBody);
Map<String, Object> commentValues = comment.toMap();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/comments/" + key, commentValues);
mDatabase.updateChildren(childUpdates);
}
private void setEditingEnabled(boolean enabled) {
titleEt.setEnabled(enabled);
bodyEt.setEnabled(enabled);
if (enabled) {
commentBtn.setVisibility(View.VISIBLE);
} else {
commentBtn.setVisibility(View.GONE);
}
}
}
UPDATE
I used this
#Override
protected void onRestart() {
super.onRestart();
finish();
startActivity(getIntent());
}
and voila!
Some stuff I thought you would know when doing Android:
Basically, in android, you need to understand how the life cycle works. So, when you call queryFirebaseDb() from onCreate and from onResume, your app is doing two queries at the same time when activity starts initially.
Lifecycle is like this OnCreate -> onResume. So, it makes sense that when activity starts, query gets executed once on onCreate than on onResume based on your logic.
Answer is here
I noticed that you are using ArrayList<Comment> commentArrayList;, which is an ArrayList structure, which lets you have duplicate data. And, if you look into the behavior of Firebase and how your query is structured, it is like this,
Query query = mDatabase.child("comments").orderByChild("newsTitle").equalTo(newsTitle);
This query means that you are taking all the comments, the previous comment and the new comment, (not just new comment), which I think you either just want (1) to get recently added comment or (2) to replace the old comments with new one.
The first way of doing this sounds complicated to me, though that is not impossible. But, second way of doing is rather easy.
Therefore, to solve this,
simply, replace the arrayList you have with this data.
if(dataSnapshot.exists()){
ArrayList<Comment> tempComments = new ArrayList();
for(DataSnapshot dataSnapshots : dataSnapshot.getChildren()){
Comment comment = dataSnapshots.getValue(Comment.class);
//mUserDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(userId);
tempComments.add(comment);
//Log.d(LOG_TAG, String.valueOf(commentArrayList.size()));
}
commentArrayList = tempComments; //assuming you want to store the data in the class fields
displayCommentsAdapter = new DisplayCommentsAdapter(this,commentArrayList);
mRecyclerView.setAdapter(displayCommentsAdapter);
displayCommentsAdapter.setCommentsData(commentArrayList);
noCommentsTextView.setVisibility(View.GONE);
//commentsTextView.setVisibility(View.VISIBLE);
}
I am working on my first app and am just setting all the frame work up.
That is user sign up via Google, Email, Facebook and saving the data to Firebase.
I started using Realtime Database, which worked fine, but for the proceeding of my project, I think FireStore Cloud would be better suited.
I didnt have much data yet, so it was easy to get it set up.
User signs up or logs in, and if he doesnt exist already, a profile is set up based on the FirebaseAuth Name + Email and some variables I defined ("Nickname", "-"), and a few more.
All good so far. The information is fetched and displayed once the user clicks on his profile.
Then there is the OPTION TO EDIT some data, like the nickname, the age and the nationality.
If I update the data directly on firestore and click on profile again, it displays correctly.
BUT if the user enters the information and clicks the button that triggers the update to the firestore cloud, the app crashes. The database, however, also updates correctly...
I tried a lot things, but Im stuck! Thanks a lot for your help!
MY CODE
USER CLASS => where the information is stored to the cloud one time, when the user logs in
public class User extends AppCompatActivity {
public static final String AGE = "Age";
public static final String EMAIL = "Email";
public static final String FULLNAME = "Full name";
public static final String NATIONALITY = "Nationality";
public static final String NICKNAME = "Nickname";
public static final String STATUS = "Status";
private String userEmail = FirebaseAuth.getInstance().getCurrentUser().getEmail();
private String userFullName = FirebaseAuth.getInstance().getCurrentUser().getDisplayName();
public User() {
// Default constructor required for calls to DataSnapshot.getValue(User.class)
}
protected void checkFireStoreDatabase() {
// Create a new user with a first and last name
FirebaseFirestore db = FirebaseFirestore.getInstance();
DocumentReference usersDocRef = db.collection("Users").document(userFullName);
if (usersDocRef != null) {
} else {
createNewEntry();
}
}
public void createNewEntry() {
FirebaseFirestore db = FirebaseFirestore.getInstance();
DocumentReference usersDocRef = db.collection("Users").document(userFullName);
Map<String, Object> userEntry;
userEntry = new HashMap<>();
userEntry.put("Full name", userFullName);
userEntry.put(EMAIL, userEmail);
userEntry.put("Nickname", "-");
userEntry.put("Age", "-");
userEntry.put("Nationality", "-");
userEntry.put("Status", "Baby monkey");
db.document(userFullName).set(userEntry, SetOptions.merge()).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "Document has been saved");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, "Document could not be saved");
}
});
}
USER PROFILE FRAGMENT => where the user can see his information that is stored in the cloud
public class UserProfileFragment extends Fragment implements View.OnClickListener {
private Button btnEditProfile;
//get firestore database data
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private DocumentReference usersDocRef = db.collection("Users").document(FirebaseAuth.getInstance().getCurrentUser().getDisplayName());
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//DATA FROM FIRESTORE
displayFirestoreData();
btnEditProfile = (Button) view.findViewById(R.id.edit_user_info);
btnEditProfile.setOnClickListener(this);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_user_profile, container, false);
}
#Override
public void onClick(View v) {
Fragment fragment = null;
//if the button representing the "train now or create workout" fragment is clicked, create this fragment
if (v.getId() == R.id.edit_user_info) {
fragment = new EditUserProfileFragment();
}
if (fragment != null) {
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit();
}
}
public void displayFirestoreData() {
if (usersDocRef != null) {
}
//this.getActivity makes sure the listener only works when in this FragmentActivity
usersDocRef.addSnapshotListener(this.getActivity(), new EventListener<DocumentSnapshot>() {
#Override
public void onEvent(DocumentSnapshot documentSnapshot, FirebaseFirestoreException e) {
if (documentSnapshot.exists()) {
String name = documentSnapshot.getString(FULLNAME);
String email = documentSnapshot.getString(EMAIL);
String nickname = documentSnapshot.getString(NICKNAME);
String age = documentSnapshot.getString(AGE);
String nationality = documentSnapshot.getString(NATIONALITY);
String status = documentSnapshot.getString(STATUS);
//setting all the text views in the user profile
TextView txtProfileName = (TextView) getView().findViewById(R.id.profile_section_fullname);
txtProfileName.setText(name);
TextView txtProfileEmail = (TextView) getView().findViewById(R.id.profile_section_email);
txtProfileEmail.setText(email);
TextView txtProfileNickname = (TextView) getView().findViewById(R.id.profile_section_nickname);
txtProfileNickname.setText(nickname);
TextView txtProfileAge = (TextView) getView().findViewById(R.id.profile_section_age);
txtProfileAge.setText(age);
TextView txtProfileNationality = (TextView) getView().findViewById(R.id.profile_section_nationality);
txtProfileNationality.setText(nationality);
TextView txtProfileStatus = (TextView) getView().findViewById(R.id.profile_section_status);
txtProfileStatus.setText(status);
} else if (e != null) {
Log.w(TAG, "An exception occured", e);
}
}
});
}
EDIT USER PROFILE FRAGMENT => where the user can enter a new nickname, age or nationality
public class EditUserProfileFragment extends Fragment implements View.OnClickListener {
private Button btnSaveProfile;
private EditText editUsername;
private EditText editAge;
private EditText editNationality;
private String username_input;
private String age_input;
private String nationality_input;
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//Button to save the profile
btnSaveProfile = (Button) view.findViewById(R.id.save_user_info);
btnSaveProfile.setOnClickListener(this);
//field that allows changes on the nick name
editUsername = (EditText) view.findViewById(R.id.profile_section_edit_nickname);
//field that allows you to enter the correct age
editAge = (EditText) view.findViewById(R.id.profile_section_edit_age);
//field that allows you to enter your nationality
editNationality = (EditText) view.findViewById(R.id.profile_section_edit_nationality);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_user_profile_edit, container, false);
}
#Override
public void onClick(View v) {
username_input= editUsername.getText().toString().trim();
age_input = editAge.getText().toString().trim();
nationality_input = editNationality.getText().toString().trim();
//update Firestore data
updateFireStoreData(username_input, age_input, nationality_input);
}
//update the user entered information to the database, if the strings arent empty
public void updateFireStoreData(String nicknameUpdate, String ageUpdate, String nationalityUpdate) {
FirebaseFirestore db = FirebaseFirestore.getInstance();
FirebaseUser currUser = FirebaseAuth.getInstance().getCurrentUser();
DocumentReference userDocRef = db.collection("Users").document(currUser.getDisplayName());
if (!nicknameUpdate.matches("")) {
Map<String, Object> dataUpdate = new HashMap<String, Object>();
dataUpdate.put(NICKNAME, nicknameUpdate);
userDocRef
.set(dataUpdate, SetOptions.merge()).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "Document has been saved");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, "Document could not be saved");
}
});
}
}
ERROR LOG:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: MYAPP, PID: 3992
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)'
on a null object reference
at MYAPP.UserProfileFragment$1.onEvent(UserProfileFragment.java:103)
at MYAPP.UserProfileFragment$1.onEvent(UserProfileFragment.java:91)
at com.google.firebase.firestore.DocumentReference.zza(Unknown Source:45)
at com.google.firebase.firestore.zzd.onEvent(Unknown Source:6)
at com.google.android.gms.internal.zzevc.zza(Unknown Source:6)
at com.google.android.gms.internal.zzevd.run(Unknown Source:6)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:251)
at android.app.ActivityThread.main(ActivityThread.java:6563)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
This is not a Firebase database Exception, either a Cloud Firestore Exception. Your Exception tells you clearly what is going on. So you are attempting to use findViewById() method on a null object reference. This means that getView() returns null. And this is happening because you are calling that method after you are returning the fragmnet view.
In order to solve this, call those methods before and use findViewById() method directly on the view.
I load a recyclerview based on Firebase data via the following method:
#Override
public void onStart() {
super.onStart();
mChildEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String newPollEpoch = dataSnapshot.getKey();
if (mNewPollsAray.contains(newPollEpoch)) {
Log.v("POLL_ADDED", "POLL ADDED: " + newPollEpoch);
} else {
Log.v("Child_Added", "The new child is " + newPollEpoch);
String newPollImageURL = dataSnapshot.child(IMAGE_URL).getValue(String.class);
//TODO: On additional devices, numbesr are not appearing as the question
String newPollQuestion = dataSnapshot.child(QUESTION_STRING).getValue(String.class);
String convertedQuestion = newPollQuestion.toString();
mNewPollsAray.add(0, new Poll(convertedQuestion, newPollImageURL, newPollEpoch));
mNewPollsAdapter.notifyDataSetChanged();
Log.v("OnChildChanged", "OnCHILDCHANGEDCALLED " + dataSnapshot.getKey());
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
mPollsRef.addChildEventListener(mChildEventListener);
}
#Override
public void onStop() {
super.onStop();
mPollsRef.removeEventListener(mChildEventListener);
}
Here is the method I call when an item in the recyclerview is clicked:
#Override
public void onClick(View view) {
view.getId();
int itemPosition = getAdapterPosition();
String passEpoch = mNewPollsAray.get(itemPosition).getPollID();
Log.v("PASSED_ID", "The passed ID is " + passEpoch);
Intent toPoll = new Intent(getActivity(), PollHostActivity.class);
toPoll.putExtra("POLL_ID", passEpoch);
startActivity(toPoll);
}
The fragment I am loading it from is part of a TabLayout. When I navigate between the tabs the recyclerview loads correctly.
However, when I click an item in the recyclerview (which takes me to a new activity) and then navigate back to the fragment containing the recyclerview, items get duplicated and the recyclerview items are all out of order. I think it has to do with onStart() being called multiple times and essentially "stacking" new items onto the recyclerview instead of replacing them, but I was hoping to confirm.
This happens because you add a listener, but never remove it. So the next time when you enter the view, you add a second listener and thus get two calls to onChildAdded() for each item in the database.
The solution is to remove the listener when you exit the view. Since you attach the listener in onStart(), you should remove it again in onStop():
#Override
public void onStop() {
mPollsRef.removeEventListener(mChildEventListener);
}
You can try with code, I was facing similar issue got resolved with bellow changes.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if(mMainLayout == null)
{
mMainLayout = inflater.inflate(R.layout.fragment_main, container,false);
...
}
return mMainLayout;
}
When mMainlayout is not null, it mean that your fragment instance has already one instance of the mMainLayout and already added to ViewGroup container no need to add it again. You may be facing issue as you are adding same view again to same container.
By Clear the data set you can avoid loading of similar items again in Recycler View. It worked for me.
listOftrailers.clear();
try {
JSONObject jsonObject = new JSONObject(data);
JSONArray jsonArray = jsonObject.getJSONArray("results");
for (int i = 0; i < jsonArray.length(); i++) {
MovieTrailer item = new MovieTrailer();
JSONObject js = jsonArray.getJSONObject(i);
item.setVideoID(js.getString("id"));
item.setVideoName(js.getString("name"));
item.setVideoKey(js.getString("key"));
item.setVideoSite(js.getString("site"));
item.setVideoType(js.getString("type"));
String name = item.getVideoName();
if (name.contains("Official Trailer") ||
name.startsWith("Official"))
listOftrailers.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
videosadapter = new TrailerListAdapter(listOftrailers.size(),
listOftrailers, MoviePage.this);
recyclerView.setAdapter(videosadapter);