Android Studio: как правильно войти в Firebase, используя фрагменты - PullRequest
0 голосов
/ 10 февраля 2019

Я искал несколько вопросов StackOverflow, таких как:

Сбой приложения Android при отображении записей базы данных Firebase

Необходимо ли добавлять AuthStateListener в каждыйактивность Android Firebase?

Приложение завершает работу с java.lang.NullPointerException

FirebaseAuth.getCurrentUser () возвращает нулевое значение

android- java.lang.NullPointerException с использованием getCurrentUser firebase auth

сбой приложения во время первого запуска при использовании FirebaseAuthentication

Что такое NullPointerException и как его исправить?

И, наконец, самый близкий вопрос, касающийся проблемы, с которой я сталкиваюсь:

Получение ссылки на нулевой объект наgetCurrentUser (). getUid () для фрагмента

Я еще не нашел ответа.В последней ссылке член StackOverflow объяснил, что NullPointerException происходит потому, что приложение почему-то игнорирует перенаправление с MainActivity на LoginActivity в случае getCurrentUser().getUid() == null и выполняет ChatFragment, где NullPointerException происходит.

У моего приложения вначале была такая проблема на Эмуляторе, но как-то на Эмуляторе все работает нормально.

Но теперь я попытался установить приложение вмое физическое устройство и приложение не работают.Я получаю NullPointerException , потому что пользователь еще не вошел в систему.

Мое приложение похоже на WhatsApp ChatApp.Он имеет скользящий TabLayout с двумя фрагментами.Мое приложение запускает MainActivity, которое должно перенаправить AppUser в LoginActivity в случае первого использования приложения.

Вот моя MainActivity

public class MainPageActivity extends AppCompatActivity implements GroupListAdapter.DataChangeListener {

    public static final int PERMISSIONS_MULTIPLE_REQUEST = 123;

    private Toolbar mToolBar;
    private ViewPager mViewPager;
    private TabLayout mTabLayout;

    private TabsAccessAdapter mTabsAcessAdapter;

    private FirebaseAuth mAuth;
    private DatabaseReference RootRef;

    private String currentUserID;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_page);

        FirebaseApp.initializeApp(this);

        mAuth = FirebaseAuth.getInstance();
        RootRef = FirebaseDatabase.getInstance().getReference();

        mToolBar = (Toolbar) findViewById(R.id.main_page_toolbar);
        setSupportActionBar(mToolBar);
        getSupportActionBar().setTitle("MyApp");

        mViewPager = (ViewPager) findViewById(R.id.tabs_pager);
        mTabsAcessAdapter = new TabsAccessAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(mTabsAcessAdapter);

        mTabLayout = (TabLayout) findViewById(R.id.tablayout);
        mTabLayout.setupWithViewPager(mViewPager);

        getPermissions();

    }


    private void getPermissions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(new String[]{Manifest.permission.WRITE_CONTACTS,Manifest.permission.READ_CONTACTS,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE},PERMISSIONS_MULTIPLE_REQUEST);
        }
    }

    @Override
    protected void onStart() {
        super.onStart();

        Log.i("debinf mainpage", "onStart");

        FirebaseAuth.getInstance().addAuthStateListener(new FirebaseAuth.AuthStateListener() {
            @Override
            public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {

                FirebaseUser currentUser = firebaseAuth.getCurrentUser();

                if (currentUser == null) {
                    //Here is the place to redirect the AppUser to LoginActivity
                    sendUserToLoginActivity();
                }else {

                    VerifyUserExistance();
                }

            }
        });
    }

    private void VerifyUserExistance() {
        String currentUserID = mAuth.getCurrentUser().getUid();

        RootRef.child("user").child(currentUserID).addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                Toast.makeText(MainPageActivity.this, "Bem vindo(a)!", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }


    // Dealing with MENU > starts here
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        getMenuInflater().inflate(R.menu.options_menu,menu);

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        super.onOptionsItemSelected(item);

        if (item.getItemId() == R.id.main_logout_option) {


            mAuth.signOut();
            sendUserToLoginActivity();
        }
        if (item.getItemId() == R.id.main_settings_option) {
            //sendUserToSettingsActivity();
            Toast.makeText(this, "Settings from MainAct", Toast.LENGTH_SHORT).show();
        }

        return false;
    }

    private void sendUserToLoginActivity() {
        Intent loginIntent = new Intent(MainPageActivity.this,LoginActivity.class);
        loginIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        startActivity(loginIntent);

    }


    @Override
    public void onDataSetChanged(String groupKeyFromSender, boolean addToCall) {
        String tag = "android:switcher:" + R.id.tabs_pager + ":" + 1;
        CallFragment rf = (CallFragment) getSupportFragmentManager().findFragmentByTag(tag);
        rf.getDataFromGroupFragment(groupKeyFromSender, addToCall);
    }
}

