Data Binding
Data binding connects values stored by your Flutter app to text shown on the home screen widget — without a platform channel, without the app being open.
How it works
Flutter app Android widget
│ ▲
│ HomeWidgetData.save('score', '42') │
▼ │
SharedPreferences ───────────────────────────┘
Key: "flutter.flutter_android_widgets_score"
Value: "42"- Flutter writes values via
HomeWidgetData.save(), which uses theshared_preferencesplugin - The generated Kotlin reads from the same
FlutterSharedPreferencesXML file - No platform channel. No app process required. Works even when the app is killed.
Basic usage
Save from Flutter
// Save a single value
await HomeWidgetData.save('userName', 'Alice');
// Save multiple values at once
await HomeWidgetData.saveAll({
'temperature': '72°F',
'condition': 'Partly Cloudy',
'humidity': '58%',
});Declare keys in the widget definition
final weatherWidget = AndroidWidget(
info: WidgetInfo(...),
layout: WColumn(children: [
WText('\${temperature}', textSize: 32, bold: true, textColor: '#FFFFFF'),
WText('\${condition}', textSize: 16, textColor: '#CCCCCC'),
WText('\${humidity}', textSize: 12, textColor: '#888888'),
]),
dataKeys: ['temperature', 'condition', 'humidity'],
);Binding patterns
Simple binding
The entire text content is one placeholder:
WText('\${score}')Generated Kotlin:
val val_text_0 = prefs.getString("flutter.${KEY_PREFIX}score", "") ?: ""
views.setTextViewText(R.id.text_0, val_text_0)Template binding
Static text mixed with one or more placeholders:
WText('Hello, \${name}! You have \${count} messages.')Generated Kotlin:
var text_text_0 = "Hello, ${name}! You have ${count} messages."
val key_text_0_name = prefs.getString("flutter.${KEY_PREFIX}name", "") ?: ""
text_text_0 = text_text_0.replace("${name}", key_text_0_name)
val key_text_0_count = prefs.getString("flutter.${KEY_PREFIX}count", "") ?: ""
text_text_0 = text_text_0.replace("${count}", key_text_0_count)
views.setTextViewText(R.id.text_0, text_text_0)Static text (no binding)
WText('Last updated')No SharedPreferences read — the text is hardcoded in the XML layout.
HomeWidgetData API
| Method | Returns | Description |
|---|---|---|
HomeWidgetData.save(key, value) | Future<void> | Save a single String value |
HomeWidgetData.read(key) | Future<String?> | Read the current value for a key |
HomeWidgetData.remove(key) | Future<void> | Delete a key from storage |
HomeWidgetData.saveAll(map) | Future<void> | Save multiple key-value pairs atomically |
HomeWidgetData.autoUpdate | bool (setter) | Set to true to auto-call updateAll() after every save |
All values are stored as String. Serialize numbers, booleans, and objects yourself:
await HomeWidgetData.saveAll({
'count': count.toString(),
'isOnline': isOnline ? 'Yes' : 'No',
'temperature': temp.toStringAsFixed(1),
'updatedAt': DateTime.now().toString().substring(0, 16),
});Key format
The full SharedPreferences key is:
flutter.flutter_android_widgets_<yourKey>
│ │ └── key you pass to save()
│ └── package prefix (collision avoidance)
└── Flutter shared_preferences plugin prefix (always "flutter.")The generated Kotlin constructs the same key string. This is why there's zero configuration — the key format is deterministic on both sides.
Auto-refresh
Set HomeWidgetData.autoUpdate = true to automatically refresh all widgets after every save:
void main() {
WidgetsFlutterBinding.ensureInitialized();
WidgetUpdater.initialize(widgets: [myWidget]);
HomeWidgetData.autoUpdate = true; // ← enable auto-refresh
runApp(const MyApp());
}Now every save() or saveAll() call triggers an immediate widget refresh — so the home screen always shows current data.
Tips
- Default values: If a key has never been saved, the widget shows an empty string. Consider pre-populating keys in
main()withsaveAll(). - Key naming: Use consistent
camelCaseorsnake_case. Mismatch betweendataKeysandsave()keys means the widget shows nothing. - Serialization: All values are strings. For large/complex data, serialize to JSON first:
jsonEncode(myMap).