发送消息时使用Firebase的Android聊天应用程序崩溃

时间:2019-06-17 05:14:57

标签: java android firebase firebase-realtime-database

你好,我在学习在线课程时正在创建一个Android聊天应用程序。该课程的作者在2-3年前创建了它,似乎代码的某些部分已过时并引起问题。

我的问题是,当我注册new user,然后使用该帐户登录时,一切正常。但是,当我重新启动application并使用另一个帐户(not the account just created)登录并发送消息时,Firebase仅存储了消息,但没有存储用户帐户,然后application崩溃了。之后,当我尝试与任何用户登录并进入主要的聊天活动时,该应用将崩溃,因为Fire-base中有一条消息没有用户。

enter image description here 我花了几个小时尝试google并进行修复,但仍然不知道如何。谢谢您的时间和帮助。

这是我的一些代码,我的应用程序包含3个活动:LoginActivity,RegisterActivity和MainChatActivity。

LoginActivity

public class LoginActivity extends AppCompatActivity {

    // TODO: Add member variables here:
    private FirebaseAuth mAuth;
    // UI references.
    private AutoCompleteTextView mEmailView;
    private EditText mPasswordView;

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

        mEmailView = (AutoCompleteTextView) findViewById(R.id.login_email);
        mPasswordView = (EditText) findViewById(R.id.login_password);

        mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
                if (id == R.integer.login || id == EditorInfo.IME_NULL) {
                    attemptLogin();
                    return true;
                }
                return false;
            }
        });

        // TODO: Grab an instance of FirebaseAuth
        mAuth = FirebaseAuth.getInstance();

    }

    // Executed when Sign in button pressed
    public void signInExistingUser(View v)   {
        // TODO: Call attemptLogin() here
        attemptLogin();

    }

    // Executed when Register button pressed
    public void registerNewUser(View v) {
        Intent intent = new Intent(this, com.example.simple_messenger.RegisterActivity.class);
        finish();
        startActivity(intent);
    }

    // TODO: Complete the attemptLogin() method
    private void attemptLogin() {

        String email = mEmailView.getText().toString();
        String password = mPasswordView.getText().toString();

        if (email.isEmpty())
            if (email.equals("") || password.equals("")) return;
        Toast.makeText(this, "Login in progress...", Toast.LENGTH_SHORT).show();

        // TODO: Use FirebaseAuth to sign in with email & password
        mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {

                Log.d("Simple Messenger", "signInWithEmail() onComplete: " + task.isSuccessful());

                if (!task.isSuccessful()) {
                    Log.d("Simple Messenger", "Problem signing in: " + task.getException());
                    showErrorDialog("There was a problem signing in");
                } else {
                    Intent intent = new Intent(LoginActivity.this, MainChatActivity.class);
                    finish();
                    startActivity(intent);
                }

            }
        });


    }

    // TODO: Show error on screen with an alert dialog
    private void showErrorDialog(String message) {

        new AlertDialog.Builder(this)
                .setTitle("Oops")
                .setMessage(message)
                .setPositiveButton(android.R.string.ok, null)
                .setIcon(android.R.drawable.ic_dialog_alert)
                .show();
    }


注册活动

public class RegisterActivity extends AppCompatActivity {

    // Constants
    static final String CHAT_PREFS = "ChatPrefs";
    static final String DISPLAY_NAME_KEY = "username";

    // TODO: Add member variables here:
    // UI references.
    private AutoCompleteTextView mEmailView;
    private AutoCompleteTextView mUsernameView;
    private EditText mPasswordView;
    private EditText mConfirmPasswordView;

    // Firebase instance variables
    private FirebaseAuth mAuth;


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

        mEmailView = (AutoCompleteTextView) findViewById(R.id.register_email);
        mPasswordView = (EditText) findViewById(R.id.register_password);
        mConfirmPasswordView = (EditText) findViewById(R.id.register_confirm_password);
        mUsernameView = (AutoCompleteTextView) findViewById(R.id.register_username);