Вот моя LoginActivity, которая должна вызываться MainActivityв первом использовании, но это не так.

public class LoginActivity extends AppCompatActivity {

    private EditText mPhoneNumber, mCode;
    private Button mSend;

    private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks;

    String mVerificationId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        FirebaseApp.initializeApp(this);

        userIsLoggedIn();

        mPhoneNumber = findViewById(R.id.phoneNumber);
        mCode = findViewById(R.id.code);

        mSend = findViewById(R.id.send);
        mSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mVerificationId != null) {
                    verifyPhoneNumberWithCode();
                } else {
                    startPhoneNumberVerification();
                }

            }
        });

        mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
            @Override
            public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
                sighInWithPhoneAuthCredential(phoneAuthCredential);
            }

            @Override
            public void onVerificationFailed(FirebaseException e) {

            }

            @Override
            public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken forceResendingToken) {
                super.onCodeSent(verificationId, forceResendingToken);

                mVerificationId = verificationId;
                mSend.setText("Enviar codigo");
            }
        };
    }

    private void verifyPhoneNumberWithCode(){
        PhoneAuthCredential credential = PhoneAuthProvider.getCredential(mVerificationId, mCode.getText().toString());
        sighInWithPhoneAuthCredential(credential);
    }

    private void sighInWithPhoneAuthCredential(PhoneAuthCredential phoneAuthCredential) {
        FirebaseAuth.getInstance().signInWithCredential(phoneAuthCredential).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    //userIsLoggedIn();
                    final FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();

                    // I think add child named user and inside other child named userId = user.getUid()
                    if (user != null) {
                        // Do not forget to add database implementation in the gradle (module app)
                        final DatabaseReference mUserDB = FirebaseDatabase.getInstance().getReference().child("user").child(user.getUid());
                        mUserDB.addListenerForSingleValueEvent(new ValueEventListener() {
                            @Override
                            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                                if (!dataSnapshot.exists()) {
                                    // if user has never loged in, add a new user
                                    Map<String, Object> userMap = new HashMap<>();
                                    userMap.put("phone", user.getPhoneNumber());
                                    //userMap.put("name", user.getPhoneNumber());
                                    userMap.put("name", "babaloo");
                                    mUserDB.updateChildren(userMap);
                                }
                                userIsLoggedIn();
                            }

                            @Override
                            public void onCancelled(@NonNull DatabaseError databaseError) {

                            }
                        });
                    }
                }
            }
        });
    }

    private void userIsLoggedIn() {

        FirebaseAuth.getInstance().addAuthStateListener(new FirebaseAuth.AuthStateListener() {
            @Override
            public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {

                FirebaseUser user = firebaseAuth.getCurrentUser();

                if (user != null) {
                    startActivity(new Intent(getApplicationContext(), MainPageActivity.class));
                    finish();
                    return;
                }
            }
        });


    }

    private void startPhoneNumberVerification() {
        PhoneAuthProvider.getInstance().verifyPhoneNumber(
                mPhoneNumber.getText().toString(),60,
                TimeUnit.SECONDS, this, mCallbacks);
    }
}

А вот onCreateView GroupFragment, где происходит NullPointerException .

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.group_fragment, container, false);

    groupTablePath = getContext().getFilesDir().getPath()+"/GroupDataBase/";
    rootPath = Environment.getExternalStorageDirectory() + "/";

    mAuth = FirebaseAuth.getInstance();
    currentUser = mAuth.getCurrentUser().getUid();

    GroupRef = FirebaseDatabase.getInstance().getReference().child("Group");
    UserRef = FirebaseDatabase.getInstance().getReference().child("user");

    StoreRef = FirebaseStorage.getInstance().getReference();

    FloatingActionButton findUser = (FloatingActionButton) view.findViewById(R.id.addContact);
    findUser.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            startActivity(new Intent(view.getContext(), FindUserActivity.class));

        }
    });

    //getPermissions();


    CreateRootFolder();
    initializeRecyclerView();
    loadGroupListDatabase();
    populateTeamTableInternet();
    OwnerGroupUploadClientListTable();
    updateClientListInternet();


    // Inflate the layout for this fragment
    return view;
}

