Skip to content

Commit d1751f1

Browse files
authored
chore: doInBackground (#317)
1 parent 605d6de commit d1751f1

File tree

1 file changed

+85
-31
lines changed

1 file changed

+85
-31
lines changed

android/src/main/java/fr/greweb/reactnativeviewshot/ViewShot.java

Lines changed: 85 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,22 @@
88
import android.graphics.Paint;
99
import android.graphics.Point;
1010
import android.net.Uri;
11+
1112
import androidx.annotation.IntDef;
1213
import androidx.annotation.NonNull;
1314
import androidx.annotation.StringDef;
15+
16+
import android.os.Build;
17+
import android.os.Handler;
18+
import android.os.HandlerThread;
1419
import android.util.Base64;
1520
import android.util.Log;
1621
import android.view.TextureView;
1722
import android.view.View;
1823
import android.view.ViewGroup;
1924
import android.widget.ScrollView;
2025

26+
import com.facebook.react.bridge.LifecycleEventListener;
2127
import com.facebook.react.bridge.Promise;
2228
import com.facebook.react.bridge.ReactApplicationContext;
2329
import com.facebook.react.uimanager.NativeViewHierarchyManager;
@@ -47,7 +53,7 @@
4753
/**
4854
* Snapshot utility class allow to screenshot a view.
4955
*/
50-
public class ViewShot implements UIBlock {
56+
public class ViewShot implements UIBlock, LifecycleEventListener {
5157
//region Constants
5258
/**
5359
* Tag fort Class logs.
@@ -66,6 +72,30 @@ public class ViewShot implements UIBlock {
6672
*/
6773
private static final int ARGB_SIZE = 4;
6874

75+
private HandlerThread mBgThread;
76+
private Handler mBgHandler;
77+
78+
@Override
79+
public void onHostResume() {
80+
81+
}
82+
83+
@Override
84+
public void onHostPause() {
85+
86+
}
87+
88+
@Override
89+
public void onHostDestroy() {
90+
this.reactContext.removeLifecycleEventListener(this);
91+
mBgHandler.post(new Runnable() {
92+
@Override
93+
public void run() {
94+
cleanup();
95+
}
96+
});
97+
}
98+
6999
@SuppressWarnings("WeakerAccess")
70100
@IntDef({Formats.JPEG, Formats.PNG, Formats.WEBP, Formats.RAW})
71101
public @interface Formats {
@@ -157,44 +187,68 @@ public ViewShot(
157187
this.reactContext = reactContext;
158188
this.currentActivity = currentActivity;
159189
this.promise = promise;
190+
191+
reactContext.addLifecycleEventListener(this);
192+
193+
// bg hanadler for non UI heavy work
194+
mBgThread = new HandlerThread("RNViewShot-Handler-Thread");
195+
mBgThread.start();
196+
mBgHandler = new Handler(mBgThread.getLooper());
160197
}
161198
//endregion
162199

163-
//region Overrides
164-
@Override
165-
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
166-
final View view;
200+
private void cleanup() {
201+
if (mBgThread != null) {
202+
if (Build.VERSION.SDK_INT < 18) {
203+
mBgThread.quit();
204+
} else {
205+
mBgThread.quitSafely();
206+
}
167207

168-
if (tag == -1) {
169-
view = currentActivity.getWindow().getDecorView().findViewById(android.R.id.content);
170-
} else {
171-
view = nativeViewHierarchyManager.resolveView(tag);
208+
mBgThread = null;
172209
}
210+
}
173211

174-
if (view == null) {
175-
Log.e(TAG, "No view found with reactTag: " + tag, new AssertionError());
176-
promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "No view found with reactTag: " + tag);
177-
return;
178-
}
212+
//region Overrides
213+
@Override
214+
public void execute(final NativeViewHierarchyManager nativeViewHierarchyManager) {
215+
mBgHandler.post(new Runnable() {
216+
@Override
217+
public void run() {
218+
final View view;
219+
220+
if (tag == -1) {
221+
view = currentActivity.getWindow().getDecorView().findViewById(android.R.id.content);
222+
} else {
223+
view = nativeViewHierarchyManager.resolveView(tag);
224+
}
179225

180-
try {
181-
final ReusableByteArrayOutputStream stream = new ReusableByteArrayOutputStream(outputBuffer);
182-
stream.setSize(proposeSize(view));
183-
outputBuffer = stream.innerBuffer();
184-
185-
if (Results.TEMP_FILE.equals(result) && Formats.RAW == this.format) {
186-
saveToRawFileOnDevice(view);
187-
} else if (Results.TEMP_FILE.equals(result) && Formats.RAW != this.format) {
188-
saveToTempFileOnDevice(view);
189-
} else if (Results.BASE_64.equals(result) || Results.ZIP_BASE_64.equals(result)) {
190-
saveToBase64String(view);
191-
} else if (Results.DATA_URI.equals(result)) {
192-
saveToDataUriString(view);
226+
if (view == null) {
227+
Log.e(TAG, "No view found with reactTag: " + tag, new AssertionError());
228+
promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "No view found with reactTag: " + tag);
229+
return;
230+
}
231+
232+
try {
233+
final ReusableByteArrayOutputStream stream = new ReusableByteArrayOutputStream(outputBuffer);
234+
stream.setSize(proposeSize(view));
235+
outputBuffer = stream.innerBuffer();
236+
237+
if (Results.TEMP_FILE.equals(result) && Formats.RAW == format) {
238+
saveToRawFileOnDevice(view);
239+
} else if (Results.TEMP_FILE.equals(result) && Formats.RAW != format) {
240+
saveToTempFileOnDevice(view);
241+
} else if (Results.BASE_64.equals(result) || Results.ZIP_BASE_64.equals(result)) {
242+
saveToBase64String(view);
243+
} else if (Results.DATA_URI.equals(result)) {
244+
saveToDataUriString(view);
245+
}
246+
} catch (final Throwable ex) {
247+
Log.e(TAG, "Failed to capture view snapshot", ex);
248+
promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "Failed to capture view snapshot");
249+
}
193250
}
194-
} catch (final Throwable ex) {
195-
Log.e(TAG, "Failed to capture view snapshot", ex);
196-
promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "Failed to capture view snapshot");
197-
}
251+
});
198252
}
199253
//endregion
200254

0 commit comments

Comments
 (0)