Firebase Session Management: Issues with instatiating Global User - java

I'm a Android Studio coding beginner and currently building a nutrition app to get programming practice. I use Firebase for Authentication and as a database to save User data.
How it works:
My app has a survey built in which asks for body specifics and taste (age, height, liked/disliked ingredients etc.). I have a class GlobalUser with public static attributes to save the answers in the app. When the user registers, he is sent directly to the survey activity. There he answers the questions and the results are written to the Firebase database under his UID (I use a User class with the same attributes as GlobalUser to create an instance and use Firebase's setValue(Object) method). If he signs in (or still is signed in), the LoginRegistrationActivity directly sends him to the MainActivity. There, the GlobalUser class gets instantiated with the data saved under his UID. From the MainActivity, he can navigate to a ProfileActivity where the UI gets updated based on his data. This works quite well. After doing the survey I can find the results in a child node consisting of the UID of the user, the UI gets updated correctly and the sign in/registration process works as intended.
What is wrong:
However, as I was playing around with different designs and constantly restarting the app, it started to crash occasionally. After some testing it showed that the GlobalUser class wasn't updated and thus the ArrayLists were null and caused NullPointerExceptions when I used .size() on them. Since this issue only occurs rarely and seems to be related to restarting the app multiple times I thought it would have something to do with the Activity lifecycle so I also updated the GlobalUser in onStart and onResume but it didn't help. I also tried updating GlobalUser again in the ProfileActivity directly before the ArrayLists were set but it didn't work. I still guess it has something to do with the lifecycle but I have no idea where I should start. Here's the code of the relevant classes/actvitites:
LoginRegistrationActivity:
public class LoginRegistrationActivity extends AppCompatActivity {
private DatabaseReference mRef;
private FirebaseAuth mAuth;
private EditText emailAddress;
private EditText emailPassword;
private Button emailLogin;
private Button emailRegistration;
private TextView forgotPassword;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login_registration);
mAuth = FirebaseAuth.getInstance();
if (mAuth.getCurrentUser()!=null){
Intent i = new Intent (LoginRegistrationActivity.this, MainActivity.class);
LoginRegistrationActivity.this.startActivity(i);
}
emailAddress = findViewById(R.id.address_edit);
emailPassword = findViewById(R.id.password_edit);
emailLogin = findViewById(R.id.mail_login_button);
emailRegistration = findViewById(R.id.mail_registration_button);
forgotPassword = findViewById(R.id.forgot_password);
emailRegistration.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String email = emailAddress.getText().toString().trim();
String password = emailPassword.getText().toString().trim();
if (TextUtils.isEmpty(email)){
Toast.makeText(LoginRegistrationActivity.this, "Bitte E-Mail Addresse eingeben!", Toast.LENGTH_LONG).show();
return;
}
if (TextUtils.isEmpty(password)){
Toast.makeText(LoginRegistrationActivity.this, "Bitte Passwort eingeben!", Toast.LENGTH_LONG).show();
return;
}
if (password.length()<6){
Toast.makeText(LoginRegistrationActivity.this, "Passwort muss mindestens sechs Zeichen lang sein!", Toast.LENGTH_LONG).show();
return;
}
mAuth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(LoginRegistrationActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (!task.isSuccessful()){
Toast.makeText(LoginRegistrationActivity.this, "Unbekannter Fehler", Toast.LENGTH_LONG).show();
} else {
Intent i = new Intent (LoginRegistrationActivity.this, SurveyGreetingActivity.class);
LoginRegistrationActivity.this.startActivity(i);
finish();
}
}
});
}
});
emailLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String password = emailPassword.getText().toString();
String email = emailAddress.getText().toString();
if (TextUtils.isEmpty(email)){
Toast.makeText(LoginRegistrationActivity.this, "Bitte E-Mail Addresse eingeben!", Toast.LENGTH_LONG).show();
return;
}
if (TextUtils.isEmpty(password)){
Toast.makeText(LoginRegistrationActivity.this, "Bitte Passwort eingeben!", Toast.LENGTH_LONG).show();
return;
}
if (password.length()<6){
Toast.makeText(LoginRegistrationActivity.this, "Passwort muss mindestens sechs Zeichen haben!", Toast.LENGTH_LONG).show();
return;
}
mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(LoginRegistrationActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (!task.isSuccessful()){
Toast.makeText(LoginRegistrationActivity.this, "Unbekannter Fehler beim Einloggen", Toast.LENGTH_LONG).show();
} else {
Intent i = new Intent (LoginRegistrationActivity.this, MainActivity.class);
LoginRegistrationActivity.this.startActivity(i);
finish();
}
}
});
}
});
}
}
MainActivity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final FirebaseAuth mAuth = FirebaseAuth.getInstance();
FirebaseUser user = mAuth.getCurrentUser();
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference mRef = database.getReference().child("users").child("uid").child(mAuth.getCurrentUser().getUid());
//In case the user cancelled the app when filling out the survey for the first time
if (mRef == null){
MainActivity.this.startActivity(new Intent (MainActivity.this, SurveyGreetingActivity.class));
}
//sets GlobalUser to data saved in Firebase Database User object
mRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
if (user!=null){
GlobalUser.setToUser(user);
GlobalUser.setGlobalUid(mAuth.getCurrentUser().getUid());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(getApplicationContext(), "Database Error", Toast.LENGTH_LONG).show();
}
});
}
}
GlobalUser:
package com.example.andre.valetto02;
import java.util.ArrayList;
public class GlobalUser {
public static String globalUid = null;
public static ArrayList<Ingredient> globalLikes;
public static ArrayList<Ingredient> globalDislikes;
public static int globalAge;
public static int globalWeight;
public static int globalHeight;
public static int globalTrainingGoal;
public static int globalDailyActive;
public static boolean globalIsMale;
public GlobalUser() {
}
public static String getGlobalUid() {
return globalUid;
}
public static void setGlobalUid(String globalUid) {
GlobalUser.globalUid = globalUid;
}
public static ArrayList<Ingredient> getGlobalLikes() {
return globalLikes;
}
public static void setGlobalLikes(ArrayList<Ingredient> globalLikes) {
GlobalUser.globalLikes = globalLikes;
}
public static ArrayList<Ingredient> getGlobalDislikes() {
return globalDislikes;
}
public static void setGlobalDislikes(ArrayList<Ingredient> globalDislikes) {
GlobalUser.globalDislikes = globalDislikes;
}
public static int getGlobalAge() {
return globalAge;
}
public static void setGlobalAge(int globalAge) {
GlobalUser.globalAge = globalAge;
}
public static int getGlobalWeight() {
return globalWeight;
}
public static void setGlobalWeight(int globalWeight) {
GlobalUser.globalWeight = globalWeight;
}
public static int getGlobalHeight() {
return globalHeight;
}
public static void setGlobalHeight(int globalHeight) {
GlobalUser.globalHeight = globalHeight;
}
public static int getGlobalTrainingGoal() {
return globalTrainingGoal;
}
public static void setGlobalTrainingGoal(int globalTrainingGoal) {
GlobalUser.globalTrainingGoal = globalTrainingGoal;
}
public static int getGlobalDailyActive() {
return globalDailyActive;
}
public static void setGlobalDailyActive(int globalDailyActive) {
GlobalUser.globalDailyActive = globalDailyActive;
}
public static boolean isGlobalIsMale() {
return globalIsMale;
}
public static void setGlobalIsMale(boolean globalIsMale) {
GlobalUser.globalIsMale = globalIsMale;
}
public static void setToUser(User user) {
GlobalUser.setGlobalAge(user.getAge());
GlobalUser.setGlobalWeight(user.getWeight());
GlobalUser.setGlobalHeight(user.getHeight());
GlobalUser.setGlobalDailyActive(user.getDailyActive());
GlobalUser.setGlobalTrainingGoal(user.getTrainingGoal());
GlobalUser.setGlobalIsMale(user.getIsMale());
GlobalUser.setGlobalLikes(user.getLikes());
GlobalUser.setGlobalDislikes(user.getDislikes());
}
public static void resetLikesAndDislikes(){
globalLikes = new ArrayList <>();
globalDislikes = new ArrayList<>();
}
public static User globalToUser () {
return new User (globalLikes, globalDislikes, globalWeight, globalHeight, globalAge, globalTrainingGoal, globalDailyActive, globalIsMale);
}
}
User:
package com.example.andre.valetto02;
import java.util.ArrayList;
public class User {
ArrayList<Ingredient> likes;
ArrayList<Ingredient> dislikes;
Boolean isMale;
public Boolean getIsMale(){return isMale;}
public void setIsMale(Boolean b){isMale = b;}
public void setDislikes(ArrayList<Ingredient> dislikes) {
this.dislikes = dislikes;
}
public User (){
likes = new ArrayList<>();
dislikes = new ArrayList<>();
weight = 0;
height = 0;
age = 0;
trainingGoal = 2;
dailyActive = 1;
isMale=true;
}
public User (ArrayList<Ingredient> l, ArrayList<Ingredient> d, int w, int h, int a, int tG, int dA, boolean iM) {
likes = l;
dislikes = d;
weight = w;
height = h;
age = a;
trainingGoal = tG;
dailyActive = dA;
isMale = iM;
}
int age;
public ArrayList<Ingredient> getDislikes() {
return dislikes;
}
public ArrayList<Ingredient> getLikes() {
return likes;
}
public void setLikes (ArrayList<Ingredient> list){
likes = list;
}
public void setDisikes (ArrayList<Ingredient> list){
dislikes = list;
}
public int getAge () {
return age;
}
public void setAge (int i) {
age = i;
}
int weight;
public int getWeight (){
return weight;
}
public void setWeight(int i) {
weight = i;
}
int height;
public int getHeight (){
return height;
}
public void setHeight(int i) {
height = i;
}
int trainingGoal; //trainingGoal = 0 means weight loss, 1 means muscle gain and 2 means healthy living
public void setTrainingGoal(int i) {
trainingGoal = i;
}
public int getTrainingGoal(){
return trainingGoal;
}
int dailyActive; //dailyActive = 0 means wenig, 1 means leicht, 2 means moderat, 3 means sehr and 4 means extrem
public int getDailyActive() {return dailyActive;}
public void setDailyActive(int i) {dailyActive = i;}
public double computeCalorieGoal(){
if (isMale) {
double RMR;
RMR = weight*10 + 6.25*height - 5*age + 5;
if (dailyActive==0) {RMR=RMR*1.2;}
else if (dailyActive==1) {RMR=RMR*1.375;}
else if (dailyActive==2) {RMR=RMR*1.55;}
else if (dailyActive==3) {RMR=RMR*1.725;}
else {RMR=RMR*1.9;}
if (trainingGoal == 0) {RMR = RMR - 400;}
else if (trainingGoal ==1){RMR = RMR + 400;}
return RMR;
} else {
double RMR;
RMR = weight*10 + 6.25*height - 5*age - 161;
if (dailyActive==0) {RMR=RMR*1.2;}
else if (dailyActive==1) {RMR=RMR*1.375;}
else if (dailyActive==2) {RMR=RMR*1.55;}
else if (dailyActive==3) {RMR=RMR*1.725;}
else {RMR=RMR*1.9;}
if (trainingGoal == 0) {RMR = RMR - 300;}
else if (trainingGoal ==1){RMR = RMR + 300;}
return RMR;
}
}
}
Thanks for the help!

