I was using FirebaseMessagingService to send a notification to other users using my app, the problem is I cannot add extra data to the message. I have a notification, sender, and data model classes. Problem is when I try adding the data model when sending the token however I get invalid JSON.
Notifcation class:
public String title;
public String body;
public Notification() {
}
public Notification(String title, String body) {
this.title = title;
this.body = body;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
Sender class:
public class Sender {
public Notification data;
public data extra;
public String to;
public Sender() {
}
public Sender(Notification data, data extra, String to) {
this.data = data;
this.to = to;
this.extra = extra;
}
public Notification getData() {
return data;
}
public void setData(Notification data) {
this.data = data;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
}
data class:
public class data {
public String username;
public data() {
}
public data(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
Home:
data extra = new data("Test");
Notification notification = new Notification("title test", "body test");
Sender content = new Sender(notification, extra, token.getToken());
mService.sendMessage(content)
.enqueue(new Callback<FCMResponse>() {
#Override
public void onResponse(Call<FCMResponse> call, Response<FCMResponse> response) {
Log.i(TAG, "onResponse: " + response.toString());
if (response.body().success == 1){
Toast.makeText(c, "Request sent!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(c, "Request failed!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<FCMResponse> call, Throwable t) {
Log.e(TAG, "onFailure: "+ t.getMessage());
}
});
MyFirebaseMessaingService:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage.getData().isEmpty()){
} else {
String title = remoteMessage.getData().get("title").toString();
String body = remoteMessage.getData().get("body").toString();
String username = remoteMessage.getData().get("username").toString();
Log.i(TAG, "showNotifcation: " + title + body + username);
}
}
Problem occurs when i send extra data from the model class i.e the username. Without send extra data i.e just the notification it will work fine.
Related
am using retrofit for insert data to my webservice, I have made it before but without uploading the image and the insert is successful, the input field through the model class not in interface,how I add an input field fot uploading files through the model so that it can be sent to my web services storage folder?
I have tried but failed please help
for my insert in activity
btnsubmit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String tanggal = textdate.getText().toString();
SimpleDateFormat formatter1=new SimpleDateFormat("dd/MM/yyyy");
Date date1= null;
try {
date1 = formatter1.parse(tanggal);
} catch (ParseException e) {
e.printStackTrace();
}
SwabtestModel sw = new SwabtestModel();
sw.sethasil(texthasil.getText().toString());
sw.settanggal(date1);
sw.settempat(texttempat.getText().toString());
sw.setuserid(Integer.valueOf(txtuserid.getText().toString()));
sw.setFile_name(new File(txturi.getText().toString()));
save(sw);
}
});
public void save(SwabtestModel sw){
Call<SwabtestModel> call = swabtestService.addswab(sw);
call.enqueue(new Callback<SwabtestModel>() {
#Override
public void onResponse(Call<SwabtestModel> call, Response<SwabtestModel> response) {
if(response.isSuccessful()){
String status = response.body().getStatus();
Toast.makeText(SwabtestActivity.this, status, Toast.LENGTH_LONG).show(); }
}
#Override
public void onFailure(Call<SwabtestModel> call, Throwable t) {
Log.e("ERROR: ", t.getMessage());
}
});
}
for my file chooser
public void onActivityResult(int request_code, int result_code, Intent data){
super.onActivityResult(request_code,result_code,data);
if(request_code==request_code && result_code== Activity.RESULT_OK){
if(data==null){
return;
}
uri= data.getData();
filePath = uri.getPath();
txturi.setText(filePath);
}
}
public void openfilechooser(){
Intent intent= new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
startActivityForResult(intent,request_code);
}
for my model class
public class SwabtestModel {
#SerializedName("hasil")
#Expose
private String hasil;
#SerializedName("tanggal")
#Expose
private Date tanggal;
#SerializedName("tempat")
#Expose
private String tempat;
#SerializedName("file_name")
#Expose
private File file_name;
#SerializedName("user_id")
#Expose
private Integer user_id;
String data;
String status;
public SwabtestModel(String hasil, Date tanggal, String tempat){
this.hasil = hasil;
this.tanggal = tanggal;
this.tempat = tempat;
}
public void sethasil(String hasil) {
this.hasil = hasil;
}
public String gethasil(){
return hasil;
}
public void settanggal(Date tanggal) {
this.tanggal = tanggal;
}
public Date gettanggal(){
return tanggal;
}
public void settempat(String tempat) {
this.tempat = tempat;
}
public String gettempat(){
return tempat;
}
public void setuserid(Integer user_id) {
this.user_id = user_id;
}
public Integer getuserid(){
return user_id;
}
public void setFile_name( File file_name) {
this.file_name =file_name ;
}
public File getfilename(){
return file_name;
}
public String getData() {
return data;
}
public String getStatus() {
return status;
}
}
my interface
public interface swabtestService
{
#GET("hasil-antigen-list")
Call<List<SwabtestModel>> getUsers();
#POST("insert-hantigen")
Call<SwabtestModel> addswab(#Body SwabtestModel swabtest);
}
To upload files you should use Multipart, Please refer to this post for example and please ping me if you have any queries https://stackoverflow.com/a/39953566
Take a data in list like #Part List<MultipartBody.Part> partFile
private List<MultipartBody.Part> getMapPartListSave(List<PojoAttachDocList> fields) {
List<MultipartBody.Part> mapPart = new ArrayList<>();
for (int i = 0; i < fields.size(); i++) {
**PojoAttachDocList** attachDoc = fields.get(i);
if (!attachDoc.isAttached() && attachDoc.getDocFile() != null && attachDoc.getDocFile().exists()
&& attachDoc.getDocFile().length() > 0) {
String fileParam = PARAMS_DOCUMENT + "[" + i + "]";
mapPart.add(MultipartBody.Part.createFormData(fileParam, attachDoc.getDocFile().getName(),
RequestBody.create(MediaType.parse("*/*"), attachDoc.getDocFile())));
}
}
return mapPart;
}
Convert it to MultipartBody
Being new to Retrofit2 and having troubles in processing the Response Body from the Call - the needed Response is visible in the Android Studio Debugger, the data is there; however, due to lack of Java skills,
it is unclear to me how to access the Data that I am receiving. It looks like type conversion is needed.
The data looks like this -
Log.d(TAG, "messageId" + addBookingMessageList.toString());
gives me
messageIdcom.example.xxx.AddBookingMessage#88fe1de
and
Log.d(TAG, "addBookingMessageList Class" + addBookingMessageList.getClass().getName());
returns
addBookingMessageList Classjava.lang.String
How do I parse this data correctly? I know it´s an Object, but it is
unclear to me how to access the object properties.
Any hints or help would be very much appreciated.
Here´s my Retrofit Call:
public static void putBookingOnPallet(String basic,
AddBookingMessage message, Context mContext) {
MessagesApi messageApi = retrofit.create(MessagesApi.class);
//making the call objects
Call<AddBookingMessage> call = messageApi.addBooking(basic, message);
//call.execute();
call.enqueue(new Callback<AddBookingMessage>() {
#Override
public void onResponse(#NonNull Call<AddBookingMessage> call, #NonNull
Response<AddBookingMessage> response) {
if (response.isSuccess()) {
Object addBookingMessageList;
addBookingMessageList = response.body().toString();
Log.d(TAGGG, (String) addBookingMessageList.toString());
Log.d(TAG, "messageId" + addBookingMessageList.toString());
Log.d(TAG, "addBookingMessageList Class" + addBookingMessageList.getClass().getName());
//Toast.makeText(context, statusCode, Toast.LENGTH_LONG).show();
}
else {
int statusCode = response.code();
Log.d(TAG, "statusCode" + statusCode);
}
}
#Override
public void onFailure(Call<AddBookingMessage> call, Throwable t) {
Log.d(TAG, "t.getMessage" + t.getMessage());
Toast.makeText(mContext, t.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
Here´s my MessagesAPI:
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.POST;
public interface MessagesApi {
String BASE_URL = "xxx";
#POST("message")
#Headers({ "Content-Type: application/json;charset=UTF-8"})
Call<AddBookingMessage> addBooking(
#Header("Authorization")
String basic,
#Body AddBookingMessage message
);
#POST("message")
#Headers({ "Content-Type: application/json;charset=UTF-8"})
Call<AddBookingMessage> removebooking(
#Header("Authorization")
String basic,
#Body AddBookingMessage message
);
}
Here´s my Pojo:
package xxx;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class AddBookingMessage {
#SerializedName("type")
#Expose
private String type;
#SerializedName("time")
#Expose
private Integer fromID;
#SerializedName("fromID")
#Expose
private Integer toID;
#SerializedName("toID")
#Expose
private Integer typeID;
#SerializedName("typeID")
#Expose
private String title;
#SerializedName("title")
#Expose
private String receiptNo;
#SerializedName("receiptNo")
#Expose
private String note;
#SerializedName("note")
#Expose
/* private String id;
#SerializedName("id")
#Expose*/
private Long time;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public void setTitle(String title) {
this.title = title;
}
public void getTitle(String title) {
this.title = title;
}
public Integer getFromId() {
return fromID;
}
public void setFromId(Integer fromID) {
this.fromID = fromID;
}
public Integer getToID() {
return toID;
}
public void setToId(Integer toId) {
this.toID = toId;
}
public Integer getTypeId() {
return typeID;
}
public void setTypeId(Integer typeID) {
this.typeID = typeID;
}
public String getReceiptNo() {
return receiptNo;
}
public void setReceiptNo(String receiptNo) {
this.receiptNo = receiptNo;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public Long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
/*public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}*/
}
Again, any hints or help would be vey much appreciated as I am stuck here, Thanks in advance!
As #Chirag Rayani mentioned, you should have your pojo in the api definition and in the call. So you should have something like:
MessageApi:
Change
Call<Object> addBooking(headers, etc...);
to
Call<AddBookingMessage> addBooking(headers, etc...);
And same for the call:
Call<AddBookingMessage> call = messageApi.addBooking(basic, message);
call.enqueue(new Callback<AddBookingMessage>() {
#Override
public void onResponse(#NonNull Call<AddBookingMessage> call, #NonNull
Response<AddBookingMessage> response) {
if (response.isSuccess()) {
// use your object here
Log.v("response", "id " + response.body().getId());
...
}
}
#Override
public void onFailure(Call<AddBookingMessage> call, Throwable t) {
...
}
});
I want to make a fitur to login, I want to make a feature to log in, initially I saw the response code shows 200, but when I saw the response body was null. I can still log in, but the logged in user data isn't saved. I used 2 db MySql and SQLite and im using retrofit and shared preference. And here my code
API Interface
public interface Api {
#FormUrlEncoded
#POST(Config.API_LOGIN_USER)
Call<UserOrtu> loginUser(
#Field("email") String email,
#Field("password") String password
);
PrefUtil.java
public class PrefUtil {
public static final String USER_SESSION = "user_session";
public static final String USER_STORAGE = "user_storage";
public static SharedPreferences getSharedPreferences(Context ctx){
return PreferenceManager.getDefaultSharedPreferences(ctx);
}
public static void putUser(Context ctx, String key, UserOrtu user){
Gson gson = new Gson();
String json = gson.toJson(user);
putString(ctx, key, json);
}
public static UserOrtu getUser(Context ctx, String key){
Gson gson = new Gson();
String json = getString(ctx, key);
UserOrtu user = gson.fromJson(json, UserOrtu.class);
return user;
}
public static void putString(Context ctx, String key, String value){
getSharedPreferences(ctx).edit().putString(key, value).apply();
}
public static String getString(Context ctx, String key){
return getSharedPreferences(ctx).getString(key, null);
}
public static void clear(Context ctx) {
getSharedPreferences(ctx).edit().clear().apply();
}
}
Models
UserOrtu.java
public class UserOrtu {
#SerializedName("id_user")
#Expose
private int idUser;
#SerializedName("nama")
#Expose
private String nama;
#SerializedName("email")
#Expose
private String email;
#SerializedName("password")
#Expose
private String password;
#SerializedName("error")
#Expose
private Boolean error;
#SerializedName("message")
#Expose
private String message;
public int getIdUser() {
return idUser;
}
public void setIdUser(int idUser) {
this.idUser = idUser;
}
public String getNama() {
return nama;
}
public void setNama(String nama) {
this.nama = nama;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Boolean getError() {
return error;
}
public void setError(Boolean error) {
this.error = error;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
SignInActivity.java
public class SignInActivity extends AppCompatActivity {
#BindView(R.id.input_email_signin)
TextInputEditText etEmail;
#BindView(R.id.text_register)
TextView tvRegister;
#BindView(R.id.input_password_signin)
TextInputEditText etPassword;
EmailValidator emailValidator;
PasswordValidator passwordValidator;
Context context;
private String email;
private String password;
private Api mApi;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (isSessionLogin()){
startActivity(new Intent(this, MainActivity.class));
this.finish();
}
setContentView(R.layout.activity_sign_in);
ButterKnife.bind(this);
AndroidThreeTen.init(this);
mApi = RetrofitBuilder.builder(this).create(Api.class);
}
boolean isEmail(EditText text){
emailValidator = new EmailValidator();
String email = text.getText().toString();
return emailValidator.isValid(email);
}
boolean isPassword(EditText text){
passwordValidator = new PasswordValidator();
String pass = text.getText().toString();
return passwordValidator.isValid(pass);
}
#OnClick(R.id.text_register) void toRegister(){
Intent intent = new Intent(this, SignUpActivity.class);
startActivity (intent);
}
#OnClick(R.id.btn_signin) void onLogin(){
if(isEempty(etEmail)){
etEmail.setError("Email harus diisi");
}else if(isEempty(etPassword)){
etPassword.setError("Password harus diisi");
}else if(!isEmail(etEmail)){
etEmail.setError("Email tidak valid");
}else if(!isPassword(etPassword)){
String str = passwordValidator.getString();
Toast.makeText(getApplicationContext(),str, Toast.LENGTH_SHORT).show();
}else {
loginAct();
}
}
void loginAct(){
email = etEmail.getText().toString();
password = etPassword.getText().toString();
final MaterialDialog dialog = DialogBuilder.showLoadingDialog(SignInActivity.this, "Updating Data", "Please wait..", false);
mApi.loginUser(email, password).enqueue(new Callback<UserOrtu>() {
#Override
public void onResponse(Call<UserOrtu> call, Response<UserOrtu> response) {
UserOrtu user = response.body();
Log.i("USER_LOGIN", response.message());
if (user != null){
//Masih error disini
//if (!user.getError()){
PrefUtil.putUser(getApplicationContext(), PrefUtil.USER_SESSION, user);
Intent intent = new Intent(SignInActivity.this, MainActivity.class);
startActivity(intent);
//this.finish();
//}
Toast.makeText(getApplicationContext(), user.getMessage(), Toast.LENGTH_SHORT).show();
}
if (response.code() == 403){
etPassword.requestFocus();
etPassword.setError(getString(R.string.error_password));
}
if (response.code() == 404){
etEmail.requestFocus();
etEmail.setError(getString(R.string.error_login));
}
dialog.dismiss();
}
#Override
public void onFailure(Call<UserOrtu> call, Throwable t) {
//Toast.makeText(getActivity(), t.getMessage(), Toast.LENGTH_SHORT).show();
dialog.dismiss();
Log.i("USER_LOGIN", t.getMessage());
DialogBuilder.showErrorDialog(SignInActivity.this, "Gagal Login");
}
});
}
// this method to check is user logged in ?
boolean isSessionLogin(){
return PrefUtil.getUser(getApplicationContext(), PrefUtil.USER_SESSION) != null;
}
}
And here's my result
enter image description here
Here's my JSON request
enter image description here
Your model is not representing same data as in JSON. With UserOrtu class it will works only if your response will have structure like below:
{
"id":1,
"nama": "Name",
"email":"email",
"message":"msg"
}
But as you can see 3 first fields are inside another object data. So your model should look more like:
class LoginResponse{
#SerializedName("data")
#Expose
private UserOrtu userData;
#SerializedName("message")
#Expose
private String message;
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 3 years ago.
I am trying to call login API using Retrofit2.
But in onResponse i alwasy get null as response.
Login API endpoint
#FormUrlEncoded
#POST("/api/login/{mobile}")
Call<ResObj> userLogin( #Field("phoneNumber") String mobile );
And the API implementation
private void doLogin(final String mobile){
Call<ResObj> call = userService.login(mobile);
call.enqueue(new Callback<ResObj>() {
#Override
public void onResponse(Call<ResObj> call, Response<ResObj> response) {
ResObj resObj = response.body(); // here i am getting null response.body()
if(resObj.getMessage().equals("true")){
Intent intent = new Intent(Login.this, ListActivity.class);
intent.putExtra("mobile", mobile);
startActivity(intent);
} else{
Toast.makeText(Login.this, "Phone Number is incorrect!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ResObj> call, Throwable t) {
Toast.makeText(Login.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
ResObj class:
public class ResObj {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
I just want to know what causes the error and what are possible solutions.
UPDATE
POSTMAN
You are getting null response in your login API. It may be due to many reasons. You can check your API is working as expected or not using POSTMAN.
And inside your code, you can prevent this type of exception by checking OBJECT is null or not. like the following.
#Override
public void onResponse(Call<ResObj> call, Response<ResObj> response) {
ResObj resObj = response.body();
if(resObj != null){ // checking object is not null
if(resObj.getStatus()){
Intent intent = new Intent(Login.this, ListActivity.class);
intent.putExtra("mobile", mobile);
startActivity(intent);
} else{
Toast.makeText(Login.this, "Phone Number is incorrect!", Toast.LENGTH_SHORT).show();
}
}else{
// handle null response here.
}
}
Update:
According to your Response JSON, Your Model(ResObj) class should be like the following.
public class ResObj
{
private String date;
private String address;
private String accountName;
private String contactPerson;
private String timeOut;
private String problem;
private String srNo;
private String fieldEngineer;
private String joNo;
private String irNo;
private String designation;
private String email;
private String timeIn;
private String productType;
private boolean status;
private String contactNo;
public String getDate ()
{
return date;
}
public void setDate (String date)
{
this.date = date;
}
public String getAddress ()
{
return address;
}
public void setAddress (String address)
{
this.address = address;
}
public String getAccountName ()
{
return accountName;
}
public void setAccountName (String accountName)
{
this.accountName = accountName;
}
public String getContactPerson ()
{
return contactPerson;
}
public void setContactPerson (String contactPerson)
{
this.contactPerson = contactPerson;
}
public String getTimeOut ()
{
return timeOut;
}
public void setTimeOut (String timeOut)
{
this.timeOut = timeOut;
}
public String getProblem ()
{
return problem;
}
public void setProblem (String problem)
{
this.problem = problem;
}
public String getSrNo ()
{
return srNo;
}
public void setSrNo (String srNo)
{
this.srNo = srNo;
}
public String getFieldEngineer ()
{
return fieldEngineer;
}
public void setFieldEngineer (String fieldEngineer)
{
this.fieldEngineer = fieldEngineer;
}
public String getJoNo ()
{
return joNo;
}
public void setJoNo (String joNo)
{
this.joNo = joNo;
}
public String getIrNo ()
{
return irNo;
}
public void setIrNo (String irNo)
{
this.irNo = irNo;
}
public String getDesignation ()
{
return designation;
}
public void setDesignation (String designation)
{
this.designation = designation;
}
public String getEmail ()
{
return email;
}
public void setEmail (String email)
{
this.email = email;
}
public String getTimeIn ()
{
return timeIn;
}
public void setTimeIn (String timeIn)
{
this.timeIn = timeIn;
}
public String getProductType ()
{
return productType;
}
public void setProductType (String productType)
{
this.productType = productType;
}
public boolean getStatus ()
{
return status;
}
public void setStatus (boolean status)
{
this.status = status;
}
public String getContactNo ()
{
return contactNo;
}
public void setContactNo (String contactNo)
{
this.contactNo = contactNo;
}
}
You are passing parameter as raw data(according to your screen-shot). So your API endpoint would be like below.
#Headers("Content-Type: application/json")
#POST("/api/login")
Call<ResObj> userLogin(#Body JsonObject jsonObject);
And call your API like this
private void doLogin(final String mobile){
try {
JsonObject paramObject = new JsonObject();
paramObject.addProperty("mobile", mobile);
} catch (JSONException e) {
e.printStackTrace();
}
Call<ResObj> call = userService.login(paramObject);
call.enqueue(new Callback<ResObj>() {
//your rest of code
});
}
UPDATE-2:
To send object from one Activity to another using intent you have to make your model class Percelable. like this
// implements Parcelable
public class ResObj implements Parcelable {
// ...........your previous code here
// just simply add the following methods
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(date);
dest.writeString(address);
dest.writeString(accountName);
dest.writeString(contactPerson);
dest.writeString(timeOut);
dest.writeString(problem);
dest.writeString(srNo);
dest.writeString(fieldEngineer);
dest.writeString(joNo);
dest.writeString(irNo);
dest.writeString(designation);
dest.writeString(email);
dest.writeString(timeIn);
dest.writeString(productType);
dest.writeByte((byte) (status ? 1 : 0));
dest.writeString(contactNo);
}
public static final Parcelable.Creator<ResObj> CREATOR
= new Parcelable.Creator<ResObj>() {
public ResObj createFromParcel(Parcel in) {
return new ResObj(in);
}
public ResObj[] newArray(int size) {
return new ResObj[size];
}
};
protected ResObj(Parcel in) {
date = in.readString();
address = in.readString();
accountName = in.readString();
contactPerson = in.readString();
timeOut = in.readString();
problem = in.readString();
srNo = in.readString();
fieldEngineer = in.readString();
joNo = in.readString();
irNo = in.readString();
designation = in.readString();
email = in.readString();
timeIn = in.readString();
productType = in.readString();
status = in.readByte() != 0;
contactNo = in.readString();
}
}
Now pass your object via intent like the following.
if(resObj != null){
if(resObj.getStatus()){
Intent intent = new Intent(Login.this, ListActivity.class);
intent.putExtra("your_key", resObj); // pass resObj and use same key to get data
startActivity(intent);
} else{
Toast.makeText(Login.this, "Phone Number is incorrect!", Toast.LENGTH_SHORT).show();
}
}
Get data from your ListActivity like this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
final ResObj yourObject = getIntent().getParcelableExtra("your_key"); // make sure you use same key like data.
// Now you can use your data like that
yourEditText.setText(yourObject.getEmail());
}
I want to receive all challenges in Firestore and loop over result to add it to an ArrayList.
db.collection("challenges")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
if (document.exists()) {
Log.d(TAG, document.getId() + " => " + document.getData());
Error-> Challenge challenge = document.toObject(Challenge.class);
Log.d(TAG, challenge.getUid() + " => " + challenge.getText());
challengeList.add(document.getData().toString());
}
}
challengeListView.setAdapter(challengeArrayAdapter);
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
Error is:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.reflect.Constructor.newInstance(java.lang.Object[])' on a null object reference
Line:
Challenge challenge = document.toObject(Challenge.class);
The log with Log.d(TAG, document.getId() + " => " + document.getData());
is working.
Reference: https://firebase.google.com/docs/firestore/query-data/get-data#get_all_documents_in_a_collection
This is my my Challenge Class:
public class Challenge {
private Date createdAt;
private Date changedAt;
private String uid;
private String text;
private double longitude;
private double latitude;
public Challenge(String uid, String text, double longitude, double latitude) {
Date currentDate = new Date();
this.createdAt = currentDate;
this.changedAt = currentDate;
this.uid = uid;
this.text = text;
this.longitude = longitude;
this.latitude = latitude; }
public Date getCreatedAt() { return createdAt; }
public Date getChangedAt() { return changedAt; }
public String getUid() { return uid; }
public String getText() { return text; }
public double getLongitude() { return longitude; }
public double getLatitude() { return latitude;}
}
You need to change this line of code:
Challenge challenge = document.toObject(Challenge.class);
with
Map<String, Object> map = task.getResult().getData());
To use toObject() method for a single document, please use the following code:
DocumentReference docRef = db.collection("challenges").document("yourDocument");
docRef.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
Challenge challenge = documentSnapshot.toObject(Challenge.class);
}
});
The error is because of your modell class. Your code looks good. Add the no-argument constructor in your model class. Keep that code or use the Map<String, Object> and your problem will be solved.
To add the no-argument constructor, please add the following line of code in your model class:
public Challenge() {} //Needed for Firebase
after the decalaration of class variables.
I know it is too late but it may help some one in my case my object was
public class RFQ {
public String content,email,receiverKey,productKey,companyKey;
public Sender sender;
public Long createAt;
public RFQ() {
}
public RFQ(String content, String email, String receiverKey, String productKey, String companyKey, Sender sender, Long createAt) {
this.content = content;
this.email = email;
this.receiverKey = receiverKey;
this.productKey = productKey;
this.companyKey = companyKey;
this.sender = sender;
this.createAt = createAt;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Long getCreateAt() {
return createAt;
}
public void setCreateAt(Long createAt) {
this.createAt = createAt;
}
public String getReceiverKey() {
return receiverKey;
}
public void setReceiverKey(String receiverKey) {
this.receiverKey = receiverKey;
}
public String getProductKey() {
return productKey;
}
public void setProductKey(String productKey) {
this.productKey = productKey;
}
public String getCompanyKey() {
return companyKey;
}
public void setCompanyKey(String companyKey) {
this.companyKey = companyKey;
}
public Sender getSender() {
return sender;
}
public void setSender(Sender sender) {
this.sender = sender;
}
}
Everything is proper here but still, I was getting the error that was due to my Sender class in my Sender class I missed to place non-args constructor.
Bro, you need to add Default Constructor in your Challenge Model class as it is needed for Firebase
public Challenge() {} //add this line