        // Keyboard sign in action
        mConfirmPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
                if (id == R.integer.register_form_finished || id == EditorInfo.IME_NULL) {
                    attemptRegistration();
                    return true;
                }
                return false;
            }
        });

        // TODO: Get hold of an instance of FirebaseAuth
        mAuth = FirebaseAuth.getInstance();


    }

    // Executed when Sign Up button is pressed.
    public void signUp(View v) {
        attemptRegistration();
    }

    private void attemptRegistration() {

        // Reset errors displayed in the form.
        mEmailView.setError(null);
        mPasswordView.setError(null);

        // Store values at the time of the login attempt.
        String email = mEmailView.getText().toString();
        String password = mPasswordView.getText().toString();

        boolean cancel = false;
        View focusView = null;

        // Check for a valid password, if the user entered one.
        if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
            mPasswordView.setError(getString(R.string.error_invalid_password));
            focusView = mPasswordView;
            cancel = true;
        }

        // Check for a valid email address.
        if (TextUtils.isEmpty(email)) {
            mEmailView.setError(getString(R.string.error_field_required));
            focusView = mEmailView;
            cancel = true;
        } else if (!isEmailValid(email)) {
            mEmailView.setError(getString(R.string.error_invalid_email));
            focusView = mEmailView;
            cancel = true;
        }

        if (cancel) {
            // There was an error; don't attempt login and focus the first
            // form field with an error.
            focusView.requestFocus();
        } else {
            // TODO: Call create FirebaseUser() here
            createFirebaseUser();

        }
    }

    private boolean isEmailValid(String email) {
        // You can add more checking logic here.
        return email.contains("@");
    }

    private boolean isPasswordValid(String password) {
        //TODO: Add own logic to check for a valid password
        String confirmPassword = mConfirmPasswordView.getText().toString();
        return confirmPassword.equals(password) && password.length() > 4;
    }

    // TODO: Create a Firebase user
    private void createFirebaseUser() {

        String email = mEmailView.getText().toString();
        String password = mPasswordView.getText().toString();



        mAuth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(this,
                new OnCompleteListener<AuthResult>() {

                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        Log.d("FlashChat", "createUser onComplete: " + task.isSuccessful());

                        if(!task.isSuccessful()){
                            Log.d("FlashChat", "user creation failed");
                            showErrorDialog("Registration attempt failed");
                        } else {
                            saveDisplayName();
                            Intent intent = new Intent(RegisterActivity.this, LoginActivity.class);
                            finish();
                            startActivity(intent);
                        }
                    }
                });
    }


    // TODO: Save the display name to Shared Preferences
    private void saveDisplayName() {

        FirebaseUser user = mAuth.getCurrentUser();
        String displayName = mUsernameView.getText().toString();

        if (user !=null) {
            UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
                    .setDisplayName(displayName)
                    .build();

            user.updateProfile(profileUpdates)
                    .addOnCompleteListener(new OnCompleteListener<Void>() {
                        @Override
                        public void onComplete(@NonNull Task<Void> task) {
                            if (task.isSuccessful()) {
                                Log.d("SimpleMessenger", "User name updated.");
                            }
                        }
                    });

        }

    }


    // TODO: Create an alert dialog to show in case registration failed
    private void showErrorDialog(String message){

        new AlertDialog.Builder(this)
                .setTitle("Oops")
                .setMessage(message)
                .setPositiveButton(android.R.string.ok, null)
                .setIcon(android.R.drawable.ic_dialog_alert)
                .show();

    }




}

MainChatActivity

public class MainChatActivity extends AppCompatActivity {

    // TODO: Add member variables here:
    private String mDisplayName;
    private ListView mChatListView;
    private EditText mInputText;
    private ImageButton mSendButton;
    private DatabaseReference mDatabaseReference;
    private ChatListAdapter mAdapter;

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

        // TODO: Set up the display name and get the Firebase reference
        setupDisplayName();
        mDatabaseReference = FirebaseDatabase.getInstance().getReference();


