Android 屏幕旋转时 onSurfaceTextureSizeChanged 的值错误
Android wrong values from onSurfaceTextureSizeChanged on screen rotation
我正在尝试将视频流式传输到自定义 TextureView。视频以全屏模式显示。纵向模式和横向模式的布局相同:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root_layout"
tools:context=".SampleActivity">
<com.my.package.MyCustomTextureView
android:id="@+id/texture_custom"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:keepScreenOn="true" />
...
</RelativeLayout>
Manifest 中的 Activity 设置为自行处理方向更改:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".SampleActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/app_name"
android:theme="@style/FullscreenTheme" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
当方向改变时,Activity 似乎找到了正确的尺寸:
public class SampleActivity extends FragmentActivity {
....
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
RelativeLayout root = (RelativeLayout) findViewById(R.id.root_layout);
MyCustomTextureView view = (MyCustomTextureView) findViewById(R.id.texture_custom);
Log.d(TAG, "onConfigurationChanged newConfig: " + newConfig.screenWidthDp + "x" + newConfig.screenHeightDp + " root: "+root.getWidth() + "x" + root.getHeight() + " view: " + view.getWidth() + "x" + view.getHeight());
....
}
}
Activity 日志输出,当我从纵向转换为横向时(注意:这是在布局更改之前):
09-29 15:30:28.975 22303-22303/com.my.package D/com.my.package.SampleActivity onConfigurationChanged newConfig: 598x335 root: 1080x1920 view: 1080x1920
...但是自定义纹理视图收到错误的值:
public class MyCustomTextureView extends TextureView implements TextureView.SurfaceTextureListener {
....
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
Log.v(TAG, "onSurfaceTextureSizeChanged params: " + width + "x" + height + ", old values " + mMyWidth + "x" + mMyHeight + ", method values: " + getWidth() + "x" + getHeight());
}
....
}
TextureView 日志输出,当我从纵向转到横向时:
09-29 15:30:29.037 22303-22303/com.my.package V/com.my.package.MyCustomTextureView﹕ onSurfaceTextureSizeChanged params: 1080x1080, old values 1080x1920, method values: 1080x1080
如果我回到纵向模式,它似乎会再次检索到正确的尺寸:
Activity:
09-29 15:30:45.019 22303-22303/com.my.package D/com.my.package.SampleActivity onConfigurationChanged newConfig: 360x567 layout: 1920x1080 view: 1080x1080
纹理视图:
09-29 15:30:45.096 22303-22303/com.my.package V/com.my.package.MyCustomTextureView onSurfaceTextureSizeChanged params: 1080x1920, old values 1080x1920, method values: 1080x1920
我做错了什么?
...好的,我通过反复试验自己找到了解决方案。主要是错误。
无论如何,我仍然不知道为什么会有这种行为。如果您有任何想法,请随时发表评论并启发我 :D(并帮助其他可能遇到类似问题的人)。
阅读 Mark G. 的问题后我想到了这个想法。我只是在 onConfigurationChanged
函数中添加了一行:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
RelativeLayout root = (RelativeLayout) findViewById(R.id.root_layout);
MyCustomTextureView myView = (MyCustomTextureView) findViewById(R.id.texture_custom);
Log.d(TAG, "onConfigurationChanged newConfig: " + newConfig.screenWidthDp + "x" + newConfig.screenHeightDp + " root: "+root.getWidth() + "x" + root.getHeight() + " view: " + myView.getWidth() + "x" + myView.getHeight());
myView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
....
}
进行此更改后,当我从 1080x1920 传递到 1920x1080 时,我在 onSurfaceTextureSizeChanged
函数中得到了正确的值,而不是 1080x1080。当我从 1920x1080 变为 1080x1920 时也是如此。
...不,别问我为什么要手动放这个。我不知道。
为了完全确定,我尝试将该行直接放在 onSurfaceTextureSizeChanged
函数中,而不是 onConfigurationChanged
:
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
Log.v(TAG, "onSurfaceTextureSizeChanged params: " + width + "x" + height + ", old values " + mMyWidth + "x" + mMyHeight + ", method values: " + getWidth() + "x" + getHeight());
setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
}
...那没用。再一次,我不知道为什么。可能是因为 1080x1080 不是 TextureView 的错误大小,而是根 RelativeLayout 本身的错误大小。
我在使用 Camera2 实现时遇到了类似的问题。我使用 TextureView 的 AutoFitTextureView 实现作为相机的预览,并希望调整到正确的比例。我的问题来自方法的不同实现并传播到 onSurfaceTextureSizeChanged。
[1]com.google.android.cameraview.CameraView#onMeasure(..) -> [2]com.google.android.cameraview.AutoFitTextureView#onMeasure(..) -> [3]onSurfaceTextureSizeChanged(..)
问题 if [1] 与 [2] 不同。
我在 [1]:
中替换了
if (height < width * ratio.getY() / ratio.getX()) {
到
if (!(height < width * ratio.getY() / ratio.getX())) {
因为 [2] 有 if 基于宽度而不是高度
if (width < height * mRatioWidth / mRatioHeight) {
验证 onMeasure(..) 方法是否正确实施。
我正在尝试将视频流式传输到自定义 TextureView。视频以全屏模式显示。纵向模式和横向模式的布局相同:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root_layout"
tools:context=".SampleActivity">
<com.my.package.MyCustomTextureView
android:id="@+id/texture_custom"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:keepScreenOn="true" />
...
</RelativeLayout>
Manifest 中的 Activity 设置为自行处理方向更改:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".SampleActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/app_name"
android:theme="@style/FullscreenTheme" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
当方向改变时,Activity 似乎找到了正确的尺寸:
public class SampleActivity extends FragmentActivity {
....
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
RelativeLayout root = (RelativeLayout) findViewById(R.id.root_layout);
MyCustomTextureView view = (MyCustomTextureView) findViewById(R.id.texture_custom);
Log.d(TAG, "onConfigurationChanged newConfig: " + newConfig.screenWidthDp + "x" + newConfig.screenHeightDp + " root: "+root.getWidth() + "x" + root.getHeight() + " view: " + view.getWidth() + "x" + view.getHeight());
....
}
}
Activity 日志输出,当我从纵向转换为横向时(注意:这是在布局更改之前):
09-29 15:30:28.975 22303-22303/com.my.package D/com.my.package.SampleActivity onConfigurationChanged newConfig: 598x335 root: 1080x1920 view: 1080x1920
...但是自定义纹理视图收到错误的值:
public class MyCustomTextureView extends TextureView implements TextureView.SurfaceTextureListener {
....
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
Log.v(TAG, "onSurfaceTextureSizeChanged params: " + width + "x" + height + ", old values " + mMyWidth + "x" + mMyHeight + ", method values: " + getWidth() + "x" + getHeight());
}
....
}
TextureView 日志输出,当我从纵向转到横向时:
09-29 15:30:29.037 22303-22303/com.my.package V/com.my.package.MyCustomTextureView﹕ onSurfaceTextureSizeChanged params: 1080x1080, old values 1080x1920, method values: 1080x1080
如果我回到纵向模式,它似乎会再次检索到正确的尺寸:
Activity:
09-29 15:30:45.019 22303-22303/com.my.package D/com.my.package.SampleActivity onConfigurationChanged newConfig: 360x567 layout: 1920x1080 view: 1080x1080
纹理视图:
09-29 15:30:45.096 22303-22303/com.my.package V/com.my.package.MyCustomTextureView onSurfaceTextureSizeChanged params: 1080x1920, old values 1080x1920, method values: 1080x1920
我做错了什么?
...好的,我通过反复试验自己找到了解决方案。主要是错误。
无论如何,我仍然不知道为什么会有这种行为。如果您有任何想法,请随时发表评论并启发我 :D(并帮助其他可能遇到类似问题的人)。
阅读 Mark G. 的问题后我想到了这个想法。我只是在 onConfigurationChanged
函数中添加了一行:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
RelativeLayout root = (RelativeLayout) findViewById(R.id.root_layout);
MyCustomTextureView myView = (MyCustomTextureView) findViewById(R.id.texture_custom);
Log.d(TAG, "onConfigurationChanged newConfig: " + newConfig.screenWidthDp + "x" + newConfig.screenHeightDp + " root: "+root.getWidth() + "x" + root.getHeight() + " view: " + myView.getWidth() + "x" + myView.getHeight());
myView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
....
}
进行此更改后,当我从 1080x1920 传递到 1920x1080 时,我在 onSurfaceTextureSizeChanged
函数中得到了正确的值,而不是 1080x1080。当我从 1920x1080 变为 1080x1920 时也是如此。
...不,别问我为什么要手动放这个。我不知道。
为了完全确定,我尝试将该行直接放在 onSurfaceTextureSizeChanged
函数中,而不是 onConfigurationChanged
:
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
Log.v(TAG, "onSurfaceTextureSizeChanged params: " + width + "x" + height + ", old values " + mMyWidth + "x" + mMyHeight + ", method values: " + getWidth() + "x" + getHeight());
setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
}
...那没用。再一次,我不知道为什么。可能是因为 1080x1080 不是 TextureView 的错误大小,而是根 RelativeLayout 本身的错误大小。
我在使用 Camera2 实现时遇到了类似的问题。我使用 TextureView 的 AutoFitTextureView 实现作为相机的预览,并希望调整到正确的比例。我的问题来自方法的不同实现并传播到 onSurfaceTextureSizeChanged。 [1]com.google.android.cameraview.CameraView#onMeasure(..) -> [2]com.google.android.cameraview.AutoFitTextureView#onMeasure(..) -> [3]onSurfaceTextureSizeChanged(..)
问题 if [1] 与 [2] 不同。 我在 [1]:
中替换了if (height < width * ratio.getY() / ratio.getX()) {
到
if (!(height < width * ratio.getY() / ratio.getX())) {
因为 [2] 有 if 基于宽度而不是高度
if (width < height * mRatioWidth / mRatioHeight) {
验证 onMeasure(..) 方法是否正确实施。