2017-01-25 4 views
4

Я пытаюсь реализовать AutoCompleteTextView, чтобы заполнить электронную почту пользователей в активности входа для лучшего UX.Android AutoCompleteTextView с электронной почтой не заполняется

Чтобы соответствовать спецификациям Google для чтения контактов, это приложение запрашивает разрешение у пользователя во время выполнения с использованием метода checkSelfPermission() и что многое из того, что я знаю, работает. Однако, когда пользователь вводит в свою электронную почту пользователя, раскрывающийся список должен показывать после ввода не менее двух символов, и это не происходит.

Ожидаемый результат:

enter image description here

Ниже моя реализация (попытка). Любая обратная связь с примером кода (исправления) будет с благодарностью оценена.

build.gradle:

... 
compileSdkVersion 25 
buildToolsVersion "25.0.2" 
... 

AndroidManifest.xml:

... 
<uses-permission android:name="android.permission.GET_ACCOUNTS" /> 
<uses-permission android:name="android.permission.READ_CONTACTS" /> 
<uses-permission android:name="android.permission.READ_PROFILE" /> 
... 

activity_login.xml:

... 
<android.support.design.widget.TextInputLayout 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content"> 

    <AutoCompleteTextView 
     android:id="@+id/email" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:hint="@string/email" 
     android:inputType="textEmailAddress" 
     android:maxLines="1" 
     android:textColor="@android:color/white" 
     /> 

</android.support.design.widget.TextInputLayout> 
... 

LoginActivity.java: (К сожалению для показа всего класса, но .... только в случае.)

package com.company.product.activity; 

import too.many.imports 

import com.company.product.R; 

import static android.Manifest.permission.READ_CONTACTS; 


public class LoginActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> { 

    // UI references. 
    private EditText inputPassword; 
    private AutoCompleteTextView inputEmail; 
    private FirebaseAuth auth; 
    private ProgressBar progressBar; 
    private Button btnSignup, btnLogin, btnReset; 

    /** 
    * Id to identity READ_CONTACTS permission request. 
    */ 
    private static final int REQUEST_READ_CONTACTS = 0; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 

     // Get Firebase auth instance 
     auth = FirebaseAuth.getInstance(); 

     if (auth.getCurrentUser() != null) { 
      startActivity(new Intent(LoginActivity.this, MainActivity.class)); 
      finish(); 
     } 

     // set the content view 
     setContentView(R.layout.activity_login); 

     Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 
     setSupportActionBar(toolbar); 

     inputEmail = (AutoCompleteTextView) findViewById(R.id.email); 
     inputPassword = (EditText) findViewById(R.id.password); 
     progressBar = (ProgressBar) findViewById(R.id.progressBar); 
     btnSignup = (Button) findViewById(R.id.btn_signup); 
     btnLogin = (Button) findViewById(R.id.btn_login); 
     btnReset = (Button) findViewById(R.id.btn_reset_password); 

     populateAutoComplete(); 

     //Get Firebase auth instance 
     auth = FirebaseAuth.getInstance(); 