        // Link the Views in the layout to the Java code
        mInputText = (EditText) findViewById(R.id.messageInput);
        mSendButton = (ImageButton) findViewById(R.id.sendButton);
        mChatListView = (ListView) findViewById(R.id.chat_list_view);

        // TODO: Send the message when the "enter" button is pressed
        mInputText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {

                sendMessage();
                return true;
            }
        });

        // TODO: Add an OnClickListener to the sendButton to send a message
        mSendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendMessage();
            }
        });

    }

    // TODO: Retrieve the display name from the Shared Preferences
    // TODO: Retrieve the display name from the Shared Preferences
    private void setupDisplayName(){
        FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
        mDisplayName = user.getDisplayName();
    }



    private void sendMessage() {

        Log.d("FlashChat", "I sent something");
        // TODO: Grab the text the user typed in and push the message to Firebase
        String input = mInputText.getText().toString();
        if (!input.equals("")) {
            InstantMessage chat = new InstantMessage(input, mDisplayName);
            mDatabaseReference.child("messages").push().setValue(chat);
            mInputText.setText("");
        }

    }

    // TODO: Override the onStart() lifecycle method. Setup the adapter here.
    @Override
    public void onStart() {
        super.onStart();
        mAdapter = new ChatListAdapter(this, mDatabaseReference, mDisplayName);
        mChatListView.setAdapter(mAdapter);
    }


    @Override
    public void onStop() {
        super.onStop();

        // TODO: Remove the Firebase event listener on the adapter.
        mAdapter.cleanup();

    }

}

此处的崩溃日志:

2019-06-17 12:22:08.370 17132-17158/com.example.simple_messenger W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
2019-06-17 12:22:08.371 17132-17158/com.example.simple_messenger I/FirebaseAuth: [FirebaseAuth:] Loading module via FirebaseOptions.
2019-06-17 12:22:08.371 17132-17158/com.example.simple_messenger I/FirebaseAuth: [FirebaseAuth:] Preparing to create service connection to gms implementation
2019-06-17 12:22:08.386 17132-17132/com.example.simple_messenger W/BiChannelGoogleApi: [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzak@8d8060e
2019-06-17 12:22:09.771 17132-17148/com.example.simple_messenger D/FirebaseAuth: Notifying id token listeners about user ( HJsRBb7DjyWEXgnYvsp614YAbG32 ).
2019-06-17 12:22:09.777 17132-17132/com.example.simple_messenger D/FlashChat: signInWithEmail() onComplete: true
2019-06-17 12:22:09.817 17132-17132/com.example.simple_messenger W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@659ce27
2019-06-17 12:22:09.921 17132-17148/com.example.simple_messenger D/DecorView: onWindowFocusChangedFromViewRoot hasFocus: true, DecorView@8a0c21b[MainChatActivity]
2019-06-17 12:22:09.960 17132-18551/com.example.simple_messenger D/NetworkSecurityConfig: No Network Security Config specified, using platform default
2019-06-17 12:22:10.526 17132-17148/com.example.simple_messenger D/FirebaseAuth: Notifying id token listeners about user ( HJsRBb7DjyWEXgnYvsp614YAbG32 ).
2019-06-17 12:22:11.705 17132-17132/com.example.simple_messenger D/AndroidRuntime: Shutting down VM
2019-06-17 12:22:11.707 17132-17132/com.example.simple_messenger E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.simple_messenger, PID: 17132
    java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
        at com.example.simple_messenger.ChatListAdapter.getView(ChatListAdapter.java:111)
        at android.widget.AbsListView.obtainView(AbsListView.java:2408)
        at android.widget.ListView.measureHeightOfChildren(ListView.java:1482)
        at android.widget.ListView.onMeasure(ListView.java:1389)
        at android.view.View.measure(View.java:23355)
        at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715)
        at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461)
        at android.view.View.measure(View.java:23355)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6758)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
        at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143)
        at android.view.View.measure(View.java:23355)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6758)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1535)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:825)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:704)
        at android.view.View.measure(View.java:23355)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6758)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
        at android.view.View.measure(View.java:23355)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6758)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1535)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:825)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:704)
        at android.view.View.measure(View.java:23355)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6758)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
        at com.android.internal.policy.DecorView.onMeasure(DecorView.java:717)
        at android.view.View.measure(View.java:23355)
        at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2915)
        at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1745)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2038)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1633)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7786)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1004)
        at android.view.Choreographer.doCallbacks(Choreographer.java:816)
        at android.view.Choreographer.doFrame(Choreographer.java:751)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:990)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6863)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2019-06-17 12:22:11.835 17132-18559/com.example.simple_messenger D/OSTracker: OS Event: crash
