diff --git a/app/src/main/java/com/haodustudio/DailyNotes/utils/BitmapUtils.kt b/app/src/main/java/com/haodustudio/DailyNotes/utils/BitmapUtils.kt
index 0f61568..be7352a 100644
--- a/app/src/main/java/com/haodustudio/DailyNotes/utils/BitmapUtils.kt
+++ b/app/src/main/java/com/haodustudio/DailyNotes/utils/BitmapUtils.kt
@@ -20,6 +20,70 @@ import java.io.InputStream
object BitmapUtils {
+
+ /**
+ * 安全地从资源中加载图片,自动计算采样率避免 OOM 和 Canvas 绘制过大 Bitmap 错误
+ * @param resId 图片资源ID
+ * @param reqWidth 需要的宽度(如果为0则不限制)
+ * @param reqHeight 需要的高度(如果为0则不限制)
+ * @return 采样后的 Bitmap,如果加载失败返回 null
+ */
+ fun decodeSampledBitmapFromResource(resId: Int, reqWidth: Int = 0, reqHeight: Int = 0): Bitmap? {
+ return try {
+ val options = BitmapFactory.Options().apply {
+ inJustDecodeBounds = true
+ }
+ BitmapFactory.decodeResource(BaseApplication.instance.resources, resId, options)
+
+ // 计算采样率
+ options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)
+
+ // 实际解码图片
+ options.inJustDecodeBounds = false
+ options.inPreferredConfig = Bitmap.Config.RGB_565 // 使用更少内存
+
+ BitmapFactory.decodeResource(BaseApplication.instance.resources, resId, options)
+ } catch (e: Exception) {
+ Log.e("BitmapUtils", "Failed to decode bitmap from resource: $resId", e)
+ null
+ }
+ }
+
+ /**
+ * 计算合适的采样率
+ */
+ private fun calculateInSampleSize(
+ options: BitmapFactory.Options,
+ reqWidth: Int,
+ reqHeight: Int
+ ): Int {
+ val height = options.outHeight
+ val width = options.outWidth
+ var inSampleSize = 1
+
+ // 如果没有指定需求尺寸,使用屏幕尺寸作为限制
+ val finalReqWidth = if (reqWidth <= 0) {
+ BaseApplication.instance.resources.displayMetrics.widthPixels
+ } else reqWidth
+
+ val finalReqHeight = if (reqHeight <= 0) {
+ BaseApplication.instance.resources.displayMetrics.heightPixels
+ } else reqHeight
+
+ if (height > finalReqHeight || width > finalReqWidth) {
+ val halfHeight = height / 2
+ val halfWidth = width / 2
+
+ // 计算最大的 inSampleSize 值,保证采样后的图片尺寸大于需求尺寸
+ while (halfHeight / inSampleSize >= finalReqHeight &&
+ halfWidth / inSampleSize >= finalReqWidth) {
+ inSampleSize *= 2
+ }
+ }
+
+ return inSampleSize
+ }
+
fun getImageFromAssetsFile(filePath: String): Bitmap {
val am: AssetManager = BaseApplication.instance.resources.assets
val mIs: InputStream = am.open(filePath)
diff --git a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/AboutSoftware.kt b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/AboutSoftware.kt
index 2fd0158..f274d8b 100644
--- a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/AboutSoftware.kt
+++ b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/AboutSoftware.kt
@@ -9,6 +9,7 @@ import com.haodustudio.DailyNotes.BaseApplication
import com.haodustudio.DailyNotes.R
import com.haodustudio.DailyNotes.databinding.ActivityAboutSoftwareBinding
import com.haodustudio.DailyNotes.helper.makeToast
+import com.haodustudio.DailyNotes.utils.BitmapUtils
import com.haodustudio.DailyNotes.view.activities.base.BaseActivity
import com.haodustudio.DailyNotes.view.activities.ViewImage
import com.haodustudio.DailyNotes.view.activities.PrivacySettingsActivity
@@ -20,10 +21,36 @@ class AboutSoftware : BaseActivity() {
super.onCreate(savedInstanceState)
setContentView(binding.root)
+ loadBannerImageSafely()
configureBanner()
configureCards()
}
+ private fun loadBannerImageSafely() {
+ try {
+ binding.bannerImage.post {
+ val viewWidth = binding.bannerImage.width
+ val viewHeight = binding.bannerImage.height
+
+ val bitmap = BitmapUtils.decodeSampledBitmapFromResource(
+ R.drawable.about_banner,
+ viewWidth,
+ viewHeight
+ )
+
+ if (bitmap != null) {
+ binding.bannerImage.setImageBitmap(bitmap)
+ } else {
+ // 如果加载失败,使用占位符
+ binding.bannerImage.setImageResource(android.R.color.darker_gray)
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ binding.bannerImage.setImageResource(android.R.color.darker_gray)
+ }
+ }
+
private fun configureBanner() {
binding.bannerBadge.text = getString(R.string.about_codename_label)
binding.bannerTitle.text = getString(R.string.about_banner_title)
diff --git a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/PrivacySettingsActivity.kt b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/PrivacySettingsActivity.kt
index 5c2f067..c9124f6 100644
--- a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/PrivacySettingsActivity.kt
+++ b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/PrivacySettingsActivity.kt
@@ -12,6 +12,7 @@ import com.haodustudio.DailyNotes.R
import com.haodustudio.DailyNotes.databinding.ActivityPrivacySettingsBinding
import com.haodustudio.DailyNotes.helper.PrivacySettingsManager
import com.haodustudio.DailyNotes.helper.makeToast
+import com.haodustudio.DailyNotes.utils.BitmapUtils
import com.haodustudio.DailyNotes.view.activities.base.BaseActivity
class PrivacySettingsActivity : BaseActivity() {
@@ -22,10 +23,32 @@ class PrivacySettingsActivity : BaseActivity() {
super.onCreate(savedInstanceState)
setContentView(binding.root)
+ loadBannerImageSafely()
setupListeners()
refreshIndicators()
}
+ private fun loadBannerImageSafely() {
+ try {
+ binding.privacyBannerImage.post {
+ val viewWidth = binding.privacyBannerImage.width
+ val viewHeight = binding.privacyBannerImage.height
+
+ val bitmap = BitmapUtils.decodeSampledBitmapFromResource(
+ R.drawable.privacy_banner,
+ viewWidth,
+ viewHeight
+ )
+
+ bitmap?.let {
+ binding.privacyBannerImage.setImageBitmap(it)
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+
private fun setupListeners() {
binding.privacyCardCrash.setOnClickListener {
handleSettingClick(PrivacySetting.CRASH_REPORTING)
diff --git a/app/src/main/res/drawable/about_banner.jpg b/app/src/main/res/drawable/about_banner.jpg
new file mode 100644
index 0000000..72d9b08
Binary files /dev/null and b/app/src/main/res/drawable/about_banner.jpg differ
diff --git a/app/src/main/res/drawable/about_banner.png b/app/src/main/res/drawable/about_banner.png
deleted file mode 100644
index ddf5c48..0000000
Binary files a/app/src/main/res/drawable/about_banner.png and /dev/null differ
diff --git a/app/src/main/res/layout/activity_about_software.xml b/app/src/main/res/layout/activity_about_software.xml
index 9e82ca0..e875d30 100644
--- a/app/src/main/res/layout/activity_about_software.xml
+++ b/app/src/main/res/layout/activity_about_software.xml
@@ -62,7 +62,6 @@
android:adjustViewBounds="true"
android:contentDescription="@string/about_banner_content_description"
android:scaleType="centerCrop"
- android:src="@drawable/about_banner"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
diff --git a/app/src/main/res/layout/activity_privacy_settings.xml b/app/src/main/res/layout/activity_privacy_settings.xml
index de05cce..84d8a21 100644
--- a/app/src/main/res/layout/activity_privacy_settings.xml
+++ b/app/src/main/res/layout/activity_privacy_settings.xml
@@ -56,8 +56,7 @@
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:contentDescription="@string/privacy_banner_content_desc"
- android:scaleType="centerCrop"
- android:src="@drawable/privacy_banner" />
+ android:scaleType="centerCrop" />
diff --git a/app/src/main/res/layout/dialog_privacy_confirmation.xml b/app/src/main/res/layout/dialog_privacy_confirmation.xml
index 93e46f8..14b3e43 100644
--- a/app/src/main/res/layout/dialog_privacy_confirmation.xml
+++ b/app/src/main/res/layout/dialog_privacy_confirmation.xml
@@ -66,7 +66,8 @@
android:layout_height="48dp"
android:background="@drawable/bg_privacy_dialog_button_cancel"
android:contentDescription="@string/privacy_confirm_cancel"
- android:padding="14dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
android:src="@drawable/privacy_dialog_close" />