Как переместить мои методы 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 2

3 ответа:

Реально, вы можете использовать CursorAdapter, чтобы удалить все загрузчики, но в любом случае


Во-первых, я бы извлек этот метод "may request".

public interface ContactPermissionRequester {
    boolean mayRequestContacts();
}

Пусть ваша деятельность реализует это.

Тогда идея заключается в том, что вы просто хотите иметь голую активность и самостоятельно содержать представление автозаполнения textview. Для этого, по крайней мере, нужны Context и TextView. Для DB Loader вы также передаете это.

Вам нужно спросить разрешения в действии для эти методы я считаю .

  • 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) {
    }
}