2019-06-17 12:22:11.860 17132-18559/com.example.simple_messenger D/AbstractTracker: Event success
2019-06-17 12:22:11.863 17132-17132/com.example.simple_messenger I/Process: Sending signal. PID: 17132 SIG: 9

ChatListAdapter

public class ChatListAdapter extends BaseAdapter {

    private Activity mActivity;
    private DatabaseReference mDatabaseReference;
    private String mDisplayName;
    private ArrayList<DataSnapshot> mSnapshotList;

    private ChildEventListener mListener = new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {

            mSnapshotList.add(dataSnapshot);
            notifyDataSetChanged();

        }

        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) {

        }

        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) {

        }

        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String s) {

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    };

    public ChatListAdapter(Activity activity, DatabaseReference ref, String name) {

        mActivity = activity;
        mDisplayName = name;
        // common error: typo in the db location. Needs to match what's in MainChatActivity.
        mDatabaseReference = ref.child("messages");
        mDatabaseReference.addChildEventListener(mListener);

        mSnapshotList = new ArrayList<>();
    }

    private static class ViewHolder{
        TextView authorName;
        TextView body;
        LinearLayout.LayoutParams params;
    }

    @Override
    public int getCount() {
        return mSnapshotList.size();
    }

    @Override
    public InstantMessage getItem(int position) {

        DataSnapshot snapshot = mSnapshotList.get(position);
        return snapshot.getValue(InstantMessage.class);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.chat_msg_row, parent, false);

            final ViewHolder holder = new ViewHolder();
            holder.authorName = (TextView) convertView.findViewById(R.id.author);
            holder.body = (TextView) convertView.findViewById(R.id.message);
            holder.params = (LinearLayout.LayoutParams) holder.authorName.getLayoutParams();
            convertView.setTag(holder);

        }

        final InstantMessage message = getItem(position);
        final ViewHolder holder = (ViewHolder) convertView.getTag();

        boolean isMe = message.getAuthor().equals(mDisplayName);
        setChatRowAppearance(isMe, holder);

        String author = message.getAuthor();
        holder.authorName.setText(author);

        String msg = message.getMessage();
        holder.body.setText(msg);


        return convertView;
    }

    private void setChatRowAppearance(boolean isItMe, ViewHolder holder) {

        if (isItMe) {


            holder.params.gravity = Gravity.END;
            holder.authorName.setTextColor(Color.GREEN);

            // If you want to use colours from colors.xml
            // int colourAsARGB = ContextCompat.getColor(mActivity.getApplicationContext(), R.color.yellow);
            // holder.authorName.setTextColor(colourAsARGB);

            holder.body.setBackgroundResource(R.drawable.bubble2);
        } else {
            holder.params.gravity = Gravity.START;
            holder.authorName.setTextColor(Color.BLUE);
            holder.body.setBackgroundResource(R.drawable.bubble1);
        }

        holder.authorName.setLayoutParams(holder.params);
        holder.body.setLayoutParams(holder.params);

    }


    void cleanup() {

        mDatabaseReference.removeEventListener(mListener);
    }


}

当我按照布尔值(DHAVAL)的建议编辑布尔值时,消息已发送但没有作者的名字enter image description here

0 个答案:

没有答案