Я создаю приложение на основе Stitch Mongodb с методом аутентификации по электронной почте / паролю. Мне удалось зарегистрировать пользователя и отправить электронное письмо с подтверждением. После регистрации и отправки электронного письма я перенаправляю пользователя на страницу входа напрямую. Затем я перехожу на свою электронную почту и подтверждаю учетную запись и возвращаюсь в приложение для входа в систему, но каждый раз, когда я делаю это, он не входит напрямую, это дает мне исключение одновременной модификации. Это проблема, которую я могу решить, или пользователь должен немного подождать, прежде чем войти в систему?
Ошибка выглядит следующим образом:
2020-04-06 19:13:17.631 7255-7255/com.example.goonernews E/Error Logging in:: java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at com.mongodb.stitch.android.core.internal.StitchAppClientImpl.onRebindEvent(StitchAppClientImpl.java:313)
at com.mongodb.stitch.android.core.internal.StitchAppClientImpl.onUserLoggedIn(StitchAppClientImpl.java:332)
at com.mongodb.stitch.android.core.auth.internal.StitchAuthImpl.onUserLoggedIn(StitchAuthImpl.java:326)
at com.mongodb.stitch.android.core.auth.internal.StitchAuthImpl.onUserLoggedIn(StitchAuthImpl.java:48)
at com.mongodb.stitch.core.auth.internal.CoreStitchAuth.doLogin(CoreStitchAuth.java:640)
at com.mongodb.stitch.core.auth.internal.CoreStitchAuth.loginWithCredentialInternal(CoreStitchAuth.java:382)
at com.mongodb.stitch.android.core.auth.internal.StitchAuthImpl.access$000(StitchAuthImpl.java:48)
at com.mongodb.stitch.android.core.auth.internal.StitchAuthImpl$1.call(StitchAuthImpl.java:105)
at com.mongodb.stitch.android.core.auth.internal.StitchAuthImpl$1.call(StitchAuthImpl.java:102)
at com.mongodb.stitch.core.internal.common.ThreadDispatcher$1.run(ThreadDispatcher.java:57)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:459)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Страница входа выглядит следующим образом:
package com.example.goonernews;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.BounceInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.mongodb.stitch.android.core.Stitch;
import com.mongodb.stitch.android.core.StitchAppClient;
import com.mongodb.stitch.android.core.auth.StitchUser;
import com.mongodb.stitch.android.core.auth.providers.userpassword.UserPasswordAuthProviderClient;
import com.mongodb.stitch.android.services.mongodb.remote.RemoteMongoClient;
import com.mongodb.stitch.android.services.mongodb.remote.RemoteMongoCollection;
import com.mongodb.stitch.core.auth.providers.userpassword.UserPasswordCredential;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteInsertOneResult;
import org.bson.Document;
public class LoginPage extends AppCompatActivity {
TextView SignUpMessage;
ImageView BouncingLogo;
EditText Username;
EditText Password;
Button Login;
private StitchUser currentUser;
public static StitchAppClient client;
private RemoteMongoClient mongoClient;
private RemoteMongoCollection usersCollection;
@Override
protected void onStart() {
super.onStart();
if (ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 101);
}
if(client==null)
client = Stitch.initializeAppClient("goonernews-ocisk");
client = Stitch.getAppClient("goonernews-ocisk");
mongoClient = client.getServiceClient(RemoteMongoClient.factory, "mongodb-atlas");
usersCollection = mongoClient.getDatabase("ArsenalLebanon").getCollection("Users");
currentUser = client.getAuth().getUser();
if(currentUser != null){
startActivity(new Intent(LoginPage.this, Homepage.class));
finish();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login_page);
SignUpMessage = findViewById(R.id.SignUpMessage);
BouncingLogo = findViewById(R.id.bouncinglogo);
Username = findViewById(R.id.username);
Password = findViewById(R.id.password);
Login = findViewById(R.id.login_button);
String signupmessage = "Don't have an account? Sign Up";
SpannableString Ssignupmessage = new SpannableString(signupmessage);
ForegroundColorSpan fcsRed = new ForegroundColorSpan(Color.RED);
ForegroundColorSpan fcsBlack = new ForegroundColorSpan(Color.BLACK);
Ssignupmessage.setSpan(fcsRed,0,22, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ClickableSpan goToSignUp = new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
Intent RegisterActivity = new Intent(getApplicationContext(), RegistrationPage.class);
startActivity(RegisterActivity);
}
};
Ssignupmessage.setSpan(goToSignUp,23,30, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Ssignupmessage.setSpan(fcsBlack,23,30,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
SignUpMessage.setText(Ssignupmessage);
SignUpMessage.setMovementMethod(LinkMovementMethod.getInstance());
BouncingLogo.clearAnimation();
TranslateAnimation translateAnimation = new TranslateAnimation(0,0,0,getDisplayHeight()/10);
translateAnimation.setStartOffset(500);
translateAnimation.setDuration(3000);
translateAnimation.setFillAfter(true);
translateAnimation.setInterpolator(new BounceInterpolator());
translateAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
Log.i("Animation", "Starting button dropdown animation");
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
}
});
BouncingLogo.startAnimation(translateAnimation);
Login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String email = Username.getText().toString();
String password = Password.getText().toString();
boolean cancel = false;
View focusView = null;
if (TextUtils.isEmpty(email)) {
Username.setError("Please enter an Email Address!");
focusView = Username;
cancel = true;
} else if (!MiscFunc.isEmailValid(email)) {
Username.setError("Please enter a valid Email Address!");
focusView = Username;
cancel = true;
}
if (!TextUtils.isEmpty(password) && !MiscFunc.isPasswordValid(password)) {
Password.setError("Please enter a valid Password!");
focusView = Password;
cancel = true;
}
if (cancel) {
focusView.requestFocus();
}
else {
new getLoginTask().execute(email,password);
}
}
});
}
@SuppressLint("StaticFieldLeak")
private class getLoginTask extends AsyncTask<String, Void, Void> {
private byte statusCode;
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Void doInBackground(String... params) {
try {
Log.e("Email: ",params[0]);
Log.e("Password: ",params[1]);
UserPasswordCredential credential = new UserPasswordCredential(params[0], params[1]);
client.getAuth().loginWithCredential(credential).addOnCompleteListener(new OnCompleteListener<StitchUser>() {
@Override
public void onComplete(@NonNull final Task<StitchUser> task) {
if (task.isSuccessful()){
statusCode = 1;
onPostExecute();
}
else{
statusCode = 0;
Log.e("Error Logging in: ","",task.getException());
onPostExecute();
}
}
});
} catch (Exception e) {
Log.e("stitch-auth", "Authentication Failed!");
}
return null;
}
protected void onPostExecute() {
if (statusCode == 1) {
Log.d("stitch-auth", "Authentication Successful.");
StitchUser newAccount = client.getAuth().getUser();
try
{
String full_name = getIntent().getStringExtra("FullName");
String full_Birthday = getIntent().getStringExtra("Birthday");
if(newAccount!= null && full_name!= null && full_Birthday!= null) {
String id = newAccount.getId();
Document newUser = new Document()
.append("UserID", id)
.append("FullName", full_name)
.append("Birthday", full_Birthday);
final Task<RemoteInsertOneResult> insertTask = usersCollection.insertOne(newUser);
insertTask.addOnCompleteListener(new OnCompleteListener<RemoteInsertOneResult>() {
@Override
public void onComplete(@NonNull Task<RemoteInsertOneResult> task) {
if (task.isSuccessful()) {
Log.d("app", String.format("successfully inserted item with id %s",
task.getResult().getInsertedId()));
} else {
Log.e("app", "failed to insert document with: ", task.getException());
}
}
});
}
}
catch (Exception e)
{
Log.e("No name or birthday","");
}
startActivity(new Intent(LoginPage.this, Homepage.class));
finish();
} else {
Log.e("stitch-auth", "Authentication Failed.");
Toast.makeText(LoginPage.this, "Ugh...! Error in recognizing.", Toast.LENGTH_SHORT).show();
Password.setText("");
}
}
}
private int getDisplayHeight() {
return this.getResources().getDisplayMetrics().heightPixels;
}
private void changePassword() {
String email = Username.getText().toString();
UserPasswordAuthProviderClient emailPassClient = Stitch.getDefaultAppClient().getAuth().getProviderClient(UserPasswordAuthProviderClient.factory);
if (TextUtils.isEmpty(email)) {
Username.setError("Please enter your email!");
} else {
emailPassClient.sendResetPasswordEmail(email)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull final Task<Void> task) {
if (task.isSuccessful()) {
Log.d("stitch-auth", "Successfully sent password reset email");
Toast.makeText(LoginPage.this, "Password reset mail sent.", Toast.LENGTH_SHORT).show();
} else {
Log.e("stitch-auth", "Error sending password reset email:", task.getException());
Toast.makeText(LoginPage.this, "Account not found!", Toast.LENGTH_SHORT).show();
}
}
});
}
}
}