Как переместить мои методы AutoCompleteTextView / адаптер в собственный класс(Ы)
Я пытаюсь переместить некоторые методы из моей активности входа в систему в отдельный класс, чтобы они могли быть повторно использованы другими действиями. Я не был в состоянии понять это и хотел бы некоторые примеры, основанные на моем использовании ниже.
Thnx заранее.
Логиновская активность.java:
public class LoginActivity extends FirebaseUserNet implements LoaderManager.LoaderCallbacks<Cursor> {
public AutoCompleteTextView inputEmail;
/**
* Id to identity READ_CONTACTS permission request.
*/
public static final int REQUEST_READ_CONTACTS = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
inputEmail = (AutoCompleteTextView) findViewById(R.id.email);
// Populate the users contacts with their given permission
populateAutoComplete();
}
/**
* TODO: Everything below here needs to be put into a separate class(s) for reuse:
*/
public void populateAutoComplete() {
if (!mayRequestContacts()) {
return;
}
getSupportLoaderManager().initLoader(0, null, this);
}
public 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.
ContactsContract.Data.CONTENT_URI, ProfileQueryInterface.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(ProfileQueryInterface.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);
}
3 ответа:
Реально, вы можете использовать CursorAdapter, чтобы удалить все загрузчики, но в любом случае
Во-первых, я бы извлек этот метод "may request".
public interface ContactPermissionRequester { boolean mayRequestContacts(); }
Пусть ваша деятельность реализует это.
Тогда идея заключается в том, что вы просто хотите иметь голую активность и самостоятельно содержать представление автозаполнения textview. Для этого, по крайней мере, нужны
Context
и TextView. Для DBLoader
вы также передаете это.Вам нужно спросить разрешения в действии для эти методы я считаю .
- checkSelfPermission
- shouldShowRequestPermissionRationale
- requestPermissions
Можно попробовать дать другому классу
ContextCompat
вместоContext
и посмотреть, можно ли обойти логику разрешений.public class LoginActivity extends FirebaseUserNet implements ContactPermissionRequester { @Override public boolean mayRequestContacts() { ... } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { ... } @Override protected void onCreate(Bundle savedInstanceState) { inputEmail = (AutoCompleteTextView) findViewById(R.id.email); AutoCompleteTextViewLoader autoloader = new AutoCompleteTextViewLoader(this, inputEmail, getSupportLoaderManager()); autoloader.populate(); } }
Почти все остальное можно перенести в новый класс и использовать соответствующие параметры / поля там, где это необходимо. Теперь это действие - просто контекст, но оно также реализует это ранее интерфейс, который может запрашивать разрешения.
public class AutoCompleteTextViewLoader implements LoaderManager.LoaderCallbacks<Cursor> { private final Context mContext; private final AutoCompleteTextView inputEmail; private final ArrayAdapter<String> adapter; private final LoaderManager loaderManager private final List<String> emails = new ArrayList<>(); private final ContactPermissionRequester requester; public AutoCompleteLoader(Context context, AutoCompleteTextView textView, LoaderManager loaderManager) { this.mContext = context; this.inputEmail = textView; this.adapter = new ArrayAdapter<>(mContext, android.R.layout.simple_dropdown_item_1line, emails); this.inputEmail.setAdapter(adapter); // This can throw a ClassCastException this.mRequester = (ContactPermissionRequester) context; this.loaderManager = loaderManager; } public List<String> getEmails() { return emails; } public void populate() { if (requester != null && !requester.mayRequestContacts()) { return; } loadManager.initLoader(0, null, this); } @Override public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { return new CursorLoader(mContext, // Retrieve data rows for the device user's 'profile' contact. ContactsContract.Data.CONTENT_URI, ProfileQueryInterface.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"); } @Override public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) { // ArrayList not needed here cursor.moveToFirst(); while (!cursor.isAfterLast()) { // Add directly to adapter adapter.add(cursor.getString(ProfileQueryInterface.ADDRESS)); cursor.moveToNext(); } // Separate method was pointless } @Override public void onLoaderReset(Loader<Cursor> cursorLoader) { } }
Вы можете теоретически экстраполировать все открытые методы, которые не переопределяют их соответствующий метод суперкласса. Это было бы
public void populateAutoComplete() public boolean mayRequestContacts() public Loader<Cursor> onCreateLoader(int i, Bundle bundle) public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) public void onLoaderReset(Loader<Cursor> cursorLoader) private void addEmailsToAutoComplete(List<String> emailAddressCollection)
Я бы добавил параметр
LoginActivity log_act
Каждому методу, так что вы можете дать методам
this
Указатель на экземпляр класса. Таким образом, методы по-прежнему имеют доступ ко всему в классе, например к полям
public AutoCompleteTextView inputEmail;
Или методы типа
getSupportLoaderManager().initLoader(0, null, this);
Ответ @cricket_007 дал правильный о том, как извлечь методы [которые являются всего лишь адаптером массива]. Но для тех, кто хочет, чтобы действительный код работал, у меня есть его здесь ниже и обрабатывать запросы разрешений, snakebar и диалоги, как требуется для версий сборки >=
API level 23
, я также реализовал easypermissions Google.В Деятельности:
public class SomeActivity implements EasyPermissions.PermissionCallbacks { . . . /** * Id to identity READ_CONTACTS permission request. */ public static int REQUEST_READ_CONTACTS = 0; @Override protected void onCreate(Bundle savedInstanceState) { . . . //TODO: Fire `mayRequestContacts()` when the `AutoCompleteTextView` has focus. mayRequestContacts(); . . . } public void mayRequestContacts() { String[] perms = { Manifest.permission.READ_CONTACTS }; if (EasyPermissions.hasPermissions(this, perms)) { // Have permission, do the thing! } else { // Ask for permissions EasyPermissions.requestPermissions(this, getString(R.string.agreement_positive_text), REQUEST_READ_CONTACTS, perms); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); // Forward results to EasyPermissions EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); } @Override public void onPermissionsGranted(int requestCode, List<String> perms) { if (requestCode == REQUEST_READ_CONTACTS) { AutoCompleteTextViewLoader autoCompleteTextViewLoader = new AutoCompleteTextViewLoader(this, inputEmail, getSupportLoaderManager()); autoCompleteTextViewLoader.populate(); } } @Override public void onPermissionsDenied(int requestCode, List<String> perms) { if (requestCode == REQUEST_READ_CONTACTS) { Toast.makeText(this, "Sorry you choose that - You\'ll be typing a lot more.", Toast.LENGTH_SHORT).show(); } } }
AutoCompleteTextEmailLoader:
public class AutoCompleteTextEmailLoader implements LoaderManager.LoaderCallbacks<Cursor> { private final Context mContext; private final AutoCompleteTextView inputEmail; private final ArrayAdapter<String> adapter; private final LoaderManager loaderManager; private final List<String> emails = new ArrayList<>(); public AutoCompleteTextEmailLoader(Context context, AutoCompleteTextView textView, LoaderManager loaderManager) { this.mContext = context; this.inputEmail = textView; this.adapter = new ArrayAdapter<>(mContext, android.R.layout.simple_dropdown_item_1line, emails); this.inputEmail.setAdapter(adapter); this.loaderManager = loaderManager; } public void populate() { loaderManager.initLoader(0, null, this); } @Override public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { return new CursorLoader(mContext, // Retrieve data rows for the device user's 'profile' contact. ContactsContract.Data.CONTENT_URI, ProfileQueryInterface.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"); } @Override public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) { // ArrayList not needed here cursor.moveToFirst(); while (!cursor.isAfterLast()) { // Add directly to adapter adapter.add(cursor.getString(ProfileQueryInterface.ADDRESS)); cursor.moveToNext(); } } @Override public void onLoaderReset(Loader<Cursor> cursorLoader) { } }