【问题标题】:Firebase Session Management: Issues with instatiating Global UserFirebase 会话管理:设置全局用户的问题
【发布时间】:2018-12-29 14:21:02
【问题描述】:

我是一名 Android Studio 编码初学者,目前正在构建一个营养应用程序来进行编程练习。我使用 Firebase 进行身份验证并作为数据库来保存用户数据。

工作原理:

我的应用内置了一项调查,询问身体细节和口味(年龄、身高、喜欢/不喜欢的成分等)。我有一个具有公共静态属性的 GlobalUser 类,可以将答案保存在应用程序中。当用户注册时,他被直接发送到调查活动。他在那里回答了问题,并将结果写入他的 UID 下的 Firebase 数据库(我使用具有与 GlobalUser 相同属性的 User 类来创建实例并使用 Firebase 的 setValue(Object) 方法)。如果他登录(或仍然登录),LoginRegistrationActivity 直接将他发送到 MainActivity。在那里,GlobalUser 类使用保存在其 UID 下的数据进行实例化。从 MainActivity,他可以导航到 ProfileActivity,在该 ProfileActivity 中,UI 会根据他的数据进行更新。这工作得很好。完成调查后,我可以在包含用户 UID 的子节点中找到结果,UI 得到正确更新,并且登录/注册过程按预期工作。

出了什么问题:

但是,当我在尝试不同的设计并不断重新启动应用程序时,它开始偶尔崩溃。经过一些测试,它表明 GlobalUser 类没有更新,因此 ArrayLists 为 null 并在我对它们使用 .size() 时导致 NullPointerExceptions。由于这个问题很少发生并且似乎与多次重新启动应用程序有关,我认为它与 Activity 生命周期有关,所以我还在 onStart 和 onResume 中更新了 GlobalUser 但它没有帮助。我还尝试在设置 ArrayLists 之前直接在 ProfileActivity 中再次更新 GlobalUser,但它没有用。我仍然猜想它与生命周期有关,但我不知道应该从哪里开始。以下是相关类/活动的代码:

登录注册活动:

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();
                        }
                    }
                });
            }
        });
    }
}

主活动:

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();
            }
        });
    }
}

全球用户:

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);
    }
}

用户:

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;

        }
    }
}

感谢您的帮助!

【问题讨论】:

  • 嗨安德烈。欢迎在 Stack Overflow 上发帖!请尝试发布重现特定问题所需的最少代码。这里有一些很好的指导方针。 How to create a Minimal, Complete, and Verifiable example。干杯!
  • 感谢 Elletlar,下次我会尽量把它发布得更紧凑。但是,您知道可能是什么原因吗?我尝试在 onStart、onResume、onRestart 和 onCreate 方法中实例化属性,但没有成功。有时您只需要关闭应用程序一次,当您重新启动它时,尝试打开 ProfileActivity 时会出现错误。似乎将 GlobalUser 的属性设置为 Datasnapshot 的代码不会被执行。还有其他生命周期部分可以帮助我吗?
  • 没问题。如果您发布大量这样的代码,则很难隔离问题,因此人们会转移到他们更容易理解的其他帖子上。我将创建一个重现问题的活动,并将相关代码放在此处的新帖子中。还将具有该活动的最小项目上传到 Github 或 Googledrive。通常不需要提供指向正在运行的项目的链接,但我认为如果有人可以实际运行代码,您可能更有机会获得此问题的答案。
  • 我自己刚刚发现了这个错误(不得不承认我现在为自己感到非常自豪:D)但感谢您的建议!下次一定会追的。
  • Np。很高兴它正在工作:) :) :)

标签: java android firebase session authentication


【解决方案1】:

我刚刚发现了错误。它与活动生命周期无关,它只是间接地与重新启动应用程序有关。问题是 Firebase 的值事件侦听器仍然是 AsyncTasks。当我启动应用程序并立即打开 ProfileActivity 时,在 Firebase AsyncTask 可以从数据库中获取数据之前创建了 Activity。因此 ProfileActivity 会在 ArrayLists 被实例化之前调用 .size() 方法。本质上,错误发生在您在 UI 中单击过快并且比异步数据获取任务更快时。

因此,我将会话管理移至 LoginRegistrationActivity,如下所示:

     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) {

            }
        });

    }

通过将 LoginRegistrationActivity.this.startActivity(i) 移动到 onDataChange 方法,我确保 GlobalUser 变量在 MainActivity 启动之前被实例化。可能还有更优雅的方法可以做到这一点。

【讨论】:

    猜你喜欢
    • 2011-12-23
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 2015-08-21
    • 2015-06-14
    • 1970-01-01
    相关资源
    最近更新 更多