I just found the mistake. It has nothing to do with the activity lifecycle and it only indirectly had something to do with restarting the app. The problem was that Firebase's Value Event Listeners are still AsyncTasks. When I started the app and immediately opened the ProfileActivity, the Activity was created before the Firebase AsyncTask could fetch the data from the Database. Thus the ProfileActivity would call the .size() method on the ArrayLists before they were instantiated. In essence, the error occurred when you clicked too quickly through the UI and were faster than the asynchronous data fetching task.
Therefore I moved the session management to the LoginRegistrationActivity like this:
if (mAuth.getCurrentUser()!=null){
FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
DatabaseReference mRef = firebaseDatabase.getReference().child("users").child("uid").child(mAuth.getCurrentUser().getUid());
//In case the user cancelled the app when filling out the survey for the first time
if (mRef == null){
LoginRegistrationActivity.this.startActivity(new Intent (LoginRegistrationActivity.this, SurveyGreetingActivity.class));
}
mRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
if (user!=null) {
GlobalUser.setToUser(user);
GlobalUser.setGlobalUid(mAuth.getCurrentUser().getUid());
}
Intent i = new Intent (LoginRegistrationActivity.this, MainActivity.class);
LoginRegistrationActivity.this.startActivity(i);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
By moving LoginRegistrationActivity.this.startActivity(i) to the onDataChange method, I ensure that the GlobalUser variables get instantiated before the MainActivity is started. There are probably still more elegant ways to do this.

Related

How to properly use Executer In Room Android

So I am relatively new to programming, and I have been working on this task app, where I want to save the data such as task name and more, given by the user. I am trying to accomplish this using Room. Now, initially, when I tried to do it, the app would crash since I was doing everything on the main thread probably. So, after a little research, I came to AsyncTask, but that is outdated. Now finally I have come across the Executer. I created a class for it, but I am a little unsure as to how I can implement it in my app. This is what I did :
Entity Class :
#Entity (tableName = "subtasks")
public class SubtaskDetails {
#PrimaryKey(autoGenerate = true)
private int id;
#ColumnInfo(name = "subtaskName")
private String subtasksName;
#ColumnInfo(name = "priority")
private boolean priHigh;
private boolean priMed;
private boolean priLow;
#ColumnInfo(name = "time")
private boolean timeMore;
private boolean timeMed;
private boolean timeLess;
public SubtaskDetails(String subtasksName, boolean priHigh, boolean priMed, boolean priLow, boolean timeMore, boolean timeMed, boolean timeLess){
this.subtasksName = subtasksName;
this.priHigh = priHigh;
this.priMed = priMed;
this.priLow = priLow;
this.timeMore = timeMore;
this.timeMed = timeMed;
this.timeLess = timeLess;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSubtasksName() {
return subtasksName;
}
public void setSubtasksName(String subtasksName) {
this.subtasksName = subtasksName;
}
public boolean isPriHigh() {
return priHigh;
}
public void setPriHigh(boolean priHigh) {
this.priHigh = priHigh;
}
public boolean isPriMed() {
return priMed;
}
public void setPriMed(boolean priMed) {
this.priMed = priMed;
}
public boolean isPriLow() {
return priLow;
}
public void setPriLow(boolean priLow) {
this.priLow = priLow;
}
public boolean isTimeMore() {
return timeMore;
}
public void setTimeMore(boolean timeMore) {
this.timeMore = timeMore;
}
public boolean isTimeMed() {
return timeMed;
}
public void setTimeMed(boolean timeMed) {
this.timeMed = timeMed;
}
public boolean isTimeLess() {
return timeLess;
}
public void setTimeLess(boolean timeLess) {
this.timeLess = timeLess;
}
}
Dao Class:
#Dao
public interface UserDao {
#Query("Select * from subtasks")
List<SubtaskDetails> getSubtaskDetailsList();
#Insert
void insertSubtaskDetails(SubtaskDetails subtaskDetails);
#Update
void updateSubtaskDetails(SubtaskDetails subtaskDetails);
#Delete
void deleteSubtaskDetails(SubtaskDetails subtaskDetails);
}
App Database Class :
#Database(entities = SubtaskDetails.class, exportSchema = false, version = 1)
public abstract class AppDatabase extends RoomDatabase {
private static final String DB_NAME = "subtaskdetails_db";
private static AppDatabase instance;
public static synchronized AppDatabase getInstance(Context context){
if (instance == null){
instance = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DB_NAME).fallbackToDestructiveMigration().build();
}
return instance;
}
public abstract UserDao subtaskdetailsdao();
}
Executer Class :
public class AppExecutors {
// For Singleton instantiation
private static final Object LOCK = new Object();
private static AppExecutors sInstance;
private final Executor diskIO;
private final Executor mainThread;
private final Executor networkIO;
private AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) {
this.diskIO = diskIO;
this.networkIO = networkIO;
this.mainThread = mainThread;
}
public static AppExecutors getInstance() {
if (sInstance == null) {
synchronized (LOCK) {
sInstance = new AppExecutors(Executors.newSingleThreadExecutor(),
Executors.newFixedThreadPool(3),
new MainThreadExecutor());
}
}
return sInstance;
}
public Executor diskIO() {
return diskIO;
}
public Executor mainThread() {
return mainThread;
}
public Executor networkIO() {
return networkIO;
}
private static class MainThreadExecutor implements Executor {
private Handler mainThreadHandler = new Handler(Looper.getMainLooper());
#Override
public void execute(#NonNull Runnable command) {
mainThreadHandler.post(command);
}
}
}
Where I try to implement it : (I have written a comment where I do it)
public class TaskInfo extends AppCompatActivity {
//Declaring variables
EditText etWorkingHours, etWorkingMinutes, etTaskName, etWorkingMins, etWorkinghrs, etSubtaskName;
Button btnNewSubtask;
Button btnSaveTaskName;
Button btnProceed;
ImageView ivLeft, ivRight;
TextView tvBreakTime;
TextView tvTaskName;
int breaktime = 10;
final int ENTER_SUBTASK = 20;
final int EDIT_SUBTASK = 40;
ListView lvSubtasks;
ArrayList<subtask> subtaskList = new ArrayList<>();
ScrollView scrollView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_task_info);
//Connecting XML to JAVA
etWorkingHours = findViewById(R.id.etWorkingHours);
etWorkingMinutes = findViewById(R.id.etWorkingMinutes);
etTaskName = findViewById(R.id.etTaskName);
btnNewSubtask = findViewById(R.id.btnNewSubtask);
ivLeft = findViewById(R.id.ivLeft);
ivRight = findViewById(R.id.ivRight);
tvBreakTime = findViewById(R.id.tvBreakTime);
etWorkinghrs = findViewById(R.id.etWorkingHrs);
etWorkingMins = findViewById(R.id.etWorkingMins);
lvSubtasks = findViewById(R.id.lvSubtasks);
scrollView = findViewById(R.id.scrollView);
btnSaveTaskName = findViewById(R.id.btnSaveTask);
tvTaskName = findViewById(R.id.tvTaskName);
btnProceed = findViewById(R.id.btnProceed);
tvTaskName.setVisibility(View.INVISIBLE);
if (tvTaskName.getText().equals(""))
{
tvTaskName.setClickable(false);
}
else
{
tvTaskName.setClickable(true);
}
// Code for the left right arrows along with break duration
ivRight.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (breaktime >= 10 && breaktime < 60)
{breaktime += 5;
String time = breaktime + "";
tvBreakTime.setText(time);}
else
{
String time = breaktime + "";
tvBreakTime.setText(time);
}
}
});
ivLeft.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (breaktime > 10 && breaktime <= 60)
{
breaktime -= 5;
String time = breaktime + "";
tvBreakTime.setText(time);}
else
{
String time = breaktime + "";
tvBreakTime.setText(time);
}
}
});
btnNewSubtask.setEnabled(false);
btnSaveTaskName.setEnabled(false);
//save button enabler when task name is written
etTaskName.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
btnSaveTaskName.setEnabled(!TextUtils.isEmpty(s.toString().trim()));
}
#Override
public void afterTextChanged(Editable s) {
}
});
btnSaveTaskName.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tvTaskName.setVisibility(View.VISIBLE);
tvTaskName.setText(etTaskName.getText().toString().toUpperCase().trim());
etTaskName.setVisibility(View.GONE);
btnSaveTaskName.setVisibility(View.GONE);
btnNewSubtask.setEnabled(true);
}
});
tvTaskName.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String tasksname = tvTaskName.getText().toString().trim();
tvTaskName.setText("");
etTaskName.setVisibility(View.VISIBLE);
etTaskName.setText(tasksname);
btnSaveTaskName.setVisibility(View.VISIBLE);
}
});
btnNewSubtask.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i2 = new Intent(TaskInfo.this, SubtaskActivity.class);
startActivityForResult(i2, ENTER_SUBTASK);
overridePendingTransition(R.anim.slide_in_up, R.anim.slide_out_up);
}
});
btnProceed.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (etWorkingHours.getText().toString().isEmpty())
{
etWorkingHours.setText("0");
}
if (etWorkingMinutes.getText().toString().isEmpty())
{
etWorkingMinutes.setText("0");
}
if (etWorkinghrs.getText().toString().isEmpty())
{
etWorkinghrs.setText("0");
}
if (etWorkingMins.getText().toString().isEmpty())
{
etWorkingMins.setText("0");
}
int working_hours = Integer.parseInt(etWorkinghrs.getText().toString().trim());
int working_minutes = Integer.parseInt(etWorkingMins.getText().toString().trim());
int without_break_hours = Integer.parseInt(etWorkingHours.getText().toString().trim());
int without_break_minutes = Integer.parseInt(etWorkingMinutes.getText().toString().trim());
if (etWorkingHours.getText().toString().isEmpty() || etWorkingMinutes.getText().toString().isEmpty() || etWorkinghrs.getText().toString().isEmpty() || etWorkingMins.getText().toString().isEmpty())
{
Toast.makeText(TaskInfo.this, "Field cannot be empty, please try again.", Toast.LENGTH_SHORT).show();
}
else
{
if (working_hours != 0)
{
if (working_hours > without_break_hours)
{
int breaktime = Integer.parseInt(tvBreakTime.getText().toString());
Intent intent = new Intent(TaskInfo.this, TaskSummary.class);
intent.putExtra("working_hours", working_hours);
intent.putExtra("working_minutes", working_minutes);
intent.putExtra("without_break_hours", without_break_hours);
intent.putExtra("without_break_minutes", without_break_minutes);
intent.putExtra("break_duration", breaktime);
startActivity(intent);
}
if (working_hours == without_break_hours){
if (working_minutes >= without_break_minutes){
int breaktime = Integer.parseInt(tvBreakTime.getText().toString());
Intent intent = new Intent(TaskInfo.this, TaskSummary.class);
intent.putExtra("working_hours", working_hours);
intent.putExtra("working_minutes", working_minutes);
intent.putExtra("without_break_hours", without_break_hours);
intent.putExtra("without_break_minutes", without_break_minutes);
intent.putExtra("break_duration", breaktime);
startActivity(intent);
}
if (working_minutes < without_break_minutes){
Toast.makeText(TaskInfo.this, "Invalid Time Entered", Toast.LENGTH_SHORT).show();
}
}
if (working_hours < without_break_hours){
Toast.makeText(TaskInfo.this, "Invalid Time Entered", Toast.LENGTH_SHORT).show();
}
}
if (working_hours == 0){
if (without_break_hours == 0)
{
if (working_minutes >= without_break_minutes){
int breaktime = Integer.parseInt(tvBreakTime.getText().toString());
Intent intent = new Intent(TaskInfo.this, TaskSummary.class);
intent.putExtra("working_hours", working_hours);
intent.putExtra("working_minutes", working_minutes);
intent.putExtra("without_break_hours", without_break_hours);
intent.putExtra("without_break_minutes", without_break_minutes);
intent.putExtra("break_duration", breaktime);
startActivity(intent);
}
if (working_minutes < without_break_minutes){
Toast.makeText(TaskInfo.this, "Invalid Time Entered", Toast.LENGTH_SHORT).show();
}
}
if (without_break_hours != 0)
{
Toast.makeText(TaskInfo.this, "Invalid Time Entered", Toast.LENGTH_SHORT).show();
}
}
}
}
});
//Applying the max min thing for which the class InputFilterMinMax is defined
etWorkingHours.setFilters(new InputFilter[]{new InputFilterMinMax("0", "24")});
etWorkingMinutes.setFilters(new InputFilter[]{new InputFilterMinMax("0", "59")});
etWorkinghrs.setFilters(new InputFilter[]{new InputFilterMinMax("0", "24")});
etWorkingMins.setFilters(new InputFilter[]{new InputFilterMinMax("0", "59")});
}
// This is where I try to implement the executer :
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ENTER_SUBTASK)
{
if (resultCode == RESULT_OK)
{
SubtaskAdapter adapter = new SubtaskAdapter(this, subtaskList);
assert data != null;
String subtaskName = data.getStringExtra("subtaskName");
boolean priHigh = data.getBooleanExtra("priHigh", false);
boolean priMed = data.getBooleanExtra("priMed", false);
boolean priLow = data.getBooleanExtra("priLow", false);
boolean timeMore = data.getBooleanExtra("timeMore", false);
boolean timeMed = data.getBooleanExtra("timeMed", false);
boolean timeLess = data.getBooleanExtra("timeLess", false);
AppDatabase appDb = AppDatabase.getInstance(this);
AppExecutors.getInstance().diskIO().execute(new Runnable() {
#Override
public void run() {
SubtaskDetails subtaskDetails = new SubtaskDetails(subtaskName,priHigh, priMed, priLow, timeMore, timeMed, timeLess);
appDb.subtaskdetailsdao().insertSubtaskDetails(subtaskDetails);
}
});
lvSubtasks.setAdapter(adapter);
subtask subtask = new subtask(subtaskName, priHigh, priMed, priLow, timeMore, timeMed, timeLess);
subtaskList.add(subtask);
adapter.addANewSubTask(subtask);
}
}
}
// Menu (action bar) code
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
switch (item.getItemId())
{
case (R.id.settings):
startActivity(new Intent(this, SettingsActivity.class));
break;
}
return super.onOptionsItemSelected(item);
}
//Class to make max and min value on the edit text of hours and minutes, so that they cant enter anything more than 24 hours, and 59 minutes
static class InputFilterMinMax implements InputFilter {
private int min, max;
public InputFilterMinMax(int min, int max) {
this.min = min;
this.max = max;
}
public InputFilterMinMax(String min, String max) {
this.min = Integer.parseInt(min);
this.max = Integer.parseInt(max);
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try {
int input = Integer.parseInt(dest.toString() + source.toString());
if (isInRange(min, max, input))
return null;
} catch (NumberFormatException nfe) { }
return "";
}
private boolean isInRange(int a, int b, int c) {
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
}
}
EDIT :
I implemented the code, but I am facing a few issues in the viewmodel class. For eg, the parameter in repository.insertSubtaskDetails(userDao); is userDao, but it actually it requires of type subtaskDetails.. some errors in the todo part as well. this is the code:
package com.example.taskmasterv3;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import java.util.List;
public class ViewModel extends AndroidViewModel {
private Repository repository;
private List<SubtaskDetails> subtaskDetails;
public ViewModel(#NonNull Application application) {
super(application);
repository = new Repository(application);
subtaskDetails = repository.getSubtaskDetails();
}
public void insert(UserDao userDao) {
repository.insertSubtaskDetails(userDao);
}
public void delete(Todo todo) {
repository.deleteSubtaskDetails(userDao);
}
}
First make a Repository class and make an instance of your DAO
public class Repository {
private UserDAO userDAO;
private List<SubtaskDetails> subtaskDetails;
private Executor executor = Executors.newSingleThreadExecutor();
public Repository(Application application){
AppDatabase appDatabase = AppDatabase.getInstance(application);
userDAO = appDatabase.userDAO();
subtaskDetails = userDAO.getSubtaskDetailsList();
}
Then wrap it around your executor
public void insertSubtaskDetails(SubtaskDetails subtaskDetails){
executor.execute(new Runnable() {
#Override
public void run() {
userDAO.insertSubtaskDetails(subtaskDetails);
}
});
}// For inserting
public void deleteSubtaskDetails(SubtaskDetails subtaskDetails){
executor.execute(new Runnable() {
#Override
public void run() {
userDAO.deleteSubtaskDetails(subtaskDetails);
}
});
}// for deleting
Basically just wrap your DAO queries around the executor.

Unable to use boolean values in IF statements

I have a database that is being checked using a Cursor. This database compares the data in the database to the user entered username and password. If they match data in the database a boolean is returned true. I can use a toast to output the boolean which correctly outputs as true or false if the input data does or does not match.
However, i am trying to use the boolean to move to the next activity. If the boolean is true the next intent is started. This does not work for some reason and I cant seem to work out why. Any help would be great. Thanks!
public Button btnLogin, btnSignup;
public EditText UsernameInput, PasswordInput;
public DatabaseHelper db;
public static String passUser, passPass, passFirst, passSecond;
public int count;
public Boolean matchingUser = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Align page and remove notification bar
getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
// Define everything
btnLogin = findViewById(R.id.btnLogin);
btnSignup = findViewById(R.id.btnSignup);
UsernameInput = findViewById(R.id.UsernameInput);
PasswordInput = findViewById(R.id.PasswordInput);
db = new DatabaseHelper(this);
// validation button
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
validateLogin(UsernameInput.getText().toString(), PasswordInput.getText().toString());
}
});
btnSignup.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CreateUser();
}
});
}
// Validation code
public void validateLogin(String userName, String userPassword)
{
if (userName.equals("")|| userPassword.equals(""))
{
Toast.makeText(getApplicationContext(),"Fields are empty",Toast.LENGTH_SHORT).show();
}
else
{
// CHECKING USER LOGIN DETAILS
Cursor cursor = db.CompareUserData();
for (count = 0; count<=cursor.getCount();count++)
{
if (cursor.moveToPosition(count))
{
if (UsernameInput.getText().toString().equals(cursor.getString(0))&&PasswordInput.getText().toString().equals(cursor.getString(1)))
{
matchingUser = true;
}
}
Toast.makeText(this, "boolean : "+ matchingUser, Toast.LENGTH_SHORT).show();
if (matchingUser = true)
{
passUser = cursor.getString(0);
passPass = cursor.getString(1);
passFirst = cursor.getString(2);
passSecond = cursor.getString(3);
getUser();
getPass();
getFirst();
getSecond();
Toast.makeText(getApplicationContext(), "Successfully logged in", Toast.LENGTH_SHORT).show();
LoginValidation();
}
if (matchingUser = false)
{
Toast.makeText(getApplicationContext(),"Incorrect Username",Toast.LENGTH_SHORT).show();
}}
}
}
private void LoginValidation()
{
// Changing activity code
startActivity(new Intent(MainActivity.this,Login_Biometrics.class));
}
private void CreateUser()
{
// Changing activity code
startActivity(new Intent(MainActivity.this,createUser.class));
}
public static String getUser ()
{
return passUser;
}
public static String getPass ()
{
return passPass;
}
public static String getFirst ()
{
return passFirst;
}
public static String getSecond ()
{
return passSecond;
}
It wont work with one = equal sign just do:
if(matchingUser) {
// if true do something
} else {
// if false do something
}
In your case:
if (matchingUser) {
passUser = cursor.getString(0);
passPass = cursor.getString(1);
passFirst = cursor.getString(2);
passSecond = cursor.getString(3);
getUser();
getPass();
getFirst();
getSecond();
Toast.makeText(getApplicationContext(), "Successfully logged in",Toast.LENGTH_SHORT).show();
LoginValidation();
} else {
Toast.makeText(getApplicationContext(),"Incorrect Username",Toast.LENGTH_SHORT).show();
}
You have to understand some basics:
Assignment operator =
Is used to assign value to some variable.
Logical operator ==
Is used to make some logical comparison.
So instead of doing this:
if (matchingUser = true)
{
...
Do this
if (matchingUser == true)
{
...
Apply this for every condition checking in your code.

How to update total no of child from firebase child node everytime onDataChange from AddSingleValueEventListner?

Below image shows my Firebase database structure:
All data retrieved successfully. Here is my model class.
public class Post
{
public String lastname;
public String postid;
public long timestamp;
public HashMap<String,Boolean> count;
public Post()
{
}
public Post(String lastname, long timestamp, String postid,HashMap count)
{
this.lastname=lastname;
this.timestamp=timestamp;
this.postid=postid;
this.count=count;
}
public HashMap<String, Boolean> getCounts() {
return count;
}
public void setCounts(HashMap<String, Boolean> count) {
this.count = count;
}
In Main Activity i used to get data
mAdapter = new PostAdapter(MainActivity.this);
getAllPost(null);
postList.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (!recyclerView.canScrollVertically(1))
{
loaded=loaded+10;
if (totalPost== mAdapter.getItemCount())
{
Toast.makeText(MainActivity.this, "no more post", Toast.LENGTH_SHORT).show();
}
else
{
getAllPost(mAdapter.getLastItemId());
}
}
}
});
postList.setAdapter(mAdapter);
private void getAllPost(final String nodeId)
{
final Query query;
final int left= (int) (totalPost-mAdapter.getItemCount());
Toast.makeText(this, String .valueOf(left), Toast.LENGTH_SHORT).show();
if (nodeId == null)
{
query = PostRef
.orderByChild("timestamp")
.limitToLast(mPostsPerPage);
}
else
{
if (left<10)
{
query = PostRef
.orderByChild("timestamp")
.limitToFirst(left);
}
else
{
Long time=Long.parseLong(nodeId);
query = PostRef
.orderByChild("timestamp").endAt(time)
.limitToLast(10);
}
}
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Post> userModels = new ArrayList<>();
for (DataSnapshot userSnapshot : dataSnapshot.getChildren())
{
userModels.add(userSnapshot.getValue(Post.class));
}
if (!(nodeId ==null))
{
if (left>10)
{
userModels.remove(9);
}
}
Collections.reverse(userModels);
mAdapter.addAll(userModels);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
And in adapter:
public class PostAdapter extends RecyclerView.Adapter<PostHolder>
{
List<Post> mPost;
Context mContext;
public PostAdapter(Context c) {
this.mPost = new ArrayList<>();
mContext=c;
}
#NonNull
#Override
public PostHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
return new PostHolder(LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.all_post_layout, viewGroup, false));
}
#Override
public void onBindViewHolder(#NonNull final PostHolder postHolder, final int i) {
final String PostKey=mPost.get(i).getPostid();
FirebaseAuth mAuth=FirebaseAuth.getInstance();
final String currentUserID=mAuth.getCurrentUser().getUid();
final DatabaseReference post=FirebaseDatabase.getInstance().getReference().child("Posts");
showCounts(postHolder,i);
setCountsButton(postHolder,i,currentUserID);
tapOnCounts(postHolder,i,currentUserID,post,PostKey);
}
private void tapOncounts(final PostHolder postHolder, final int i, final String currentUserID, final DatabaseReference post, final String postKey)
{
postHolder.countsButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
if (mPost.get(i).getCounts() !=null)
{
if(mPost.get(i).getCounts().containsKey(currentUserID))
{
post.child(postKey).child("counts").child(currentUserID).removeValue();
postHolder.countsButton.setImageResource(R.drawable.discounts);
}
else
{
postHolder.countsButton.setImageResource(R.drawable.counts);
post.child(postKey).child("counts").child(currentUserID).setValue(true);
}
}
else
{
postHolder.countsButton.setImageResource(R.drawable.counts);
post.child(postKey).child("counts").child(currentUserID).setValue(true);
}
}
});
}
private void setcountsButton(final PostHolder postHolder, int i, String currentUserID)
{
if (mPost.get(i).getCounts() !=null)
{
if(mPost.get(i).getCounts().containsKey(currentUserID))
{
postHolder.countsButton.setImageResource(R.drawable.counts);
}
else
{
postHolder.countsButton.setImageResource(R.drawable.discounts);
}
}
}
private void showCounts(PostHolder postHolder, int i)
{
if((mPost.get(i).getCounts() !=null))
{
postHolder.noOfcounts.setText(String.valueOf(mPost.get(i).getCounts().size()));
}
else
{
postHolder.noOfcounts.setText("0");
}
}
#Override
public int getItemCount() {
return mPost.size();
}
public void addAll(List<Post> newPost) {
int initialSize = mPost.size();
mPost.addAll(newPost);
notifyItemRangeInserted(initialSize, newPost.size());
}
public String getLastItemId() {
return String.valueOf(mPost.get(mPost.size() - 1).getTimestamp());
}
}
All is successfully but whenever total no. of child change(new child added OR old child removed) in count node recylerview is not update. It will only update when i tried to go another activity and come to rerun in MainActivity.
To get realtime updates, you should use Query's addValueEventListener(ValueEventListener listener) method:
Add a listener for changes in the data at this location.
When using addListenerForSingleValueEvent(ValueEventListener listener):
Add a listener for a single change in the data at this location.
Edit:
To get the size of your list, please change the following line of code:
holder.count.setText(String.valueOf(mPost.get(i).getCount().size));
to
holder.count.setText(String.valueOf(getItemCount());
Whenever total number of child changes then your list of Post modal also changes i.e. userModels in your case. Hence whenever your list of model changes your adapter needs to be notified. Hence my guess is to add notifyDataSetChanged to adapter.
Try this:
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Post> userModels = new ArrayList<>();
for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) {
userModels.add(userSnapshot.getValue(Post.class));
}
mAdapter.notifyDataSetChanged(); //<<changes made HERE
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
})
For this to work I hope userModels is instance variable to your MainActivity and is set to mAdapter during initialization.

