1
- import { NativeStackScreenProps } from '@react-navigation/native-stack' ;
2
- import React , { useState , useEffect , useRef } from 'react' ;
1
+ import type { NativeStackScreenProps } from '@react-navigation/native-stack' ;
2
+ import React , { useEffect , useRef , useState } from 'react' ;
3
3
import {
4
- View ,
5
- Text ,
4
+ Animated ,
5
+ SafeAreaView ,
6
+ ScrollView ,
6
7
StyleSheet ,
8
+ Text ,
7
9
TouchableOpacity ,
8
- ScrollView ,
9
- SafeAreaView ,
10
- Animated ,
10
+ View ,
11
11
} from 'react-native' ;
12
- import { HomeStackParamList } from '../../navigation/HomeStack' ;
12
+ import type { HomeStackParamList } from '../../navigation/HomeStack' ;
13
13
import { APM } from 'instabug-reactnative' ;
14
14
15
- // CustomComponents
15
+ // Custom Components
16
16
const ScreenRenderSwitch : React . FC = ( ) => {
17
17
const [ isEnabled , setIsEnabled ] = useState ( false ) ;
18
18
@@ -31,46 +31,45 @@ const ScreenRenderSwitch: React.FC = () => {
31
31
) ;
32
32
} ;
33
33
34
- const AnimatedBox : React . FC < { isBlocking : boolean } > = ( { isBlocking } ) => {
34
+ const AnimatedBox : React . FC < { isBlocking : boolean ; blockingIntensity : number } > = ( {
35
+ isBlocking,
36
+ blockingIntensity,
37
+ } ) => {
35
38
const [ counter , setCounter ] = useState ( 0 ) ;
39
+ const [ layoutThrasher , setLayoutThrasher ] = useState ( 0 ) ;
36
40
const animatedValue = useRef ( new Animated . Value ( 0 ) ) . current ;
37
41
const intervalRef = useRef < NodeJS . Timeout | null > ( null ) ;
38
42
39
- // Continuous animation
43
+ // Continuous animation - Use native driver for native thread work
40
44
useEffect ( ( ) => {
41
45
const animation = Animated . loop (
42
46
Animated . sequence ( [
43
47
Animated . timing ( animatedValue , {
44
48
toValue : 1 ,
45
49
duration : 1000 ,
46
- useNativeDriver : true ,
50
+ useNativeDriver : true , // Native driver for native thread
47
51
} ) ,
48
52
Animated . timing ( animatedValue , {
49
53
toValue : 0 ,
50
54
duration : 1000 ,
51
- useNativeDriver : true ,
55
+ useNativeDriver : true , // Native driver for native thread
52
56
} ) ,
53
57
] ) ,
54
58
) ;
55
59
animation . start ( ) ;
56
60
57
61
return ( ) => animation . stop ( ) ;
58
- } , [ ] ) ;
62
+ } , [ animatedValue ] ) ;
59
63
60
- // High frequency counter updates to force re-renders
64
+ // High frequency counter updates
61
65
useEffect ( ( ) => {
62
66
intervalRef . current = setInterval ( ( ) => {
63
- setCounter ( ( prev ) => {
64
- // This is where we block if isBlocking is true
65
- if ( isBlocking ) {
66
- const startTime = Date . now ( ) ;
67
- // Block for 100ms every render cycle
68
- while ( Date . now ( ) - startTime < 100 ) {
69
- // Busy wait - this will cause visible frozen frames
70
- }
71
- }
72
- return prev + 1 ;
73
- } ) ;
67
+ setCounter ( ( prev ) => prev + 1 ) ;
68
+
69
+ // Layout thrashing to block native thread
70
+ if ( isBlocking ) {
71
+ setLayoutThrasher ( ( prev ) => prev + 1 ) ;
72
+ }
74
73
} , 16 ) ; // ~60fps updates
75
74
76
75
return ( ) => {
@@ -85,19 +84,121 @@ const AnimatedBox: React.FC<{ isBlocking: boolean }> = ({ isBlocking }) => {
85
84
outputRange : [ 0 , 100 ] ,
86
85
} ) ;
87
86
87
+ const getStatusText = ( ) => {
88
+ if ( ! isBlocking ) {
89
+ return 'Running Smoothly' ;
90
+ }
91
+ if ( blockingIntensity === 1 ) {
92
+ return 'SLOW NATIVE RENDERING!' ;
93
+ }
94
+ if ( blockingIntensity === 2 ) {
95
+ return 'FROZEN NATIVE THREAD!' ;
96
+ }
97
+ return 'BLOCKING NATIVE THREAD!' ;
98
+ } ;
99
+
100
+ const getBoxColor = ( ) => {
101
+ if ( ! isBlocking ) {
102
+ return '#4ECDC4' ;
103
+ }
104
+ if ( blockingIntensity === 1 ) {
105
+ return '#FFB347' ;
106
+ } // Orange for slow
107
+ if ( blockingIntensity === 2 ) {
108
+ return '#FF6B6B' ;
109
+ } // Red for frozen
110
+ return '#FF6B6B' ;
111
+ } ;
112
+
113
+ // Generate many layout-heavy elements to stress native thread
114
+ const generateHeavyNativeElements = ( ) => {
115
+ if ( ! isBlocking ) return null ;
116
+
117
+ const elementCount = blockingIntensity === 1 ? 50 : 200 ; // More elements = more native work
118
+
119
+ return Array . from ( { length : elementCount } , ( _ , i ) => (
120
+ < View
121
+ key = { `heavy-${ i } -${ layoutThrasher } ` } // Force remount on layout thrash
122
+ style = { {
123
+ position : 'absolute' ,
124
+ left : ( i * 3 ) % 300 ,
125
+ top : ( i * 2 ) % 200 ,
126
+ width : 20 + ( layoutThrasher % 30 ) , // Constantly changing dimensions
127
+ height : 20 + ( ( layoutThrasher * 2 ) % 30 ) ,
128
+ backgroundColor : `hsl(${ ( i * 10 + layoutThrasher ) % 360 } , 70%, 60%)` ,
129
+ borderRadius : 5 + ( layoutThrasher % 10 ) , // Constantly changing border radius
130
+ transform : [
131
+ { rotate : `${ ( layoutThrasher * 5 + i * 10 ) % 360 } deg` } ,
132
+ { scale : 0.5 + ( layoutThrasher % 10 ) / 20 } , // Constantly changing scale
133
+ ] ,
134
+ opacity : 0.3 + ( layoutThrasher % 40 ) / 100 , // Constantly changing opacity
135
+ borderWidth : 1 + ( layoutThrasher % 3 ) , // Force layout recalculation
136
+ borderColor : `hsl(${ ( layoutThrasher * 7 ) % 360 } , 50%, 40%)` ,
137
+ } }
138
+ />
139
+ ) ) ;
140
+ } ;
141
+
88
142
return (
89
143
< View style = { styles . animatedContainer } >
90
144
< Text style = { styles . counterText } > Frame Counter: { counter } </ Text >
91
- < Animated . View
92
- style = { [
93
- styles . animatedBox ,
94
- {
145
+ < Text style = { [ styles . statusText , isBlocking && styles . statusTextAlert ] } >
146
+ Status: { getStatusText ( ) }
147
+ </ Text >
148
+
149
+ { /* Native thread heavy work area */ }
150
+ < View style = { styles . nativeWorkArea } >
151
+ < Animated . View
152
+ style = { {
153
+ backgroundColor : getBoxColor ( ) ,
95
154
transform : [ { translateX } ] ,
96
- backgroundColor : isBlocking ? '#FF6B6B' : '#4ECDC4' ,
97
- } ,
98
- ] } >
99
- < Text style = { styles . animatedBoxText } > { isBlocking ? 'FROZEN!' : 'Smooth' } </ Text >
100
- </ Animated . View >
155
+ width : 60 ,
156
+ height : 60 ,
157
+ borderRadius : 30 ,
158
+ justifyContent : 'center' ,
159
+ alignItems : 'center' ,
160
+ } } >
161
+ < Text style = { styles . animatedBoxText } >
162
+ { blockingIntensity === 1 ? 'Slow!' : blockingIntensity === 2 ? 'Frozen!' : 'Smooth' }
163
+ </ Text >
164
+ </ Animated . View >
165
+
166
+ { /* Heavy native rendering elements */ }
167
+ { generateHeavyNativeElements ( ) }
168
+ </ View >
169
+
170
+ { /* Additional native-heavy components */ }
171
+ { isBlocking && (
172
+ < View style = { styles . heavyNativeSection } >
173
+ { /* Multiple ScrollViews to stress native scrolling */ }
174
+ < ScrollView
175
+ style = { styles . miniScrollView }
176
+ showsVerticalScrollIndicator = { false }
177
+ contentContainerStyle = { { height : 1000 } } >
178
+ { Array . from ( { length : 100 } , ( _ , i ) => (
179
+ < View
180
+ key = { `scroll-${ i } -${ layoutThrasher } ` }
181
+ style = { {
182
+ height : 10 ,
183
+ backgroundColor : `hsl(${ ( i * 20 + layoutThrasher ) % 360 } , 60%, 70%)` ,
184
+ marginVertical : 1 ,
185
+ } }
186
+ />
187
+ ) ) }
188
+ </ ScrollView >
189
+
190
+ { /* Text that forces layout recalculation */ }
191
+ < Text
192
+ style = { {
193
+ fontSize : 8 + ( layoutThrasher % 10 ) ,
194
+ color : `hsl(${ layoutThrasher % 360 } , 70%, 50%)` ,
195
+ textAlign : 'center' ,
196
+ lineHeight : 12 + ( layoutThrasher % 8 ) ,
197
+ } } >
198
+ Layout Thrashing Text: { layoutThrasher }
199
+ </ Text >
200
+ </ View >
201
+ ) }
101
202
</ View >
102
203
) ;
103
204
} ;
@@ -124,24 +225,12 @@ const ScreenRenderPage: React.FC<NativeStackScreenProps<HomeStackParamList, 'Scr
124
225
navigation,
125
226
} ) => {
126
227
const [ isBlocking , setIsBlocking ] = useState ( false ) ;
228
+ const [ blockingIntensity , setBlockingIntensity ] = useState ( 0 ) ; // 0 = none, 1 = slow, 2 = frozen
127
229
const blockingTimeoutRef = useRef < NodeJS . Timeout | null > ( null ) ;
128
230
129
- const triggerSlowFrames = ( ) : void => {
130
- setIsBlocking ( true ) ;
131
-
132
- // Clear any existing timeout
133
- if ( blockingTimeoutRef . current ) {
134
- clearTimeout ( blockingTimeoutRef . current ) ;
135
- }
136
-
137
- // Stop blocking after 3 seconds
138
- blockingTimeoutRef . current = setTimeout ( ( ) => {
139
- setIsBlocking ( false ) ;
140
- } , 500 ) ;
141
- } ;
142
-
143
231
const triggerFrozenFrames = ( ) : void => {
144
232
setIsBlocking ( true ) ;
233
+ setBlockingIntensity ( 2 ) ; // Frozen frames mode
145
234
146
235
// Clear any existing timeout
147
236
if ( blockingTimeoutRef . current ) {
@@ -151,7 +240,8 @@ const ScreenRenderPage: React.FC<NativeStackScreenProps<HomeStackParamList, 'Scr
151
240
// Stop blocking after 5 seconds
152
241
blockingTimeoutRef . current = setTimeout ( ( ) => {
153
242
setIsBlocking ( false ) ;
154
- } , 3000 ) ;
243
+ setBlockingIntensity ( 0 ) ;
244
+ } , 5000 ) ;
155
245
} ;
156
246
157
247
const navigateToComplexPage = ( ) : void => {
@@ -174,19 +264,13 @@ const ScreenRenderPage: React.FC<NativeStackScreenProps<HomeStackParamList, 'Scr
174
264
175
265
< View style = { styles . spacer } />
176
266
177
- < AnimatedBox isBlocking = { isBlocking } />
267
+ < AnimatedBox isBlocking = { isBlocking } blockingIntensity = { blockingIntensity } />
178
268
179
269
< View style = { styles . largeSpacer } />
180
270
181
271
< View style = { styles . buttonContainer } >
182
272
< InstabugButton
183
- text = { isBlocking ? 'Frames are Delayed! (Wait...)' : 'Trigger Slow Frames (500ms)' }
184
- onPress = { triggerSlowFrames }
185
- disabled = { isBlocking }
186
- />
187
-
188
- < InstabugButton
189
- text = { isBlocking ? 'Frames are Delayed! (Wait...)' : 'Trigger Frozen Frames (3000ms)' }
273
+ text = { isBlocking ? 'Frames are Delayed! (Wait...)' : 'Trigger Frozen Frames (5s)' }
190
274
onPress = { triggerFrozenFrames }
191
275
disabled = { isBlocking }
192
276
/>
@@ -309,6 +393,50 @@ const styles = StyleSheet.create({
309
393
fontWeight : '600' ,
310
394
textAlign : 'center' ,
311
395
} ,
396
+ statusText : {
397
+ fontSize : 16 ,
398
+ color : '#666' ,
399
+ marginBottom : 10 ,
400
+ } ,
401
+ statusTextAlert : {
402
+ color : '#FF6B6B' , // Red for alert
403
+ fontWeight : 'bold' ,
404
+ } ,
405
+ additionalElements : {
406
+ flexDirection : 'row' ,
407
+ flexWrap : 'wrap' ,
408
+ justifyContent : 'center' ,
409
+ marginTop : 20 ,
410
+ } ,
411
+ smallBox : {
412
+ width : 30 ,
413
+ height : 30 ,
414
+ margin : 5 ,
415
+ borderRadius : 15 ,
416
+ } ,
417
+ nativeWorkArea : {
418
+ position : 'relative' ,
419
+ width : 200 ,
420
+ height : 200 ,
421
+ backgroundColor : '#f0f0f0' ,
422
+ borderRadius : 10 ,
423
+ justifyContent : 'center' ,
424
+ alignItems : 'center' ,
425
+ marginVertical : 10 ,
426
+ borderWidth : 1 ,
427
+ borderColor : '#ccc' ,
428
+ } ,
429
+ heavyNativeSection : {
430
+ marginTop : 20 ,
431
+ alignItems : 'center' ,
432
+ } ,
433
+ miniScrollView : {
434
+ width : '100%' ,
435
+ height : 100 ,
436
+ backgroundColor : '#e0e0e0' ,
437
+ borderRadius : 8 ,
438
+ marginBottom : 10 ,
439
+ } ,
312
440
} ) ;
313
441
314
442
export default ScreenRenderPage ;
0 commit comments