【问题标题】:Query SharedPreferences for each item in ListView查询 ListView 中每个项目的 SharedPreferences
【发布时间】:2019-10-01 07:06:12
【问题描述】:

我有一个联系人列表,我正在尝试使用 contacts_service 插件将其加载到 ListView 中。对于每个联系人,我想首先检查他们是否被标记为isFavourite,通过检查他们的 ID 是否在SharedPreferences 的列表中来确定。如果是这样,那么我们会在他们的名字旁边显示一个星号。

因为检查 SharedPreferences 需要一个 Future,我该如何完成呢?到目前为止的进展如下。

联系人屏幕:

@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?
    }

【问题讨论】:

    标签: listview dart flutter sharedpreferences


    【解决方案1】:

    我建议定义一个在应用启动时初始化的应用范围的超级变量。

    例如ma​​in.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;
    
      ...
    }
    

    您可能已经在代码中注意到,每次在ListView 中构建联系人时都会调用SharedPreferences 初始化,然后是prefs.getStringList("Favourites") 调用。

    如果您定义一次收藏夹数组并将其用于每个联系人构建调用,则可以避免这两个相对繁重的操作。

    我将如何做到这一点是在接受List&lt;String&gt; 作为参数的Contact 对象中创建isFavourite 函数。例如

    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);
    );
    ...
    

    但是,我必须警告你,我不知道在 Dart/Flutter 中如何处理全局(/super/app-wide)变量,以及将 main() 方法声明为 @ 是否是个好主意987654336@,所以使用它需要您自担风险。(更新)

    根据我的个人经验 - 到目前为止我还没有遇到任何问题。

    更新

    如果perfectly safe,则将main() 声明为async

    至于全局变量——我的方法是可以的,虽然有一个even better one

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多