Skip to content

Commit

Permalink
Fix - TextInput Drawable to avoid Null Pointer Exception RuntimeError #…
Browse files Browse the repository at this point in the history
…17530 (#29452)

Summary:
This issue fixes #17530 fixes expo/expo#9905 with the help of sunnylqm https://github.com/sunnylqm

Re-rendering a large number of TextInputs with key prop on the screen will trigger the below Null Pointer Exception Runtime Error

NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'

The error is caused by null.newDrawable(mSourceRes) at

https://github.com/aosp-mirror/platform_frameworks_base/blob/20b012282e0c3d94b5c0aa799cdda065f2df06db/graphics/java/android/graphics/drawable/DrawableContainer.java#L919

More info #29452 (comment) #17530 (comment)

The Theme Theme.AppCompat.Light.NoActionBar defines the Drawables for AppCompatEditText in drawable/abc_edit_text_material.xml

https://chromium.googlesource.com/android_tools/+/7200281446186c7192cb02f54dc2b38e02d705e5/sdk/extras/android/support/v7/appcompat/res/drawable/abc_edit_text_material.xml

Removing the following line from the above xml file drawable/abc_edit_text_material.xml fixes the error #17530 (comment)

`<item android:state_pressed="false" android:state_focused="false" android:drawable="drawable/abc_textfield_default_mtrl_alpha"/>`

The Theme default EditText background is replaced with a custom background, which is a copy of the original background without the above item which triggers the Runtime Error. The changes are implemented in RNTester with commit (more info in the commit) 0858d41. The new custom drawable used as default background for the TextInput is named edit_text.

`<item name="android:editTextBackground">drawable/edit_text</item>`

The same changes have been added to react-native default template for creating new applications with commit (more info) f349308, lean core moved the cli tools to https://github.com/react-native-community/cli, but the default template for creating a new application is stored in facebook/react-native/template.

New applications will be generated with this configurations and will not experience the error, existing react-native applications will fix the error by upgrading with the [upgrade-helper](https://github.com/react-native-community/upgrade-helper).

A Minimum Reproducible Example to reproduce this error is included in commit (more info in the commit) fabOnReact@4a414e2 and #17530 (comment)

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[Android] [Fixed] - TextInput Drawable to avoid Null Pointer Exception RuntimeError #17530

Pull Request resolved: #29452

Test Plan:
Works in all scenarios on Android.

**<details><summary>CLICK TO OPEN TESTS RESULTS - React Native</summary>**
<p>

Test Results from the Testing in RNTester.

Minimum Reproducible Example added with commit (more info in the commit) fabOnReact@4a414e2

The example included in commit fabOnReact@4a414e2 will cause a [NPE Runtime Error on Master Branch](https://fabriziobertoglio.s3.eu-central-1.amazonaws.com/opensource/react-native/17530/runtime.mp4), while no error is experienced in the [feature branch](https://fabriziobertoglio.s3.eu-central-1.amazonaws.com/opensource/react-native/17530/no_runtime.mp4). The links are video hosted on s3 of this tests (playable by google chrome).

| **[BEFORE](https://fabriziobertoglio.s3.eu-central-1.amazonaws.com/opensource/react-native/17530/runtime.mp4)** | **[AFTER](https://fabriziobertoglio.s3.eu-central-1.amazonaws.com/opensource/react-native/17530/no_runtime.mp4)** |
|:-------------------------:|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/88069187-6edde400-cb71-11ea-81f2-1846144cc6c1.png"  width="300" height="" />| <img src="https://user-images.githubusercontent.com/24992535/88069503-d5630200-cb71-11ea-9b87-c5c49845c96d.png" width="300" height="" /> |

The below screenshots were taken to detect any issues with the EditText Background. There is no difference between master and feature branch.

| **BEFORE** | **AFTER** |
|:-------------------------:|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/88071948-c0d43900-cb74-11ea-9a86-522b13e79f04.png"  width="300" height="" />| <img src="https://user-images.githubusercontent.com/24992535/88074345-90da6500-cb77-11ea-8ced-8b34a3c5a299.png" width="300" height="" /> |

| **BEFORE** | **AFTER** |
|:-------------------------:|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/88071966-c598ed00-cb74-11ea-8db8-c07dce3a99b6.png"  width="300" height="" />| <img src="https://user-images.githubusercontent.com/24992535/88074654-fcbccd80-cb77-11ea-961c-f39a60a1aa62.png" width="300" height="" /> |

| **BEFORE** | **AFTER** |
|:-------------------------:|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/88071989-cc276480-cb74-11ea-9eab-9ad4f858d0fb.png"  width="300" height="" />| <img src="https://user-images.githubusercontent.com/24992535/88074673-00505480-cb78-11ea-8ff5-ea5fc9ef1b8e.png" width="300" height="" /> |

| **BEFORE** | **AFTER** |
|:-------------------------:|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/88072003-d0ec1880-cb74-11ea-9285-792b2dc08187.png"  width="300" height="" />| <img src="https://user-images.githubusercontent.com/24992535/88074685-03e3db80-cb78-11ea-86a5-da2700826eea.png" width="300" height="" /> |

| **BEFORE** | **AFTER** |
|:-------------------------:|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/88072080-e7926f80-cb74-11ea-9f08-bb26eabbd5a0.png"  width="300" height="" />| <img src="https://user-images.githubusercontent.com/24992535/88074866-4a393a80-cb78-11ea-9b37-80c019909d7d.png" width="300" height="" /> |

| **BEFORE** | **AFTER** |
|:-------------------------:|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/88072100-ed885080-cb74-11ea-8450-bafa2b7a9989.png"  width="300" height="" />| <img src="https://user-images.githubusercontent.com/24992535/88074976-7359cb00-cb78-11ea-8bf3-d50566cbb3ba.png" width="300" height="" /> |

| **BEFORE** | **AFTER** |
|:-------------------------:|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/88072113-f1b46e00-cb74-11ea-9143-7e74872f2670.png"  width="300" height="" />| <img src="https://user-images.githubusercontent.com/24992535/88074880-502f1b80-cb78-11ea-8bfc-f67efec283d3.png" width="300" height="" /> |

| **BEFORE** | **AFTER** |
|:-------------------------:|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/88072118-f547f500-cb74-11ea-8ba3-8a245fdf0bc3.png"  width="300" height="" />| <img src="https://user-images.githubusercontent.com/24992535/88074883-52917580-cb78-11ea-9230-71aeb5c35582.png" width="300" height="" /> |

| **BEFORE** | **AFTER** |
|:-------------------------:|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/88072139-fb3dd600-cb74-11ea-9212-485f788648f1.png"  width="300" height="" />| <img src="https://user-images.githubusercontent.com/24992535/88075031-85d40480-cb78-11ea-8068-50f04ebbff54.png" width="300" height="" /> |

| **AFTER** |
|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/88071330-f75d8400-cb73-11ea-800d-359336c8d51e.png"  width="300" height="" />|

</p>
</details>

**<details><summary>CLICK TO OPEN TESTS RESULTS - React Native Cli</summary>**
<p>

As lean core move cli tools to https://github.com/react-native-community/cli, I tested the changes to the template in a separate repository https://github.com/fabriziobertoglio1987/react-native-template and generated the template with the following command

```
npx react-native init ProjectName --template file:///home/fabrizio/Documents/sourcecode/opensource/react-native-template/template
```

The generated app did not experience any issues and includes all the changes in [rn_edit_text_material.xml](https://github.com/fabriziobertoglio1987/react-native-template/blob/master/ProjectName/android/app/src/main/res/drawable/rn_edit_text_material.xml) and [styles.xml](https://github.com/fabriziobertoglio1987/react-native-template/blob/master/ProjectName/android/app/src/main/res/values/styles.xml)

</p>
</details>

Reviewed By: cortinico

Differential Revision: D30684030

Pulled By: lunaleaps

fbshipit-source-id: 7404da0a7259a4bc0405e57e5ed908649d180524
  • Loading branch information
fabOnReact authored and facebook-github-bot committed Oct 1, 2021
1 parent fabd253 commit 254493e
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
android:banner="@drawable/tv_banner"
android:icon="@drawable/launcher_icon"
android:label="@string/app_name"
android:theme="@style/Theme.ReactNative.AppCompat.Light" >
android:theme="@style/AppTheme">
<activity
android:name=".RNTesterActivity"
android:label="@string/app_name"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material"
android:insetRight="@dimen/abc_edit_text_inset_horizontal_material"
android:insetTop="@dimen/abc_edit_text_inset_top_material"
android:insetBottom="@dimen/abc_edit_text_inset_bottom_material">

<selector>
<!--
This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).
The item below with state_pressed="false" and state_focused="false" causes a NullPointerException.
NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'
<item android:state_pressed="false" android:state_focused="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.
-->
<item android:state_enabled="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
<item android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/>
</selector>

</inset>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:textColor">#000000</item>
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
</style>

</resources>
52 changes: 52 additions & 0 deletions packages/rn-tester/js/examples/TextInput/TextInputKeyProp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/

'use strict';

const React = require('react');
const {View, TextInput} = require('react-native');
const {useEffect, useState} = React;

function TextInputKeyProp() {
const [startKey, setStartKey] = useState(0);

useEffect(() => {
const interval = setInterval(() => setStartKey(startKey + 100), 3000);
return () => clearInterval(interval);
}, [startKey]);

const textInputs = [];
for (let i = 0; i < 101; i++) {
const key = (startKey + i).toString();
console.log('Adding a TextInput with key ' + key);
textInputs.push(
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
key={key}
/>,
);
}

return <View>{textInputs}</View>;
}

exports.title = 'TextInputs with key prop';
exports.description =
'Periodically render large number of TextInputs with key prop without a Runtime Error';
exports.examples = [
{
title: 'Long List of TextInputs with key props',
description:
'100 TextInputs are added every 3 seconds to the View. #29452 avoids a NPE Runtime Error. If you want to trigger the Runtime, change 101 to 1001 in RNTester/TextInputKeyProp.js and use an Emulator with 8GB of RAM. This example is only meant to verify no RuntimeError is triggered. To test TextInput functionalities use the <TextInput> example.',
render: function(): React.Node {
return <TextInputKeyProp />;
},
},
];
4 changes: 4 additions & 0 deletions packages/rn-tester/js/utils/RNTesterList.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ const Components: Array<RNTesterModuleInfo> = [
category: 'Basic',
module: require('../examples/TextInput/TextInputExample'),
},
{
key: 'TextInputs with key prop',
module: require('../examples/TextInput/TextInputKeyProp'),
},
{
key: 'TouchableExample',
category: 'UI',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material"
android:insetRight="@dimen/abc_edit_text_inset_horizontal_material"
android:insetTop="@dimen/abc_edit_text_inset_top_material"
android:insetBottom="@dimen/abc_edit_text_inset_bottom_material">

<selector>
<!--
This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).
The item below with state_pressed="false" and state_focused="false" causes a NullPointerException.
NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'
<item android:state_pressed="false" android:state_focused="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.
-->
<item android:state_enabled="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
<item android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/>
</selector>

</inset>
1 change: 1 addition & 0 deletions template/android/app/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
</style>

</resources>

0 comments on commit 254493e

Please sign in to comment.