Эта частьошибки

at com.example.aliton.myapp.Fragments.GroupFragment.onCreateView(GroupFragment.java:107)

соответствует этой строке кода в onCreateView GroupFragment:

currentUser = mAuth.getCurrentUser().getUid();

А вот ФАТАЛЬНАЯ ошибка:

02-09 20:24:10.950 24837-24837/com.example.aliton.myapp E/AndroidRuntime: FATAL EXCEPTION: main
    java.lang.NullPointerException
        at com.example.aliton.myapp.Fragments.GroupFragment.onCreateView(GroupFragment.java:107)
        at android.support.v4.app.Fragment.performCreateView(Fragment.java:2439)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
        at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
        at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:802)
        at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
        at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
        at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
        at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:2243)
        at android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:654)
        at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:146)
        at android.support.v4.view.ViewPager.populate(ViewPager.java:1244)
        at android.support.v4.view.ViewPager.populate(ViewPager.java:1092)
        at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1622)
        at android.view.View.measure(View.java:15294)
        at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:665)
        at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:447)
        at android.view.View.measure(View.java:15294)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4818)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
        at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143)
        at android.view.View.measure(View.java:15294)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4818)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1421)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:712)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:605)
        at android.view.View.measure(View.java:15294)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4818)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
        at android.view.View.measure(View.java:15294)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4818)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1421)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:712)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:605)
        at android.view.View.measure(View.java:15294)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4818)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2432)
        at android.view.View.measure(View.java:15294)
        at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1872)
        at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1115)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1296)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1013)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4245)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
        at android.view.Choreographer.doCallbacks(Choreographer.java:555)
        at android.view.Choreographer.doFrame(Choreographer.java:525)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
        at android.os.Handler.handleCallback(Handler.java:615)
        at android.os.Handler.dispatchMessage(Handler.java:92)
        at android.os.Looper.loop(Looper.java:153)
        at android.app.ActivityThread.main(ActivityThread.java:5076)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
        at com.

Я ценю любую помощь.

Ответы [ 2 ]

0 голосов
/ 15 мая 2019

Здесь есть 3 проблемы

  1. Слушатель аутентификации является асинхронным, поэтому создание условий гонки с помощью адаптера фрагментов
  2. Вы подключаете слушателя аутентификации на onStart после того, как onCreate к этому моментуфрагмент уже прикреплен
  3. Вы делаете основной логический экран точкой входа, если пользователь не зарегистрирован, то он возвращается к входу в систему.Это должно быть задом наперед, вы должны сделать так, чтобы вход в систему позволял пользователю переходить к следующему действию.

Для исправления 1 и 2 вам придется реорганизовать ваш код.

Дляисправляя номер 3, вы должны установить логин как действие по умолчанию в манифесте.

Для исправления того, что у вас есть сейчас, добавьте это в метод onCreate основного

FirebaseApp.initializeApp(this);

        mAuth = FirebaseAuth.getInstance();
        RootRef = FirebaseDatabase.getInstance().getReference();
if (mAuth.getCurrentUser() == null) return;

Возврат в этой точке будетзаставить код перейти к onStary, где у вас есть слушатель аутентификации, заставляющий вашу логику работать

0 голосов
/ 10 февраля 2019

Если mAuth.getCurrentUser() возвращает null, это означает, что пользователь еще не вошел в систему, или, точнее: клиент Firebase еще не проверил, что пользователь уже вошел в систему.Проверка происходит асинхронно, и, возможно, ваш mAuth.getCurrentUser() запускается до его завершения.

Решение этой проблемы всегда одно и то же: используйте AuthStateListener, как вы делаете в упражнении.

Так что-то вроде этого:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.group_fragment, container, false);

    groupTablePath = getContext().getFilesDir().getPath()+"/GroupDataBase/";
    rootPath = Environment.getExternalStorageDirectory() + "/";

    mAuth = FirebaseAuth.getInstance();
    FirebaseAuth.getInstance().addAuthStateListener(new FirebaseAuth.AuthStateListener() {
        @Override
        public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {


            if (firebaseAuth.getCurrentUser() != null) {
                currentUser = mAuth.getCurrentUser().getUid();

                // TODO: any code that needs the UID should be in here

            }
        }

onAuthStateChanged выполняется всякий раз, когда изменяется состояние аутентификации пользователя.Таким образом, в этом случае также, как только клиент проверил состояние аутентификации.И с этого момента вы можете безопасно получить UID пользователя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...