Android retrieving data from Firebase doesn't work for data models even it works for other data model in the project with similar codes

I am new in Android and working on an Android app which can retrieve data from firebase. There is a weird problem. I already successfully implemented the retrieving function for one data model of my program, and I used same codes just changed the variables but it doesn't work for another data model. I did many tests and I think the problem is in FirebaseHelper cuz there is no any data returned from the data snapshot. The error is
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
The codes are shown below:
The Activity that shows the retrieved data in a listview.
public class TimeTableActivity extends AppCompatActivity {
DatabaseReference db;
FirebaseHelper firebasehelper;
TimeTableAdapter adapter;
ListView lv_CourseList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_time_table);
//GET INTENT
Intent intent = this.getIntent();
String majorID = intent.getStringExtra("MAJOR_ID");
lv_CourseList = (ListView) findViewById(R.id.lv_CourseList);
//INITIALIZE FIREBASE DB
db= FirebaseDatabase.getInstance().getReference();
firebasehelper=new FirebaseHelper(db);
//ADAPTER
adapter = new TimeTableAdapter(getApplicationContext(),firebasehelper.retrieveCourse(majorID, new CourseCallbacks() {
#Override
public void onCourseCallback(ArrayList<CourseInfo> courseInfos) {
lv_CourseList.setAdapter(adapter);
}
}));
lv_CourseList.setAdapter(adapter);
}
}
FirebaseHelper:
public class FirebaseHelper{
private DatabaseReference db;
private ArrayList<Major> majors = new ArrayList<>();
private ArrayList<CourseInfo> courseInfos = new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//Save the Major info. into db
public Boolean saveMajor(Major major)
{
Boolean saved = null;
if(major==null)
{
saved =false;
}else
{
try
{
db.child("Major").push().setValue(major);
saved =true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved =false;
}
}
return saved;
}
//Save the Course info. into db
public Boolean saveCourse(CourseInfo courseInfo)
{
Boolean saved = null;
if(courseInfo==null)
{
saved =false;
}else
{
try
{
db.child("CourseInfo").push().setValue(courseInfo);
saved =true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved =false;
}
}
return saved;
}
public ArrayList<Major> retrieveMajor(final MajorCallbacks majorCallbacks){
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Major major = ds.getValue(Major.class);
if (major != null && major.getMajor_id() != null) {
majors.add(major);
}
}
majorCallbacks.onMajorCallback(majors);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Major major = ds.getValue(Major.class);
if (major != null && major.getMajor_id() != null) {
majors.add(major);
}
}
majorCallbacks.onMajorCallback(majors);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
db.addChildEventListener(childEventListener);
if (!majors.isEmpty()){
db.removeEventListener(childEventListener);
}
return majors;
}
public ArrayList<CourseInfo> retrieveCourse(String majorID, final CourseCallbacks courseCallbacks){
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
CourseInfo courseInfo = ds.getValue(CourseInfo.class);
if (courseInfo != null && courseInfo.getCourse_id() != null) {
courseInfos.add(courseInfo);
}
}
courseCallbacks.onCourseCallback(courseInfos);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
CourseInfo courseInfo = ds.getValue(CourseInfo.class);
if (courseInfo != null && courseInfo.getCourse_id() != null) {
courseInfos.add(courseInfo);
}
}
courseCallbacks.onCourseCallback(courseInfos);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
db.child("CourseInfo").orderByChild("major_id").equalTo(majorID).addChildEventListener(childEventListener);
return courseInfos;
}
}
The retrieveMajor method works well even though it returns many null data and repetitive data, and I used the codes of retrieveMajor in retrieveCourse. It doesn't work, the courseInfos is always null. Even though I changed db.child("CourseInfo").orderByChild("major_id").equalTo(majorID).addChildEventListener(childEventListener);
to
db.addChildEventListener(childEventListener);
,still nothing is retrieved which means the problem is not the query (Probably the query is also wrong).
Adapter:
public class TimeTableAdapter extends BaseAdapter {
Context context;
ArrayList<CourseInfo> courseInfos;
public TimeTableAdapter(Context context, ArrayList<CourseInfo> courseInfos) {
this.context = context;
this.courseInfos = courseInfos;
}
#Override
public int getCount() {
return courseInfos.size();
}
#Override
public Object getItem(int pos) {
return courseInfos.get(pos);
}
#Override
public long getItemId(int pos) {
return pos;
}
#Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
LayoutInflater inflater = LayoutInflater.from(context);
if(convertView == null)
{
convertView= LayoutInflater.from(context).inflate(R.layout.model_timetable,viewGroup,false);
}
TextView tv_courseid= (TextView) convertView.findViewById(R.id.tv_courseid);
TextView tv_coursename= (TextView) convertView.findViewById(R.id.tv_coursename);
TextView tv_courseinstructor= (TextView) convertView.findViewById(R.id.tv_courseinstructor);
TextView tv_courseavailable= (TextView) convertView.findViewById(R.id.tv_courseavailable);
final CourseInfo courseInfo= (CourseInfo) this.getItem(position);
tv_courseid.setText(courseInfo.getCourse_id());
tv_coursename.setText(courseInfo.getCourse_name());
tv_courseinstructor.setText(courseInfo.getCourse_instructor());
tv_courseavailable.setText(courseInfo.getCourse_available());
return convertView;
}
}
Data model:
#IgnoreExtraProperties
public class CourseInfo {
public String course_id;
public String course_name;
public int course_section;
public String course_type;
public double course_crdhrs;
public String course_days;
public String course_times;
public String course_location;
public int course_max;
public int course_cur;
public int course_available;
public int course_wl;
public double course_per;
public String course_instructor;
public String course_description;
public String course_prerequire;
public String major_id;
public CourseInfo() {
}
public CourseInfo(String course_id, String course_name, int course_section, String course_type, double course_crdhrs, String course_days, String course_times, String course_location, int course_max, int course_cur, int course_available, int course_wl, double course_per, String course_instructor, String course_description, String course_prerequire, String major_id) {
this.course_id = course_id;
this.course_name = course_name;
this.course_section = course_section;
this.course_type = course_type;
this.course_crdhrs = course_crdhrs;
this.course_days = course_days;
this.course_times = course_times;
this.course_location = course_location;
this.course_max = course_max;
this.course_cur = course_cur;
this.course_available = course_available;
this.course_wl = course_wl;
this.course_per = course_per;
this.course_instructor = course_instructor;
this.course_description = course_description;
this.course_prerequire = course_prerequire;
this.major_id = major_id;
}
public String getCourse_id() {
return course_id;
}
public String getCourse_name() {
return course_name;
}
public int getCourse_section() {
return course_section;
}
public String getCourse_type() {
return course_type;
}
public double getCourse_crdhrs() {
return course_crdhrs;
}
public String getCourse_days() {
return course_days;
}
public String getCourse_times() {
return course_times;
}
public String getCourse_location() {
return course_location;
}
public int getCourse_max() {
return course_max;
}
public int getCourse_cur() {
return course_cur;
}
public int getCourse_available() {
return course_available;
}
public int getCourse_wl() {
return course_wl;
}
public double getCourse_per() {
return course_per;
}
public String getCourse_instructor() {
return course_instructor;
}
public String getCourse_description() {
return course_description;
}
public String getCourse_prerequire() {
return course_prerequire;
}
public String getMajor_id() {
return major_id;
}
}
If you need more codes or information, please comment and let me know. I will really appreciate if you can also help me solve the null data and repetitive data problem cuz it makes the listview show many blank and repetitive items.
You cannot return something now that hasn't been loaded yet. With other words, you cannot just simply create a method that as a return type, an ArrayList<Major> and in the same time return that object. This is happening because those methods, onChildAdded(), onChildChanged() and so on, have an asynchronous behaviour, which means that are called even before you are getting/updating the data from/in the database. To solve this, you can move the declaration of that ArrayList inside one method and do what you need to do with it or dive into asynchronous world and use the last part of my answer from this post. You can take also a look at this video for a better understanding.

