Запрос SharedPreferences для каждого элемента в ListView - PullRequest
0 голосов
/ 14 мая 2019

У меня есть список контактов, которые я пытаюсь загрузить в ListView, используя плагин contacts_service .Для каждого контакта я сначала хочу проверить, были ли они помечены как isFavourite, что определяется путем проверки того, есть ли их идентификатор в списке в SharedPreferences.Если это так, тогда мы показываем звездочку рядом с их именем.

Поскольку проверка SharedPreferences требует будущего, как мне это сделать?Прогресс на данный момент ниже.

Экран контактов:

@override
Widget build(BuildContext context) {
    return Scaffold(
    body: ListView.builder(
                itemCount: contacts?.length,
                itemBuilder: (BuildContext context, int index) {
                Contact c = contacts?.elementAt(index);

                return ListTile(
                    // Show star next to Contact's name
                    leading: c.isFavourite ? Icon(Icons.star) : null,
                    title: Text(c.name);
                );
            }
        );
    );
}

Общие настройки:

static Future<bool> checkIsFavourite(String contactId) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();

    List<String> favouriteContacts = prefs.getStringList("Favourites");
    return favouriteContacts.contains(contactId);
}

Служба контактов:

class ContactsService {
static const MethodChannel _channel =
    MethodChannel('github.com/clovisnicolas/flutter_contacts');

/// Fetches all contacts, or when specified, the contacts with a name
/// matching [query]
static Future<Iterable<Contact>> getContacts(
    {String query, bool withThumbnails = true}) async {
    Iterable contacts = await _channel.invokeMethod('getContacts',
        <String, dynamic>{'query': query, 'withThumbnails': withThumbnails});

    return contacts.map((m) => Contact.fromMap(m));
}

Класс контактов:

class Contact {
    Contact(
        {this.givenName,
        this.middleName,
        this.prefix,
        this.suffix,
        this.familyName,
        this.company,
        this.jobTitle,
        this.emails,
        this.phones,
        this.postalAddresses,
        this.avatar,
        this.note,
        this.isSelected});

    String identifier,
        displayName,
        givenName,
        middleName,
        prefix,
        suffix,
        familyName,
        company,
        jobTitle,
        note;
    Iterable<Item> emails = [];
    Iterable<Item> phones = [];
    Iterable<PostalAddress> postalAddresses = [];
    Uint8List avatar;
    bool isSelected;

    String initials() {
        return ((this.givenName?.isNotEmpty == true ? this.givenName[0] : "") +
                (this.familyName?.isNotEmpty == true ? this.familyName[0] : ""))
            .toUpperCase();
    }

    Contact.fromMap(Map m) {
        identifier = m["identifier"];
        displayName = m["displayName"];
        givenName = m["givenName"];
        middleName = m["middleName"];
        familyName = m["familyName"];
        prefix = m["prefix"];
        suffix = m["suffix"];
        company = m["company"];
        jobTitle = m["jobTitle"];
        emails = (m["emails"] as Iterable)?.map((m) => Item.fromMap(m));
        phones = (m["phones"] as Iterable)?.map((m) => Item.fromMap(m));
        postalAddresses = (m["postalAddresses"] as Iterable)
            ?.map((m) => PostalAddress.fromMap(m));
        avatar = m["avatar"];
        note = m["note"];
        isSelected = SharedPreferences.checkIsFavourite(m["identifier"]); 
        // What is the correct way to check if it's a favourite?
    }

1 Ответ

1 голос
/ 14 мая 2019

Я бы рекомендовал определить супер-переменную для всего приложения, которая инициализируется при запуске приложения.

Например, main.dart

SharedPreferences prefs;

void main() async {
  prefs = await SharedPreferences.getInstance();
  return runApp(MyApp());
}

Затем вы можете передать prefs переменная для любых других экранов / виджетов, где это необходимо в форме аргумента конструктора.Например,

class ContactsScreen extends StatefulWidget {
  ContactsScreen({
    Key key,
    @required this.prefs,
  }):
    super(key: key);

  final SharedPreferences prefs;

  ...
}

Вы, возможно, заметили в своем коде, что инициализация SharedPreferences вызывается при каждом построении контакта в ListView, за которым следует prefs.getStringList("Favourites") вызов.

Эти 2 являются относительно тяжелыми операциями, которых можно избежать, если один раз определить массив избранных и использовать его для каждого вызова построения контакта.

Как бы я это сделал, это создать isFavourite функцию в Contact объекте, который принимает List<String> в качестве аргумента.например,

class Contact {
  ...
  bool isFavourite(List<String> favouriteIds) {
    assert(favouriteIds != null);

    return favouriteIds.contains(this.identifier);
  }
  ...
}

и на экране контактов build:

final List<String> favouriteIds = prefs.getStringList("Favourites") ?? []; // Use empty array in case `Favourites` is not set
...
ListTile(
  // Show star next to Contact's name
  leading: contact.isFavourite(favouriteIds) ? Icon(Icons.star) : null,
  title: Text(contact.name);
);
...

Однако я должен предупредить вас, что я не знаю, насколько глобальным (/Переменные super / app-wide) обрабатываются в Dart / Flutter и рекомендуется ли объявлять метод main() как async, поэтому используйте его на свой страх и риск. (обновлено)

Исходя из моего личного опыта - проблем пока не возникало.

ОБНОВЛЕНО

Получается объявление main() как async, если совершенно безопасно .

Что касается глобальных переменных - мой метод в порядке, хотя есть , еще лучше .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...