你好,我在学习在线课程时正在创建一个Android聊天应用程序。该课程的作者在2-3年前创建了它,似乎代码的某些部分已过时并引起问题。
我的问题是,当我注册new user
,然后使用该帐户登录时,一切正常。但是,当我重新启动application
并使用另一个帐户(not the account just created)
登录并发送消息时,Firebase仅存储了消息,但没有存储用户帐户,然后application
崩溃了。之后,当我尝试与任何用户登录并进入主要的聊天活动时,该应用将崩溃,因为Fire-base
中有一条消息没有用户。
我花了几个小时尝试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)的建议编辑布尔值时,消息已发送但没有作者的名字