     btnSignup.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       startActivity(new Intent(LoginActivity.this, SignupActivity.class)); 
      } 
     }); 

     btnReset.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       startActivity(new Intent(LoginActivity.this, ResetPasswordActivity.class)); 
      } 
     }); 

     btnLogin.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       String email = inputEmail.getText().toString(); 
       final String password = inputPassword.getText().toString(); 

       if (TextUtils.isEmpty(email)) { 
        Toast.makeText(getApplicationContext(), "Enter email address!", Toast.LENGTH_SHORT).show(); 
        return; 
       } 

       if (TextUtils.isEmpty(password)) { 
        Toast.makeText(getApplicationContext(), "Enter password!", Toast.LENGTH_SHORT).show(); 
        return; 
       } 

       progressBar.setVisibility(View.VISIBLE); 

       //authenticate user 
       auth.signInWithEmailAndPassword(email, password) 
        .addOnCompleteListener(LoginActivity.this, new OnCompleteListener<AuthResult>() 
        { 
         @Override 
         public void onComplete(@NonNull Task<AuthResult> task) { 
          // If sign in fails, display a message to the user. If sign in succeeds 
          // the auth state listener will be notified and logic to handle the 
          // signed in user can be handled in the listener. 
          progressBar.setVisibility(View.GONE); 
          if (!task.isSuccessful()) 
          { 
           // there was an error 
           if (password.length() < 6) 
           { 
            inputPassword.setError(getString(R.string.minimum_password)); 
           } 
           else 
           { 
            Toast.makeText(LoginActivity.this, getString(R.string.auth_failed), Toast.LENGTH_LONG).show(); 
           } 
          } 
          else 
          { 
           // Send to check if the user has been verified. 
           checkIfEmailVerified(); 
          } 
         } 

         // Logic for checking if the email is verified or not 
         private void checkIfEmailVerified() 
         { 
          FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); 
          if (user.isEmailVerified()) 
          { 
           // user is verified, finish this activity and send to MainActivity. 
           Toast.makeText(LoginActivity.this, "Successfully logged in: Lets start flying!", Toast.LENGTH_SHORT).show(); 
           Intent intent = new Intent(LoginActivity.this, MainActivity.class); 
           startActivity(intent); 
           finish(); 
          } 
          else 
          { 
           // Email is not verified and prompt a message to the user and restart this activity. 
           // NOTE: don't forget to log out the user. 
           FirebaseAuth.getInstance().signOut(); 
          } 
         } 

        }); 
      } 
     }); 
    } 

    private void populateAutoComplete() { 
     if (!mayRequestContacts()) { 
      return; 
     } 

     getSupportLoaderManager().initLoader(0, null, this); 
    } 

    private boolean mayRequestContacts() { 
     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 
      return true; 
     } 
     if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) { 
      return true; 
     } 
     if (shouldShowRequestPermissionRationale(READ_CONTACTS)) { 
      Snackbar.make(inputEmail, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE) 
        .setAction(android.R.string.ok, new View.OnClickListener() { 
         @Override 
         @TargetApi(Build.VERSION_CODES.M) 
         public void onClick(View v) { 
          requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS); 
         } 
        }); 
     } else { 
      requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS); 
     } 
     return false; 
    } 

    /** 
    * Callback received when a permissions request has been completed. 
    */ 
    @Override 
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 
              @NonNull int[] grantResults) { 
     if (requestCode == REQUEST_READ_CONTACTS) { 
      if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
       populateAutoComplete(); 
      } 
     } 
    } 

    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { 
     return new CursorLoader(this, 
       // Retrieve data rows for the device user's 'profile' contact. 
       Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI, 
         ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION, 

       // Select only email addresses. 
       ContactsContract.Contacts.Data.MIMETYPE + 
         " = ?", new String[]{ContactsContract.CommonDataKinds.Email 
       .CONTENT_ITEM_TYPE}, 

       // Show primary email addresses first. Note that there won't be 
       // a primary email address if the user hasn't specified one. 
       ContactsContract.Contacts.Data.IS_PRIMARY + " DESC"); 
    } 

    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) { 
     List<String> emails = new ArrayList<>(); 
     cursor.moveToFirst(); 
     while (!cursor.isAfterLast()) { 
      emails.add(cursor.getString(ProfileQuery.ADDRESS)); 
      cursor.moveToNext(); 
     } 

     addEmailsToAutoComplete(emails); 
    } 

    public void onLoaderReset(Loader<Cursor> cursorLoader) { 

    } 

    private void addEmailsToAutoComplete(List<String> emailAddressCollection) { 
     //Create adapter to tell the AutoCompleteTextView what to show in its dropdown list. 
     ArrayAdapter<String> adapter = 
       new ArrayAdapter<>(LoginActivity.this, 
         android.R.layout.simple_dropdown_item_1line, emailAddressCollection); 

     inputEmail.setAdapter(adapter); 
    } 


    private interface ProfileQuery { 
     String[] PROJECTION = { 
       ContactsContract.CommonDataKinds.Email.ADDRESS, 
       ContactsContract.CommonDataKinds.Email.IS_PRIMARY, 
     }; 

     int ADDRESS = 0; 
     int IS_PRIMARY = 1; 
    } 

} 
+0

Вы уверены, что получаете результаты в 'onLoadFinished()'? Не могу сказать, что я когда-либо пользовался поставщиком контактов, но данные запроса, которые вы создаете 'CursorLoader', выглядят не совсем правильно. –

+0

могут получить все сообщения электронной почты? –

ответ

0

Вы можете достичь этого следующим образом:

  1. Сначала создайте пользовательский ArrayAdapter вместо

    ArrayAdapter<String> adapter = 
         new ArrayAdapter<>(LoginActivity.this, 
           android.R.layout.simple_dropdown_item_1line, emailAddressCollection); 
    
    inputEmail.setAdapter(adapter); 
    
  2. Скажем, мы называем это AutoCompleteAdapter и пусть реализовать Filterable интерфейс

    public class AutoCompleteAdapter extends ArrayAdapter<String> implements Filterable { 
    
  3. Переопределение getFilter() и положить чек длиной символа 2 символов для электронной почты.

1

Вы можете сделать это

сделать адаптер в качестве глобальной переменной и добавить textwatcher для ввода электронной почты и установить адаптер только тогда, когда размер текста достигает 2

inputEmail.addTextChangedListener(new TextWatcher() { 

     @Override 
     public void onTextChanged(CharSequence s, int start, int before, int count) { 

      if (s.length() < 2) { 

      inputEmail.setAdapter(null) 

      } 
      else if(s.length()==2){ 
        //this is to make sure adapter not getting set every time if length is greater than 2 
      inputEmail.setAdapter(adapter) 

      } 
     } 

     @Override 
     public void beforeTextChanged(CharSequence s, int start, int count, int after) { 


     } 

     @Override 
     public void afterTextChanged(Editable s) { 


     } 
    }); 

изменить условие, как вы предпочитаем. Надеюсь, это поможет.

8

Замените код метода onCreateLoader() на код ниже.

public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { 
    return new CursorLoader(this, 
      // Retrieve data rows for the device user's 'profile' contact. 
      ContactsContract.Data.CONTENT_URI, ProfileQuery.PROJECTION, 

      // Select only email addresses. 
      ContactsContract.Contacts.Data.MIMETYPE + 
        " = ?", new String[]{ContactsContract.CommonDataKinds.Email 
      .CONTENT_ITEM_TYPE}, 

      // Show primary email addresses first. Note that there won't be 
      // a primary email address if the user hasn't specified one. 
      ContactsContract.Contacts.Data.IS_PRIMARY + " DESC"); 
} 
+0

Это правильный ответ, который должен быть принят. – KunalK

+0

Thnx !. Извините за то, что вернусь к этому в последнюю минуту. Теперь я должен выяснить, чтобы вырваться из этой деятельности, чтобы я мог повторно использовать ее в других - LOL. – CelticParser

Смежные вопросы