应用在启动时,创建activity报错闪退,报错信息是”Activity {packageName/compomentName} did not call through to super.onCreate()” ,经确认,这个问题是梆梆加固的问题,请遇到的开发者联系梆梆加固厂商,用最新的版本升级即可。
05-13 09:53:25.471 10732 15838 15838 E AndroidRuntime: FATAL EXCEPTION: main
05-13 09:53:25.471 10732 15838 15838 E AndroidRuntime: Process: xxxx, PID: xxx
05-13 09:53:25.471 10732 15838 15838 E AndroidRuntime: android.util.SuperNotCalledException: Activity {xxx/xxxx} did not call through to super.onCreate()
05-13 09:53:25.471 10732 15838 15838 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3549)
05-13 09:53:25.471 10732 15838 15838 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3729)
..............................................//此处省略
// Determine whether the transition will be seamless.// Non-seamless transitions may cause a 1-2 second black screen.
Display display = context.getDisplay(); // API 30+
Display.Mode mode = display.getMode();
float[] refreshRates = mode.getAlternativeRefreshRates();
boolean willbeSeamless = Arrays.asList(refreshRates).contains(newRefreshRate);
// Set the frame rate even if the transition will not be seamless.
surface.setFrameRate(newRefreshRate, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS);
PACKAGE_NAME: Targeting S+ (version 10000 and above) requires that one of
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if
some functionality depends on the PendingIntent being mutable, e.g. if
it needs to be used with inline replies or bubbles.
publicclassMyReceiverimplementsOnReceiveContentListener {
publicstaticfinal String[] MIME_TYPES = new String[] {"image/*", "video/*"};
@Override
public ContentInfoCompat onReceiveContent(View view, ContentInfoCompat contentInfo) {
Pair<ContentInfoCompat, ContentInfoCompat> split = contentInfo.partition(
item -> item.getUri() != null);
ContentInfo uriContent = split.first;
ContentInfo remaining = split.second;
if (uriContent != null) {
ClipData clip = uriContent.getClip();
for (int i = 0; i < clip.getItemCount(); i++) {
Uri uri = clip.getItemAt(i).getUri();
// App-specific logic to handle the URI ...
}
}
// Return anything that your app didn't handle. This preserves the default platform// behavior for text and anything else that you aren't implementing custom handling for.return remaining;
}
}
// Create a new event for the activity.
@Override
protectedvoidonCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set the layout for the content view.
setContentView(R.layout.main_activity);
// Set up an OnPreDrawListener to the root view.final View content = findViewById(android.R.id.content);
content.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
publicbooleanonPreDraw() {
// Check if the initial data is ready.if (mViewModel.isReady()) {
// The content is ready; start drawing.
content.getViewTreeObserver().removeOnPreDrawListener(this);
returntrue;
} else {
// The content is not ready; suspend.returnfalse;
}
}
});
}
@Override
protectedvoidonCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...// Add a callback that's called when the splash screen is animating to// the app content.
getSplashScreen().setOnExitAnimationListener(splashScreenView -> {
final ObjectAnimator slideUp = ObjectAnimator.ofFloat(
splashScreenView,
View.TRANSLATION_Y,
0f,
-splashScreenView.getHeight()
);
slideUp.setInterpolator(new AnticipateInterpolator());
slideUp.setDuration(200L);
// Call SplashScreenView.remove at the end of your custom animation.
slideUp.addListener(new AnimatorListenerAdapter() {
@Override
publicvoidonAnimationEnd(Animator animation) {
splashScreenView.remove();
}
});
// Run your animation.
slideUp.start();
});
}
// Get the duration of the animated vector drawable.long animationDuration = splashScreenView.getIconAnimationDurationMillis();
// Get the start time of the animation.long animationStart = splashScreenView.getIconAnimationStartMillis();
// Calculate the remaining duration of the animation.long remainingDuration = Math.max(
animationDuration - (SystemClock.uptimeMillis() - animationStart),
0L
);
// Listener is called immediately after the user exits PIP but before animating.
playerView.addOnLayoutChangeListener { _, left, top, right, bottom,
oldLeft, oldTop, oldRight, oldBottom ->
if (left != oldLeft || right != oldRight || top != oldTop
|| bottom != oldBottom) {
// The playerView's bounds changed, update the source hint rect to // reflect its new bounds.
val sourceRectHint = Rect()
playerView.getGlobalVisibleRect(sourceRectHint)
setPictureInPictureParams(
PictureInPictureParams.Builder()
.setSourceRectHint(sourceRectHint)
.build()
)
}
}
// This broadcast receiver should be able to receive broadcasts from other apps.
// This option causes the same behavior as setting the broadcast receiver's
// "exported" attribute to true in your app's manifest.
context.registerReceiver(sharedBroadcastReceiver, intentFilter,
RECEIVER_EXPORTED);
// For app safety reasons, this private broadcast receiver should **NOT**
// be able to receive broadcasts from other apps.
context.registerReceiver(privateBroadcastReceiver, intentFilter,
RECEIVER_NOT_EXPORTED);
// Launches photo picker in single-select mode.
// This means that the user can select one photo or video.
Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
startActivityForResult(intent, PHOTO_PICKER_REQUEST_CODE);
2.1.3 选择多张照片或多个视频
如果应用的用例需要用户选择多张照片或多个视频,您可以使用EXTRA_PICK_IMAGES_MAX extra 指定照片选择器中应显示照片的数量上限,如以下代码段中所示:
// Launches photo picker in multi-select mode.
// This means that user can select multiple photos/videos, up to the limit
// specified by the app in the extra (10 in this example).
final int maxNumPhotosAndVideos = 10;
Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, maxNumPhotosAndVideos);
startActivityForResult(intent, PHOTO_PICKER_MULTI_SELECT_REQUEST_CODE);
// onActivityResult() handles callbacks from the photo picker.
@Override
protected void onActivityResult(
int requestCode, int resultCode, final Intent data) {
if (resultCode != Activity.RESULT_OK) {
// Handle error
return;
}
switch(requestCode) {
case REQUEST_PHOTO_PICKER_SINGLE_SELECT:
// Get photo picker response for single select.
Uri currentUri = data.getData();
// Do stuff with the photo/video URI.
return;
case REQUEST_PHOTO_PICKER_MULTI_SELECT:
// Get photo picker response for multi select
for (int i = 0; i < data.getClipData().getItemCount(); i++) {
Uri currentUri = data.getClipData().getItemAt(i).getUri();
// Do stuff with each photo/video URI.
}
return;
}
}
// Launches photo picker for videos only in single select mode.
Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
intent.setType("video/*");
startActivityForResult(intent, );
// Apps can also change the mimeType to allow users to select
// images only - intent.setType("images/*");
// or a specific mimeType - intent.setType("image/gif");
LocaleListCompat appLocale = LocaleListCompat.forLanguageTags("xx-YY");
// Call this on the main thread as it may require Activity.restart()
AppCompatDelegate.setApplicationLocales(appLocale);
// 1. Inside an activity, in-app language picker gets an input locale "xx-YY"
// 2. App calls the API to set its localem
Context.getSystemService(LocaleManager.class).setApplicationLocales(newLocaleList(Locale.forLanguageTag("xx-YY")));
// 3. The system updates the locale and restarts the app, including any configuration updates
// 4. The app is now displayed in "xx-YY" language
如需获取用户当前的首选语言以显示在语言选择器中,您的应用可以从系统中取回该值:
// 1. App calls the API to get the preferred locale
LocaleList currentAppLocales = mContext.getSystemService(LocaleManager.class).getApplicationLocales();
// 2. App uses the returned LocaleList to display languages to the user
2.2.2 面向用户的系统设置
用户可以通过新的系统设置为每个应用选择首选语言。他们可以通过以下两种方式访问这些设置:
通过系统设置访问
设置 > 系统 > 语言和输入法 > 应用语言 >(选择应用)
通过应用设置访问
设置 > 应用 >(选择一款应用)> 语言
已知问题
在测试应用时,有一些已知问题需要注意。
可用语言列表中可能不包含您的应用支持的语言。
如果您的应用使用拆分 APK,当应用语言区域发生变化时,系统不会自动下载这些 APK。
现在的界面只是一个初步版本,在后续版本中会不断更改。
2.2.3 DEMO演示
2.3 可由开发者降级的权限
从 Android 13 开始,应用可以撤消先前由系统或用户授予的运行时权限。此 API 可以帮助应用保护用户的隐私。
AndroidRuntime: FATAL EXCEPTION: main
AndroidRuntime: Process: com.xxx.app, PID: 25339
AndroidRuntime: java.lang.SecurityException: Not allowed to delete channel XXX with a foreground service
AndroidRuntime: at android.os.Parcel.createExceptionOrNull(Parcel.java:2376)
AndroidRuntime: at android.os.Parcel.createException(Parcel.java:2360)
AndroidRuntime: at android.os.Parcel.readException(Parcel.java:2343)
AndroidRuntime: at android.os.Parcel.readException(Parcel.java:2285)
AndroidRuntime: at android.app.INotificationManager$Stub$Proxy.deleteNotificationChannel(INotificationManager.java:4040)
AndroidRuntime: at android.app.NotificationManager.deleteNotificationChannel(NotificationManager.java:909)
AndroidRuntime: at androidx.core.app.NotificationManagerCompat.deleteNotificationChannel(SourceFile:2)
AndroidRuntime: at com.gyf.cactus.ext.c$a.run(SourceFile:1)
AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:938)
AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:99)
AndroidRuntime: at android.os.Looper.loop(Looper.java:236)
AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:8142)
AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
AndroidRuntime: Caused by: android.os.RemoteException: Remote stack trace:
AndroidRuntime: at com.android.server.notification.NotificationManagerService$10.enforceDeletingChannelHasNoFgService(NotificationManagerService.java:3427)
AndroidRuntime: at com.android.server.notification.NotificationManagerService$10.deleteNotificationChannel(NotificationManagerService.java:3440)
AndroidRuntime: at android.app.INotificationManager$Stub.onTransact(INotificationManager.java:1737)
AndroidRuntime: at android.os.Binder.execTransactInternal(Binder.java:1160)
AndroidRuntime: at android.os.Binder.execTransact(Binder.java:1129)
//获取预览窗口的宽高privatefinal TextureView.SurfaceTextureListener mSurfaceTextureListener
= new TextureView.SurfaceTextureListener() {
@Override
publicvoidonSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
openCamera(width, height);
}
@Override
publicvoidonSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
configureTransform(width, height);
}
@Override
publicbooleanonSurfaceTextureDestroyed(SurfaceTexture texture) {
returntrue;
}
@Override
publicvoidonSurfaceTextureUpdated(SurfaceTexture texture) {
}
};
//得到最佳Camera图像输出尺寸privatestatic Size chooseOptimalSize(Size[] choices, int textureViewWidth,
int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
// Collect the supported resolutions that are at least as big as the preview Surface
List<Size> bigEnough = new ArrayList<>();
// Collect the supported resolutions that are smaller than the preview Surface
List<Size> notBigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
option.getHeight() == option.getWidth() * h / w) {
if (option.getWidth() >= textureViewWidth &&
option.getHeight() >= textureViewHeight) {
bigEnough.add(option);
} else {
notBigEnough.add(option);
}
}
}
// Pick the smallest of those big enough. If there is no one big enough, pick the// largest of those not big enough.if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizesByArea());
} elseif (notBigEnough.size() > 0) {
return Collections.max(notBigEnough, new CompareSizesByArea());
} else {
Log.e(TAG, "Couldn't find any suitable preview size");
return choices[0];
}
}