微信公眾號:Android部落格,文末有二維碼
個人網站:chengang.plus
1、用法
用法示例:
class InheritedData extends InheritedWidget {
final String data;
InheritedData({
this.data,
Widget child,
}) : super(child: child);
static InheritedData of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<InheritedData>();
}
@override
bool updateShouldNotify(InheritedData old) => true;
}
class TestInheritedDataWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text(
"${InheritedData.of(context).data}",
style: TextStyle(fontSize: 18, color: Colors.pink),
),
);
}
}
class ParentWidget extends StatefulWidget {
@override
_ParentWidgetState createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
var data = "you are beautiful";
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
child: Container(
color: Colors.cyan,
width: double.infinity,
child: InheritedData(
data: data,
child: TestInheritedDataWidget(),
),
),
onTap: _buttonClicked,
),
);
}
_buttonClicked() {
setState(() {
data = "in white";
});
}
}
複製程式碼
2、ProxyWidget
InheritedWidget繼承自ProxyWidget,在ProxyWidget中createElement呼叫的時候,建立了一個InheritedElement物件。
2.1 InheritedElement
InheritedElement繼承自ProxyElement,ProxyElement繼承自ComponentElement,ComponentElement繼承自Element。
在InheritedElement中定義了一個全域性Map物件:
final Map<Element, Object> _dependents = HashMap<Element, Object>();
複製程式碼
同時還定義了一個_updateInheritance方法。在Element和 InheritedElement中都有定義:
Element
void _updateInheritance() {
_inheritedWidgets = _parent?._inheritedWidgets;
}
複製程式碼
Map<Type, InheritedElement> _inheritedWidgets
定義在Element中,是一個全域性變數。
InheritedElement
@override
void _updateInheritance() {
final Map<Type, InheritedElement> incomingWidgets = _parent?._inheritedWidgets;
if (incomingWidgets != null)
_inheritedWidgets = HashMap<Type, InheritedElement>.from(incomingWidgets);
else
_inheritedWidgets = HashMap<Type, InheritedElement>();
_inheritedWidgets[widget.runtimeType] = this;
}
複製程式碼
InheritedElement中這個方法的主要邏輯是:先判斷當前Element的_inheritedWidgets是否存在,不存在,新建一個,否則將已有的新增到_inheritedWidgets中,同時將當前Element新增到_inheritedWidgets中。
Element中的_updateInheritance方法被執行意味著,所有的Widget對應的Element都持有一個_inheritedWidgets,而InheritedWidget的child就可以通過Element的_updateInheritance方法直接持有InheritedElement。
2.2 儲存InheritedElement節點
那麼_updateInheritance是哪裡呼叫的呢?
參考之前的文章《flutter 繪製過程 系列2-佈局》,在Element類的mount方法中,會呼叫_updateInheritance方法,最終就呼叫到這裡了。
3、ProxyElement中更新
當InheritedWidget中的data被setState更新之後,依賴data的Widget也會被更新。
3.1 ProxyElement update方法
@override
void update(ProxyWidget newWidget) {
final ProxyWidget oldWidget = widget;
super.update(newWidget);
updated(oldWidget);
_dirty = true;
rebuild();
}
複製程式碼
到updated方法,在InheritedElement方法中:
InheritedElement
@override
void updated(InheritedWidget oldWidget) {
if (widget.updateShouldNotify(oldWidget))
super.updated(oldWidget);
}
複製程式碼
如果我們InheritedWidget中的updateShouldNotify返回為true的話,會執行到InheritedElement的updated方法中:
@protected
void updated(covariant ProxyWidget oldWidget) {
notifyClients(oldWidget);
}
複製程式碼
notifyClients執行到了子類InheritedElement的notifyClients方法。
3.2 InheritedElement notifyClients方法
@override
void notifyClients(InheritedWidget oldWidget) {
for (final Element dependent in _dependents.keys) {
notifyDependent(oldWidget, dependent);
}
}
複製程式碼
這裡的_dependents裡面儲存的是依賴InheritedWidget資料的節點。
3.3 _dependents儲存依賴資料的Element
本章最開始的時候InheritedData提供了一個靜態的of方法,依賴者(InheritedWidget的child Widget)呼叫dependOnInheritedWidgetOfExactType方法。在Element類中實現,BuildContext類中定義:
Element實現了BuildContext介面
Element
@override
T dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object aspect}) {
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
if (ancestor != null) {
return dependOnInheritedElement(ancestor, aspect: aspect) as T;
}
_hadUnsatisfiedDependencies = true;
return null;
}
複製程式碼
這裡先找到InheritedElement,通過_inheritedWidgets的key(runtimeType)找到對應的value(InheritedElement)。接下來呼叫dependOnInheritedElement方法:
Element
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect }) {
_dependencies ??= HashSet<InheritedElement>();
_dependencies.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
複製程式碼
在Element類中,先判斷_dependencies是否為空,為空的話新建一個HashSet,把這個InheritedElement新增進去,然後執行updateDependencies方法。這個this指代的就是InheritedWidget的child Widget的Element。
這個updateDependencies定義在對應的InheritedElement類中:
InheritedElement
@override
void updateDependencies(Element dependent, Object aspect) {
final Set<T> dependencies = getDependencies(dependent) as Set<T>;
if (dependencies != null && dependencies.isEmpty)
return;
if (aspect == null) {
setDependencies(dependent, HashSet<T>());
} else {
setDependencies(dependent, (dependencies ?? HashSet<T>())..add(aspect as T));
}
}
@protected
void setDependencies(Element dependent, Object value) {
_dependents[dependent] = value;
}
複製程式碼
到這裡基本上清楚了基本的脈絡,_dependents裡面儲存的就是是InheritedWidget的child Widget的Element。
3.4 提醒依賴Element更新
回到InheritedElement notifyClients方法,這裡會遍歷_dependents,然後執行notifyDependent方法:
InheritedElement
@protected
void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {
dependent.didChangeDependencies();
}
@mustCallSuper
void didChangeDependencies() {
markNeedsBuild();
}
複製程式碼
到這裡重新繪製渲染依賴InheritedWidget資料的Widget。