@@ -85,11 +85,98 @@ public void onActivityDestroyed(Activity activity) {
8585 @ Override
8686 public void onActivityStopped (Activity activity ) {
8787 if (thisActivity == activity ) {
88- delegate .saveStateBeforeResult ();
88+ activityState . getDelegate () .saveStateBeforeResult ();
8989 }
9090 }
9191 }
9292
93+ /**
94+ * Move all activity-lifetime-bound states into this helper object, so that {@code setup} and
95+ * {@code tearDown} would just become constructor and finalize calls of the helper object.
96+ */
97+ private class ActivityState {
98+ private Application application ;
99+ private Activity activity ;
100+ private ImagePickerDelegate delegate ;
101+ private MethodChannel channel ;
102+ private LifeCycleObserver observer ;
103+ private ActivityPluginBinding activityBinding ;
104+
105+ // This is null when not using v2 embedding;
106+ private Lifecycle lifecycle ;
107+
108+ // Default constructor
109+ ActivityState (
110+ final Application application ,
111+ final Activity activity ,
112+ final BinaryMessenger messenger ,
113+ final MethodChannel .MethodCallHandler handler ,
114+ final PluginRegistry .Registrar registrar ,
115+ final ActivityPluginBinding activityBinding ) {
116+ this .application = application ;
117+ this .activity = activity ;
118+ this .activityBinding = activityBinding ;
119+
120+ delegate = constructDelegate (activity );
121+ channel = new MethodChannel (messenger , CHANNEL );
122+ channel .setMethodCallHandler (handler );
123+ observer = new LifeCycleObserver (activity );
124+ if (registrar != null ) {
125+ // V1 embedding setup for activity listeners.
126+ application .registerActivityLifecycleCallbacks (observer );
127+ registrar .addActivityResultListener (delegate );
128+ registrar .addRequestPermissionsResultListener (delegate );
129+ } else {
130+ // V2 embedding setup for activity listeners.
131+ activityBinding .addActivityResultListener (delegate );
132+ activityBinding .addRequestPermissionsResultListener (delegate );
133+ lifecycle = FlutterLifecycleAdapter .getActivityLifecycle (activityBinding );
134+ lifecycle .addObserver (observer );
135+ }
136+ }
137+
138+ // Only invoked by {@link #ImagePickerPlugin(ImagePickerDelegate, Activity)} for testing.
139+ ActivityState (final ImagePickerDelegate delegate , final Activity activity ) {
140+ this .activity = activity ;
141+ this .delegate = delegate ;
142+ }
143+
144+ void release () {
145+ if (activityBinding != null ) {
146+ activityBinding .removeActivityResultListener (delegate );
147+ activityBinding .removeRequestPermissionsResultListener (delegate );
148+ activityBinding = null ;
149+ }
150+
151+ if (lifecycle != null ) {
152+ lifecycle .removeObserver (observer );
153+ lifecycle = null ;
154+ }
155+
156+ if (channel != null ) {
157+ channel .setMethodCallHandler (null );
158+ channel = null ;
159+ }
160+
161+ if (application != null ) {
162+ application .unregisterActivityLifecycleCallbacks (observer );
163+ application = null ;
164+ }
165+
166+ activity = null ;
167+ observer = null ;
168+ delegate = null ;
169+ }
170+
171+ Activity getActivity () {
172+ return activity ;
173+ }
174+
175+ ImagePickerDelegate getDelegate () {
176+ return delegate ;
177+ }
178+ }
179+
93180 static final String METHOD_CALL_IMAGE = "pickImage" ;
94181 static final String METHOD_CALL_MULTI_IMAGE = "pickMultiImage" ;
95182 static final String METHOD_CALL_VIDEO = "pickVideo" ;
@@ -101,15 +188,8 @@ public void onActivityStopped(Activity activity) {
101188 private static final int SOURCE_CAMERA = 0 ;
102189 private static final int SOURCE_GALLERY = 1 ;
103190
104- private MethodChannel channel ;
105- private ImagePickerDelegate delegate ;
106191 private FlutterPluginBinding pluginBinding ;
107- private ActivityPluginBinding activityBinding ;
108- private Application application ;
109- private Activity activity ;
110- // This is null when not using v2 embedding;
111- private Lifecycle lifecycle ;
112- private LifeCycleObserver observer ;
192+ private ActivityState activityState ;
113193
114194 @ SuppressWarnings ("deprecation" )
115195 public static void registerWith (io .flutter .plugin .common .PluginRegistry .Registrar registrar ) {
@@ -137,8 +217,12 @@ public ImagePickerPlugin() {}
137217
138218 @ VisibleForTesting
139219 ImagePickerPlugin (final ImagePickerDelegate delegate , final Activity activity ) {
140- this .delegate = delegate ;
141- this .activity = activity ;
220+ activityState = new ActivityState (delegate , activity );
221+ }
222+
223+ @ VisibleForTesting
224+ final ActivityState getActivityState () {
225+ return activityState ;
142226 }
143227
144228 @ Override
@@ -153,13 +237,12 @@ public void onDetachedFromEngine(FlutterPluginBinding binding) {
153237
154238 @ Override
155239 public void onAttachedToActivity (ActivityPluginBinding binding ) {
156- activityBinding = binding ;
157240 setup (
158241 pluginBinding .getBinaryMessenger (),
159242 (Application ) pluginBinding .getApplicationContext (),
160- activityBinding .getActivity (),
243+ binding .getActivity (),
161244 null ,
162- activityBinding );
245+ binding );
163246 }
164247
165248 @ Override
@@ -183,37 +266,15 @@ private void setup(
183266 final Activity activity ,
184267 final PluginRegistry .Registrar registrar ,
185268 final ActivityPluginBinding activityBinding ) {
186- this .activity = activity ;
187- this .application = application ;
188- this .delegate = constructDelegate (activity );
189- channel = new MethodChannel (messenger , CHANNEL );
190- channel .setMethodCallHandler (this );
191- observer = new LifeCycleObserver (activity );
192- if (registrar != null ) {
193- // V1 embedding setup for activity listeners.
194- application .registerActivityLifecycleCallbacks (observer );
195- registrar .addActivityResultListener (delegate );
196- registrar .addRequestPermissionsResultListener (delegate );
197- } else {
198- // V2 embedding setup for activity listeners.
199- activityBinding .addActivityResultListener (delegate );
200- activityBinding .addRequestPermissionsResultListener (delegate );
201- lifecycle = FlutterLifecycleAdapter .getActivityLifecycle (activityBinding );
202- lifecycle .addObserver (observer );
203- }
269+ activityState =
270+ new ActivityState (application , activity , messenger , this , registrar , activityBinding );
204271 }
205272
206273 private void tearDown () {
207- activityBinding .removeActivityResultListener (delegate );
208- activityBinding .removeRequestPermissionsResultListener (delegate );
209- activityBinding = null ;
210- lifecycle .removeObserver (observer );
211- lifecycle = null ;
212- delegate = null ;
213- channel .setMethodCallHandler (null );
214- channel = null ;
215- application .unregisterActivityLifecycleCallbacks (observer );
216- application = null ;
274+ if (activityState != null ) {
275+ activityState .release ();
276+ activityState = null ;
277+ }
217278 }
218279
219280 @ VisibleForTesting
@@ -273,12 +334,13 @@ public void run() {
273334
274335 @ Override
275336 public void onMethodCall (MethodCall call , MethodChannel .Result rawResult ) {
276- if (activity == null ) {
337+ if (activityState == null || activityState . getActivity () == null ) {
277338 rawResult .error ("no_activity" , "image_picker plugin requires a foreground activity." , null );
278339 return ;
279340 }
280341 MethodChannel .Result result = new MethodResultWrapper (rawResult );
281342 int imageSource ;
343+ ImagePickerDelegate delegate = activityState .getDelegate ();
282344 if (call .argument ("cameraDevice" ) != null ) {
283345 CameraDevice device ;
284346 int deviceIntValue = call .argument ("cameraDevice" );
0 commit comments