I have an online quiz app in Firebase. Shuffle method does not work. Every time question come the same interval.
Each time the questions come the same. Comes with the same sequence. I do not understand why that happens.
The question is actually very simple, but I have to extend it for acceptance.
private void loadQuestions(String categoryId) {
//First, clear list if have old questions
if (Common.questionList.size()>0)
Common.questionList.clear();
question.orderByChild("categoryId").equalTo(categoryId).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
Question question = postSnapshot.getValue(Question.class);
Common.questionList.add(question);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {}
});
//Random list
Collections.shuffle(Common.questionList);
}
public class Question {
private String sul, bri, ki, cu, dor, du, categoryId, sek;
public Question() {
}
public Question(String sul, String bri, String ki, String cu, String dor, String du, String categoryId, String sek) {
this.sul = sul;
this.bri = bri;
this.ki = ki;
this.cu = cu;
this.dor = dor;
this.du = du;
this.categoryId = categoryId;
this.sek = sek;
}
public String getSul() {
return sul;
}
public void setSul(String sul) {
this.sul = sul;
}
public String getBri() {
return bri;
}
public void setBri(String bri) {
this.bri = bri;
}
public String getKi() {
return ki;
}
public void setKi(String ki) {
this.ki = ki;
}
public String getCu() {
return cu;
}
public void setCu(String cu) {
this.cu = cu;
}
public String getDor() {
return dor;
}
public void setDor(String dor) {
this.dor = dor;
}
public String getDu() {
return du;
}
public void setDu(String du) {
this.du = du;
}
public String getCategoryId() {
return categoryId;
}
public void setCategoryId(String categoryId) {
this.categoryId = categoryId;
}
public String getSek() {
return sek;
}
public void setSek(String sek) {
this.sek = sek;
}
}
public class Common {
public static String categoryId,categoryName;
public static User currentUser;
public static List<Question> questionList = new ArrayList<>();
public static final String STR_PUSH = "pushNotification";
}
When you using the following line of code:
Collections.shuffle(Common.questionList);
Outside the onDataChange(), it means that you are trying to shuffle an empty list. This is happening because this method has an asynchronous behavior which means that by the time you are trying to shuffle that list outside that method, the data hasn't finished loading yet from the database and that's why is not accessible.
A quick solve for this problem would be to move that line of code inside the onDataChange() method, otherwise I recommend you see the last part of my anwser from this post in which I have explained how you can use a String (it can be any other object, even a List) outside the onDataChange() method using a custom callback. You can also take a look at this video for a better understanding.
Related
When I start the activity, it is showing the error:
Class com.rcpl.agni.Artist does not define a no-argument
constructor.If you are using ProGuard, make sure these constructors
are not stripped.
protected void onStart() {
super.onStart();
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//artistList.clear();
for(DataSnapshot artistSnapshot : dataSnapshot.getChildren()){
Artist artist = artistSnapshot.getValue(Artist.class);
Toast.makeText(MainActivity.this, artist.getArtistName(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Artist.java
package com.rcpl.agni;
/**
* Created by Dell-pc on 23-01-2018.
*/
public class Artist {
String artistId;
String artistName;
String artistGenre;
public Artist(String artistId, String artistName, String artistGenre) {
this.artistId = artistId;
this.artistName = artistName;
this.artistGenre = artistGenre;
}
public String getArtistId() {
return artistId;
}
public String getArtistName() {
return artistName;
}
public String getArtistGenre() {
return artistGenre;
}
}
To solve this, you just need to add the public no-argument constructor to your Artist class.
public Artist() {}
Remember, when the Firebase Realtime Database SDK deserializes objects coming from the database, it requires that any objects to a have a public no-argument constructor. This is needed to instantiate that particular object. All the fields within the object are set by using public setter methods or direct access to public members.
If you don't use a public no-arg constructor, the SDK doesn't know how to create an instance of the class. Most serialization libraries will have the same requirement.
I believe the error is pretty self-explanatory. You just need to add an empty constructor to your Artist class:
package com.rcpl.agni;
/**
* Created by Dell-pc on 23-01-2018.
*/
public class Artist {
String artistId;
String artistName;
String artistGenre;
public Artist(){}
public Artist(String artistId, String artistName, String artistGenre) {
this.artistId = artistId;
this.artistName = artistName;
this.artistGenre = artistGenre;
}
public String getArtistId() {
return artistId;
}
public String getArtistName() {
return artistName;
}
public String getArtistGenre() {
return artistGenre;
}
}
Firebase requires this constructor in order to use it when you call artistSnapshot.getValue(Artist.class);
add the non-argument in the Data class
Run the app with a clear logcat:
I tried so hard but I Can't convert an object of type java.lang.Long to type (My Model class).
I am uploading my getDataFromFirebase() method below:
MainActivity.class
private void getDataFromFirebase() {
binding.projectRecycler.setHasFixedSize(true);
binding.projectRecycler.setLayoutManager(new LinearLayoutManager(activity));
binding.projectRecycler.setAdapter(adapter);
adapter = new ProjectAdapter(activity,projectDetailsBeanList);
projectDetailsBeanList = new ArrayList<>();
firebaseDatabase =FirebaseDatabase.getInstance();
databaseRef = firebaseDatabase.getReference("project_details");
DBListener = databaseRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
projectDetailsBeanList.clear();
for(DataSnapshot dataSnapshot : snapshot.getChildren()){
ProjectModel.ProjectDetailsBean projectDetailsBean = dataSnapshot.getValue(ProjectModel.ProjectDetailsBean.class);
projectDetailsBean.setKey(snapshot.getKey());
projectDetailsBeanList.add(projectDetailsBean);
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(activity, error.toString(), Toast.LENGTH_SHORT).show();
}
});
}
My Model Class
public class ProjectModel {
private ProjectDetailsBean project_details;
public ProjectDetailsBean getProject_details() {
return project_details;
}
public void setProject_details(ProjectDetailsBean project_details) {
this.project_details = project_details;
}
public static class ProjectDetailsBean {
private int architect_no;
private String client_name;
private String payment_received;
private String project_complete_date;
private String project_name;
private int project_no;
private String project_received_date;
private String key;
#Exclude
public String getKey() {
return key;
}
#Exclude
public void setKey(String key) {
this.key = key;
}
public int getArchitect_no() {
return architect_no;
}
public void setArchitect_no(int architect_no) {
this.architect_no = architect_no;
}
public String getClient_name() {
return client_name;
}
public void setClient_name(String client_name) {
this.client_name = client_name;
}
public String getPayment_received() {
return payment_received;
}
public void setPayment_received(String payment_received) {
this.payment_received = payment_received;
}
public String getProject_complete_date() {
return project_complete_date;
}
public void setProject_complete_date(String project_complete_date) {
this.project_complete_date = project_complete_date;
}
public String getProject_name() {
return project_name;
}
public void setProject_name(String project_name) {
this.project_name = project_name;
}
public int getProject_no() {
return project_no;
}
public void setProject_no(int project_no) {
this.project_no = project_no;
}
public String getProject_received_date() {
return project_received_date;
}
public void setProject_received_date(String project_received_date) {
this.project_received_date = project_received_date;
}
}
}
JSON data
{
"project_details" : {
"architect_no" : 1,
"client_name" : "pratik bharad",
"payment_received" : "yes",
"project_complete_date" : "22/09/2020",
"project_name" : "project of building",
"project_no" : 1,
"project_received_date" : "22/06/2020"
}
}
Error is:
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.Long to type com.psb.aurumdesign.ProjectModel$ProjectDetailsBean
You are getting the following error:
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.Long to type com.psb.aurumdesign.ProjectModel$ProjectDetailsBean
Because you are trying to convert the first child from your project_details node which is of type Long into an object of type ProjectDetailsBean, which is actually not possible. As I see in the JSON schema, under the project_details node, there is actually a single object, so there is no need to actually loop through the children in order to get the data. You can simply map that object directly into an object of type ProjectDetailsBean, as in the following lines of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference projectDetailsRef = rootRef.child("project_details");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
ProjectDetailsBean projectDetailsBean = dataSnapshot.getValue(ProjectDetailsBean.class);
Log.d("TAG", projectDetailsBean.getProject_name());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("TAG", databaseError.getMessage()); //Don't ignore potential errors!
}
};
projectDetailsRef.addListenerForSingleValueEvent(valueEventListener);
The result in the logcat will be the name of the project. If you only need, for example, the value of a single property, you can change the following line of code:
ProjectDetailsBean projectDetailsBean = dataSnapshot.getValue(ProjectDetailsBean.class);
To:
String projectName = dataSnapshot.child("project_name").getValue(String.class);
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 3 years ago.
I am getting a java.lang.NullPointerException error, and even though I checked mInternshipId and it is the same as I was expecting, it does not work.
This is my Firebase Content
This is my Internship Class
public class Internship {
private String internshipId;
private String internshipTitle;
private String internshipDesc;
private String internshipDate;
private String internshipImage;
private String internshipCreatorId;
public Internship() {
}
public Internship(String internshipId, String internshipTitle, String internshipDesc, String internshipDate, String internshipImage, String internshipCreatorId) {
this.internshipId = internshipId;
this.internshipTitle = internshipTitle;
this.internshipDesc = internshipDesc;
this.internshipDate = internshipDate;
this.internshipImage = internshipImage;
this.internshipCreatorId = internshipCreatorId;
}
public String getInternshipTitle() {
return internshipTitle;
}
public String getInternshipId() {
return internshipId;
}
public void setInternshipId(String internshipId) {
this.internshipId = internshipId;
}
public void setInternshipTitle(String internshipTitle) {
this.internshipTitle = internshipTitle;
}
public String getInternshipDesc() {
return internshipDesc;
}
public void setInternshipDesc(String internshipDesc) {
this.internshipDesc = internshipDesc;
}
public String getInternshipDate() {
return internshipDate;
}
public void setInternshipDate(String internshipDate) {
this.internshipDate = internshipDate;
}
public String getInternshipImage() {
return internshipImage;
}
public void setInternshipImage(String internshipImage) {
this.internshipImage = internshipImage;
}
public String getInternshipCreatorId() {
return internshipCreatorId;
}
public void setInternshipCreatorId(String internshipCreatorId) {
this.internshipCreatorId = internshipCreatorId;
}
}
This is where I am using it. It shows that mInternship is not been initialized. Thank you everyone in advance for your time.
//Get The Internship ID
Intent intent = getIntent();
mInternshipId = intent.getStringExtra(INTERNSHIP_ID);
//Initialize the Database Reference
databaseReference = FirebaseDatabase.getInstance().getReference().child("Internships").child(mInternshipId);
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
//Initialize Useful Variables
mInternship = dataSnapshot.getValue(Internship.class);
organizationId = mInternship.getInternshipCreatorId();
databaseReference = FirebaseDatabase.getInstance().getReference().child("Users").child("Organizations").child(organizationId);
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
internshipLocation = (String) dataSnapshot.child("location").getValue();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
The problem is at this line
mInternshipId = intent.getStringExtra(INTERNSHIP_ID);
you are not getting your extra, so you can't reference to an object inside your Firebase Database, and this is causing a null pointer at a null reference to retrieve the data.
Make sure that you are getting the extra in this class, put a debug point and see the value of mInternshipId
There is a way to check if mInternshipId is the problem.
databaseReference = FirebaseDatabase.getInstance().getReference().child("Internships").child(mInternshipId);
Run this line without mInternshipId and hardcode a child to get the data.
databaseReference = FirebaseDatabase.getInstance().getReference().child("Internships").child("-LchJYhSf3uwlv7AAXtr");
If that works with a hardcode child, you can assure that the problem is at your getStringExtra().
I have implemented a history mechanism for my mvp4g project. When I traverse through the pages, I can see the url also getting changed. But on reload of any page other than home page, always home page gets displayed instead of the desired page?
This is my implementation:
#History(type = HistoryConverterType.SIMPLE)
public class CustomHistoryConverter implements HistoryConverter<AppEventBus> {
private CustomEventBus eventBus;
#Override
public void convertFromToken(String historyName, String param, CustomEventBus eventBus) {
this.eventBus = eventBus;
eventBus.dispatch(historyName, param);
}
public String convertToToken(String eventName, String name) {
return name;
}
public String convertToToken(String eventName) {
return eventName;
}
public String convertToToken(String eventName, String name, String type) {
return name;
}
public boolean isCrawlable() {
return false;
}
}
and event bus related code :
#Events(startPresenter=PageOnePresenter.class,historyOnStart=true)
public interface CustomEventBus extends EventBusWithLookup {
#Start
#Event(handlers = PageOnePresenter.class)
void start();
#InitHistory
#Event(handlers = PageOnePresenter.class)
void init();
#Event(handlers = PageTwoPresenter.class, name = "page2", historyConverter = CustomHistoryConverter.class)
void getPageTwo();
#Event(handlers = PageThreePresenter.class, name = "page3", historyConverter=CustomHistoryConverter.class)
void getPageThree();
#Event(handlers=PageOnePresenter.class, name = "page1", historyConverter=CustomHistoryConverter.class)
void getPageOne();
#Event(handlers=PageOnePresenter.class)
void setPageTwo(HistoryPageTwoView view);
#Event(handlers=PageOnePresenter.class)
void setPageThree(HistoryPageThreeView view);
}
The HistoryConverter needs to be improved.
In fact, that the event has no parameter, you should return an empty string. Update the HistoryConverter that it looks like that:
#History(type = HistoryConverterType.SIMPLE)
public class CustomHistoryConverter implements HistoryConverter<AppEventBus> {
private CustomEventBus eventBus;
#Override
public void convertFromToken(String historyName, String param, CustomEventBus eventBus) {
this.eventBus = eventBus;
// TODO handle the param in cases where you have more than one parameter
eventBus.dispatch(historyName, param);
}
public String convertToToken(String eventName, String name) {
return name;
}
public String convertToToken(String eventName) {
return "";
}
public String convertToToken(String eventName, String name, String type) {
return name - "-!-" type;
}
public boolean isCrawlable() {
return false;
}
}
Hope that helps.
I am getting an error for the following code in a java web app--
XStream xstream = new XStream();
apiresponse myClassObject;
myClassObject= xstream.fromXML(resp);
The error is shown for the line of code just above this line--
error="Type mismatch- cannot convert from Object to apiresponse"
Given below is the XML that I have to parse---
<apiresponse version="1" xmlns="http://ahrefs.com/schemas/api/links/1">
<resultset_links count="2">
<result>
<source_url>http://ahrefs.com/robot/</source_url>
<destination_url>http://blog.ahrefs.com/</destination_url>
<source_ip>50.22.24.236</source_ip>
<source_title>Ahrefs – backlinks research tool</source_title>
<visited>2011-08-31T07:56:53Z</visited>
<anchor>Blog</anchor>
<rating>257.674000</rating>
<link_type>text</link_type>
<is_nofollow>false</is_nofollow>
</result>
<result>
<source_url>http://apps.vc/</source_url>
<destination_url>http://ahrefs.com/robot/</destination_url>
<source_ip>64.20.55.86</source_ip>
<source_title>Device info</source_title>
<visited>2011-08-27T18:59:31Z</visited>
<anchor>http://ahrefs.com/robot/</anchor>
<rating>209.787100</rating>
<link_type>text</link_type>
<is_nofollow>false</is_nofollow>
</result>
</resultset_links>
</apiresponse>
I have created the following java classes to obtain data from above xml---
package com.arvindikchari.linkdatasmith.domain;
final public class apiresponse {
protected resultset_links rlinks;
public apiresponse() {
}
public resultset_links getRlinks()
{
return rlinks;
}
public setRlinks(resultset_links rlinks)
{
this.rlinks=rlinks;
}
}
final public class resultset_links {
protected List<result> indiv_result = new ArrayList<result>();
public resultset_links() {
}
public List<result> getIndiv_result()
{
return List;
}
public void setIndiv_result(List<result> indiv_result)
{
this.indiv_result=indiv_result;
}
}
final public class result {
protected String source_url;
protected String destination_url;
protected String source_ip;
protected String source_title;
protected String visited;
protected String anchor;
protected String rating;
protected String link_type;
public result() {
}
public String getSource_url()
{
return source_url;
}
public void setSource_url(String source_url)
{
this.source_url=source_url;
}
public String getDestination_url()
{
return destination_url;
}
public void setDestination_url(String destination_url)
{
this.destination_url=destination_url;
}
public String getSource_ip()
{
return source_ip;
}
public void setSource_ip(String source_ip)
{
this.source_ip=source_ip;
}
public String getSource_title()
{
return source_title;
}
public void setSource_title(String source_title)
{
this.source_title=source_title;
}
public String getVisited()
{
return visited;
}
public void setVisited(String visited)
{
this.visited=visited;
}
public String getAnchor()
{
return anchor;
}
public void setAnchor(String anchor)
{
this.anchor=anchor;
}
public String getRating()
{
return rating;
}
public void setRating(String rating)
{
this.rating=rating;
}
public String getLink_type()
{
return link_type;
}
public void setLink_type(String link_type)
{
this.link_type=link_type;
}
}
What am I doing wrong here?
You have many errors, but the one corresponding to your message is you have to cast the result of xstream.fromXML to an apiresponse' object :
apiresponse result = (apiresponse)xstream.fromXML(resp);
Moreover, the code you provided (the Java classes) do not compile, there are many errors.
Here are some improvements :
Result.java :
#XStreamAlias("result")
public class Result {
protected String source_url;
protected String destination_url;
protected String source_ip;
protected String source_title;
protected String visited;
protected String anchor;
protected String rating;
protected String link_type;
protected Boolean is_nofollow;
public Result() {
}
public String getSource_url()
{
return source_url;
}
public void setSource_url(String source_url)
{
this.source_url=source_url;
}
public String getDestination_url()
{
return destination_url;
}
public void setDestination_url(String destination_url)
{
this.destination_url=destination_url;
}
public String getSource_ip()
{
return source_ip;
}
public void setSource_ip(String source_ip)
{
this.source_ip=source_ip;
}
public String getSource_title()
{
return source_title;
}
public void setSource_title(String source_title)
{
this.source_title=source_title;
}
public String getVisited()
{
return visited;
}
public void setVisited(String visited)
{
this.visited=visited;
}
public String getAnchor()
{
return anchor;
}
public void setAnchor(String anchor)
{
this.anchor=anchor;
}
public String getRating()
{
return rating;
}
public void setRating(String rating)
{
this.rating=rating;
}
public String getLink_type()
{
return link_type;
}
public void setLink_type(String link_type)
{
this.link_type=link_type;
}
public Boolean getIs_nofollow() {
return is_nofollow;
}
public void setIs_nofollow(Boolean is_nofollow) {
this.is_nofollow = is_nofollow;
}
ResultsetLinks.java :
#XStreamAlias("resultset_links")
public class ResultsetLinks {
#XStreamImplicit(itemFieldName="result")
protected List<Result> indivResult = new ArrayList<Result>();
public ResultsetLinks() {
}
public List<Result> getResult()
{
return indivResult;
}
public void setResult(List<Result> indiv_result)
{
this.indivResult =indiv_result;
}
}
ApiResponse.java :
#XStreamAlias("apiresponse")
public class ApiResponse {
#XStreamAlias("resultset_links")
protected ResultsetLinks rlinks;
public ApiResponse() {
}
public ResultsetLinks getRlinks()
{
return rlinks;
}
public void setRlinks(ResultsetLinks rlinks)
{
this.rlinks=rlinks;
}
}
And finally your code to unmarshall the XML :
XStream xstream = new XStream();
xstream.processAnnotations(ApiResponse.class);
xstream.processAnnotations(ResultsetLinks.class);
xstream.processAnnotations(Result.class);
ApiResponse result = (ApiResponse)xstream.fromXML(resp);
All this code is working fine with Xstream 1.4.2
Try to follow Sun's coding convention for your classes name, attributes names, etc...
Use XstreamAliases to adapt the Java class name to the XML name.