Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
RestorationChannel.java
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package io.flutter.embedding.engine.systemchannels;
6
7import androidx.annotation.NonNull;
8import androidx.annotation.Nullable;
9import io.flutter.Log;
10import io.flutter.embedding.engine.dart.DartExecutor;
11import io.flutter.plugin.common.MethodCall;
12import io.flutter.plugin.common.MethodChannel;
13import io.flutter.plugin.common.StandardMethodCodec;
14import java.util.HashMap;
15import java.util.Map;
16
17/**
18 * System channel to exchange restoration data between framework and engine.
19 *
20 * <p>The engine can obtain the current restoration data from the framework via this channel to
21 * store it on disk and - when the app is relaunched - provide the stored data back to the framework
22 * to recreate the original state of the app.
23 *
24 * <p>The channel can be configured to delay responding to the framework's request for restoration
25 * data via {@code waitForRestorationData} until the engine-side has provided the data. This is
26 * useful when the engine is pre-warmed at a point in the application's life cycle where the
27 * restoration data is not available yet. For example, if the engine is pre-warmed as part of the
28 * Application before an Activity is created, this flag should be set to true because Android will
29 * only provide the restoration data to the Activity during the onCreate callback.
30 *
31 * <p>The current restoration data provided by the framework can be read via {@code
32 * getRestorationData()}.
33 */
34public class RestorationChannel {
35 private static final String TAG = "RestorationChannel";
36
38 @NonNull DartExecutor dartExecutor, @NonNull boolean waitForRestorationData) {
39 this(
40 new MethodChannel(dartExecutor, "flutter/restoration", StandardMethodCodec.INSTANCE),
42 }
43
44 RestorationChannel(MethodChannel channel, @NonNull boolean waitForRestorationData) {
45 this.channel = channel;
46 this.waitForRestorationData = waitForRestorationData;
47
48 channel.setMethodCallHandler(handler);
49 }
50
51 /**
52 * Whether the channel delays responding to the framework's initial request for restoration data
53 * until {@code setRestorationData} has been called.
54 *
55 * <p>If the engine never calls {@code setRestorationData} this flag must be set to false. If set
56 * to true, the engine must call {@code setRestorationData} either with the actual restoration
57 * data as argument or null if it turns out that there is no restoration data.
58 *
59 * <p>If the response to the framework's request for restoration data is not delayed until the
60 * data has been set via {@code setRestorationData}, the framework may intermittently initialize
61 * itself to default values until the restoration data has been made available. Setting this flag
62 * to true avoids that extra work.
63 */
64 public final boolean waitForRestorationData;
65
66 // Holds the most current restoration data which may have been provided by the engine
67 // via "setRestorationData" or by the framework via the method channel. This is the data the
68 // framework should be restored to in case the app is terminated.
69 private byte[] restorationData;
70 private MethodChannel channel;
71 private MethodChannel.Result pendingFrameworkRestorationChannelRequest;
72 private boolean engineHasProvidedData = false;
73 private boolean frameworkHasRequestedData = false;
74
75 /** Obtain the most current restoration data that the framework has provided. */
76 @Nullable
77 public byte[] getRestorationData() {
78 return restorationData;
79 }
80
81 /** Set the restoration data from which the framework will restore its state. */
82 public void setRestorationData(@NonNull byte[] data) {
83 engineHasProvidedData = true;
84 if (pendingFrameworkRestorationChannelRequest != null) {
85 // If their is a pending request from the framework, answer it.
86 pendingFrameworkRestorationChannelRequest.success(packageData(data));
87 pendingFrameworkRestorationChannelRequest = null;
88 restorationData = data;
89 } else if (frameworkHasRequestedData) {
90 // If the framework has previously received the engine's restoration data, push the new data
91 // directly to it. This case can happen when "waitForRestorationData" is false and the
92 // framework retrieved the restoration state before it was set via this method.
93 // Experimentally, this can also be used to restore a previously used engine to another state,
94 // e.g. when the engine is attached to a new activity.
95 channel.invokeMethod(
96 "push",
97 packageData(data),
98 new MethodChannel.Result() {
99 @Override
100 public void success(Object result) {
101 restorationData = data;
102 }
103
104 @Override
105 public void error(String errorCode, String errorMessage, Object errorDetails) {
106 Log.e(
107 TAG,
108 "Error "
109 + errorCode
110 + " while sending restoration data to framework: "
111 + errorMessage);
112 }
113
114 @Override
115 public void notImplemented() {
116 // Nothing to do.
117 }
118 });
119 } else {
120 // Otherwise, just cache the data until the framework asks for it.
121 restorationData = data;
122 }
123 }
124
125 /**
126 * Clears the current restoration data.
127 *
128 * <p>This should be called just prior to a hot restart. Otherwise, after the hot restart the
129 * state prior to the hot restart will get restored.
130 */
131 public void clearData() {
132 restorationData = null;
133 }
134
135 private final MethodChannel.MethodCallHandler handler =
136 new MethodChannel.MethodCallHandler() {
137 @Override
138 public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
139 final String method = call.method;
140 final Object args = call.arguments;
141 switch (method) {
142 case "put":
143 restorationData = (byte[]) args;
144 result.success(null);
145 break;
146 case "get":
147 frameworkHasRequestedData = true;
148 if (engineHasProvidedData || !waitForRestorationData) {
149 result.success(packageData(restorationData));
150 // Do not delete the restoration data on the engine side after sending it to the
151 // framework. We may need to hand this data back to the operating system if the
152 // framework never modifies the data (and thus doesn't send us any
153 // data back).
154 } else {
155 pendingFrameworkRestorationChannelRequest = result;
156 }
157 break;
158 default:
159 result.notImplemented();
160 break;
161 }
162 }
163 };
164
165 private Map<String, Object> packageData(byte[] data) {
166 final Map<String, Object> packaged = new HashMap<String, Object>();
167 packaged.put("enabled", true); // Android supports state restoration.
168 packaged.put("data", data);
169 return packaged;
170 }
171}
static void e(@NonNull String tag, @NonNull String message)
Definition Log.java:84
RestorationChannel( @NonNull DartExecutor dartExecutor, @NonNull boolean waitForRestorationData)
RestorationChannel(MethodChannel channel, @NonNull boolean waitForRestorationData)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
static ::testing::Matcher< GBytes * > MethodCall(const std::string &name, ::testing::Matcher< FlValue * > args)
GAsyncResult * result
#define TAG()