Concurrent access to static method

I have an activity that contains 2 ArcProgress , both of them get data from seperate childs from Firebase, so I created a static method in a seperate Class that change values of Arcs and then call it on the firebase's onDataChange method. The problem that the arcs shows wrong values and I think that is caused by a concurrent access to that class.
I tried to add synchronized but that doesn't solve the problem.
This is the class that contains the method
public class ArcProgSettings {
private static int diff=0;
private static int i;
private static CountDownTimer waitTimer;
private int previousTemp=0;
private int newT=0;
private ArcProgress arcTemp;
public ArcProgSettings(){
}
public ArcProgSettings(int previousTemp, int newT, final ArcProgress
arcTemp){
this.previousTemp=previousTemp;
this.newT=newT;
this.arcTemp=arcTemp;
}
public synchronized void setProg() {
diff = newT - previousTemp;
i = previousTemp;
if (diff >= 0) {
waitTimer = new CountDownTimer((diff + 2) * 100, 100) {
public void onTick(long millisUntilFinished) {
//called every 300 milliseconds, which could be used to
//send messages or some other action
arcTemp.setProgress(i);
i++;
}
public void onFinish() {
//After 60000 milliseconds (60 sec) finish current
//if you would like to execute something when time
finishes
}
}.start();
} else {
waitTimer = new CountDownTimer(-(diff - 2) * 100, 100) {
public void onTick(long millisUntilFinished) {
arcTemp.setProgress(i);
i--;
}
public void onFinish() {
}
}.start();
}
}
}
and this is the Activity that contains the calls:(setProg)
public class VisualisationActivity extends AppCompatActivity {
private ArcProgress arcTemp;
private DatabaseReference mTempDatabase;
private String MyTemp="0";
int previousTemp=0;
private ArcProgress arcCurrent;
private DatabaseReference mCurrentDatabase;
private String MyCurrent="0";
int previousCurrent=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_visualisation);
arcTemp=(ArcProgress)findViewById(R.id.arc_prog_temp);
mTempDatabase =
FirebaseDatabase.getInstance().getReference().child("temp");
mTempDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
MyTemp =(dataSnapshot.child("value").getValue().toString());
final int newT= Integer.parseInt(MyTemp);
ArcProgSettings arc=new ArcProgSettings(previousTemp,
newT,arcTemp);
arc.setProg();
previousTemp=newT;
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
arcCurrent=(ArcProgress)findViewById(R.id.arc_progress_current);
mCurrentDatabase =
FirebaseDatabase.getInstance().getReference().child("current");
mCurrentDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
MyCurrent =(dataSnapshot.child("value").getValue().toString());
final int newC= Integer.parseInt(MyCurrent);
ArcProgSettings arc1=new ArcProgSettings(previousCurrent,
newC,arcCurrent);
arc1.setProg();
previousCurrent=newC;
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
If you need separate timers and progress for each listener, why to use static variables? (waitTimer, diff, i). The problem is that both instances of ArcProgress are updating the same values, its not concurrency, is design. Change your variables to make it private only and you'll se a different result.

Categories