Compare commits

...

9 Commits

14 changed files with 856 additions and 305 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Sun Dec 21 19:13:50 HKT 2025
stageCount=18
#Mon Dec 22 10:25:46 HKT 2025
stageCount=21
libraryProject=
baseVersion=15.14
publishVersion=15.14.17
publishVersion=15.14.20
buildCount=0
baseBetaVersion=15.14.18
baseBetaVersion=15.14.21

View File

@@ -288,6 +288,8 @@
</activity>
<activity android:name="cc.winboll.studio.powerbell.unittest.MainUnitTest2Activity"/>
</application>
</manifest>

View File

@@ -15,6 +15,7 @@ import cc.winboll.studio.powerbell.utils.AppCacheUtils;
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.BitmapCacheUtils;
import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
import cc.winboll.studio.powerbell.views.MemoryCachedBackgroundView;
import java.io.File;
import java.util.concurrent.TimeUnit;
@@ -40,7 +41,7 @@ public class App extends GlobalApplication {
private static final String TRIM_MEMORY_NOTIFY_CONTENT = "由于本应用使用时,系统通知内存紧张程度级别较高,图片缓存功能暂时不启用。";
// 定时任务间隔常量(分钟)
private static final long TIMER_INTERVAL_MINUTES = 1;
//private static final long TIMER_INTERVAL_MINUTES = 1;
// ===================== 静态属性区 =====================
// 数据配置工具
@@ -48,14 +49,16 @@ public class App extends GlobalApplication {
private static AppCacheUtils sAppCacheUtils;
// 全局Bitmap缓存工具
public static BitmapCacheUtils sBitmapCacheUtils;
// 全局视图控件缓存工具
public static MemoryCachedBackgroundView sMemoryCachedBackgroundView;
// 临时文件夹路径
private static String sTempDirPath = "";
// 定时任务静态属性(全局唯一)
private static Handler sTimerHandler;
private static Runnable sTimerRunnable;
private static boolean sIsTimerRunning = false;
// private static Handler sTimerHandler;
// private static Runnable sTimerRunnable;
// private static boolean sIsTimerRunning = false;
//
// ===================== 成员属性区 =====================
// 全局广播接收器
private GlobalApplicationReceiver mGlobalReceiver;
@@ -121,7 +124,7 @@ public class App extends GlobalApplication {
// 初始化广播接收器
initReceiver();
// 启动定时任务
initTimerTask();
//initTimerTask();
LogUtils.d(TAG, "onCreate() 应用初始化完成");
}
@@ -136,7 +139,7 @@ public class App extends GlobalApplication {
// 释放通知工具
releaseNotificationManager();
// 停止定时任务
stopTimerTask();
//stopTimerTask();
LogUtils.d(TAG, "onTerminate() 应用资源释放完成");
}
@@ -145,20 +148,24 @@ public class App extends GlobalApplication {
public void onTrimMemory(int level) {
super.onTrimMemory(level);
LogUtils.d(TAG, "onTrimMemory() 调用内存等级level" + level);
// 初始化通知工具(若未初始化)
if (mNotificationManager == null) {
mNotificationManager = new NotificationManagerUtils(this);
LogUtils.d(TAG, "onTrimMemory()NotificationManagerUtils实例已初始化");
}
// 内存紧张等级判断
if (level > ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
sendTrimMemoryNotification(level);
} else {
sBitmapCacheUtils = BitmapCacheUtils.getInstance();
LogUtils.d(TAG, "onTrimMemory()Bitmap缓存已启用");
}
sMemoryCachedBackgroundView.clearAllCache();
sBitmapCacheUtils.clearAllCache();
sBitmapCacheUtils = BitmapCacheUtils.getInstance();
sMemoryCachedBackgroundView.getLastInstance(this);
//
// // 初始化通知工具(若未初始化)
// if (mNotificationManager == null) {
// mNotificationManager = new NotificationManagerUtils(this);
// LogUtils.d(TAG, "onTrimMemory()NotificationManagerUtils实例已初始化");
// }
//
// // 内存紧张等级判断
// if (level > ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
// sendTrimMemoryNotification(level);
// } else {
// sBitmapCacheUtils = BitmapCacheUtils.getInstance();
// LogUtils.d(TAG, "onTrimMemory()Bitmap缓存已启用");
// }
}
// ===================== 私有初始化方法区 =====================
@@ -212,65 +219,65 @@ public class App extends GlobalApplication {
/**
* 初始化定时任务(全局唯一实例)
*/
private void initTimerTask() {
LogUtils.d(TAG, "initTimerTask() 开始初始化定时任务,当前运行状态:" + sIsTimerRunning);
// 已运行则直接返回
if (sIsTimerRunning) {
LogUtils.d(TAG, "initTimerTask() 定时任务已在运行,无需重复启动");
return;
}
// 初始化Handler
if (sTimerHandler == null) {
sTimerHandler = new Handler(Looper.getMainLooper());
LogUtils.d(TAG, "initTimerTask() 定时任务Handler已初始化");
}
// 初始化Runnable
if (sTimerRunnable == null) {
sTimerRunnable = new Runnable() {
@Override
public void run() {
try {
LogUtils.d(TAG, "定时任务执行,间隔:" + TIMER_INTERVAL_MINUTES + "分钟");
sBitmapCacheUtils = BitmapCacheUtils.getInstance();
LogUtils.d(TAG, "定时任务Bitmap缓存已重新初始化");
} catch (Exception e) {
LogUtils.e(TAG, "定时任务执行异常:" + e.getMessage());
} finally {
if (sIsTimerRunning) {
long delayMillis = TimeUnit.MINUTES.toMillis(TIMER_INTERVAL_MINUTES);
sTimerHandler.postDelayed(this, delayMillis);
LogUtils.d(TAG, "定时任务已预约下次执行,延迟:" + delayMillis + "ms");
}
}
}
};
LogUtils.d(TAG, "initTimerTask() 定时任务Runnable已初始化");
}
// 启动任务
sTimerHandler.post(sTimerRunnable);
sIsTimerRunning = true;
LogUtils.d(TAG, "initTimerTask() 定时任务已启动,间隔:" + TIMER_INTERVAL_MINUTES + "分钟");
}
// private void initTimerTask() {
// LogUtils.d(TAG, "initTimerTask() 开始初始化定时任务,当前运行状态:" + sIsTimerRunning);
//
// // 已运行则直接返回
// if (sIsTimerRunning) {
// LogUtils.d(TAG, "initTimerTask() 定时任务已在运行,无需重复启动");
// return;
// }
//
// // 初始化Handler
// if (sTimerHandler == null) {
// sTimerHandler = new Handler(Looper.getMainLooper());
// LogUtils.d(TAG, "initTimerTask() 定时任务Handler已初始化");
// }
//
// // 初始化Runnable
// if (sTimerRunnable == null) {
// sTimerRunnable = new Runnable() {
// @Override
// public void run() {
// try {
// LogUtils.d(TAG, "定时任务执行,间隔:" + TIMER_INTERVAL_MINUTES + "分钟");
// sBitmapCacheUtils = BitmapCacheUtils.getInstance();
// LogUtils.d(TAG, "定时任务Bitmap缓存已重新初始化");
// } catch (Exception e) {
// LogUtils.e(TAG, "定时任务执行异常:" + e.getMessage());
// } finally {
// if (sIsTimerRunning) {
// long delayMillis = TimeUnit.MINUTES.toMillis(TIMER_INTERVAL_MINUTES);
// sTimerHandler.postDelayed(this, delayMillis);
// LogUtils.d(TAG, "定时任务已预约下次执行,延迟:" + delayMillis + "ms");
// }
// }
// }
// };
// LogUtils.d(TAG, "initTimerTask() 定时任务Runnable已初始化");
// }
//
// // 启动任务
// sTimerHandler.post(sTimerRunnable);
// sIsTimerRunning = true;
// LogUtils.d(TAG, "initTimerTask() 定时任务已启动,间隔:" + TIMER_INTERVAL_MINUTES + "分钟");
// }
// ===================== 私有工具方法区 =====================
/**
* 停止定时任务
*/
private void stopTimerTask() {
LogUtils.d(TAG, "stopTimerTask() 开始停止定时任务");
if (sTimerHandler != null && sTimerRunnable != null) {
sTimerHandler.removeCallbacks(sTimerRunnable);
sIsTimerRunning = false;
LogUtils.d(TAG, "stopTimerTask() 定时任务已停止运行状态重置为false");
} else {
LogUtils.d(TAG, "stopTimerTask() 定时任务未初始化,无需停止");
}
}
// private void stopTimerTask() {
// LogUtils.d(TAG, "stopTimerTask() 开始停止定时任务");
// if (sTimerHandler != null && sTimerRunnable != null) {
// sTimerHandler.removeCallbacks(sTimerRunnable);
// sIsTimerRunning = false;
// LogUtils.d(TAG, "stopTimerTask() 定时任务已停止运行状态重置为false");
// } else {
// LogUtils.d(TAG, "stopTimerTask() 定时任务未初始化,无需停止");
// }
// }
//
/**
* 释放通知管理工具资源
*/

View File

@@ -12,6 +12,7 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewStub;
import android.widget.LinearLayout;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libaes.activitys.AboutActivity;
import cc.winboll.studio.libaes.models.APPInfo;
@@ -28,6 +29,7 @@ import cc.winboll.studio.powerbell.activities.WinBoLLActivity;
import cc.winboll.studio.powerbell.models.BackgroundBean;
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
import cc.winboll.studio.powerbell.services.ControlCenterService;
import cc.winboll.studio.powerbell.unittest.MainUnitTest2Activity;
import cc.winboll.studio.powerbell.unittest.MainUnitTestActivity;
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
@@ -210,6 +212,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
break;
case R.id.action_unittestactivity:
startActivity(new Intent(this, MainUnitTestActivity.class));
break;
case R.id.action_unittest2activity:
startActivity(new Intent(this, MainUnitTest2Activity.class));
break;
case R.id.action_about:
startAboutActivity();
@@ -402,7 +407,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) {
mMainContentView.backgroundView.loadBackgroundBean(currentBgBean);
mMainContentView.backgroundView.loadByBackgroundBean(currentBgBean);
} else {
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
}

View File

@@ -402,7 +402,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
try {
mBgSourceUtils.loadSettings();
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
mBackgroundView.loadBackgroundBean(previewBean, true);
mBackgroundView.loadByBackgroundBean(previewBean, true);
mBackgroundView.setBackgroundColor(previewBean.getPixelColor());
LogUtils.d(TAG, "【双重刷新】第一重完成");
} catch (Exception e) {
@@ -418,7 +418,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
try {
mBgSourceUtils.loadSettings();
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
mBackgroundView.loadBackgroundBean(previewBean, true);
mBackgroundView.loadByBackgroundBean(previewBean, true);
mBackgroundView.setBackgroundColor(previewBean.getPixelColor());
LogUtils.d(TAG, "【双重刷新】第二重完成");
} catch (Exception e) {

View File

@@ -208,7 +208,7 @@ public class NetworkBackgroundDialog extends AlertDialog {
mPreviewFilePath = previewFilePath;
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(mContext);
utils.saveFileToPreviewBean(new File(mPreviewFilePath), mPreviewFileUrl);
mBackgroundView.loadBackgroundBean(utils.getPreviewBackgroundBean());
mBackgroundView.loadByBackgroundBean(utils.getPreviewBackgroundBean());
} catch (Exception e) {
e.printStackTrace();
mBackgroundView.setBackgroundResource(R.drawable.ic_launcher);

View File

@@ -0,0 +1,257 @@
package cc.winboll.studio.powerbell.unittest;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import androidx.appcompat.app.AppCompatActivity;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.models.BackgroundBean;
import cc.winboll.studio.powerbell.utils.FileUtils;
import cc.winboll.studio.powerbell.utils.ImageCropUtils;
import cc.winboll.studio.powerbell.views.BackgroundView;
import cc.winboll.studio.powerbell.views.MemoryCachedBackgroundView;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/22 08:31
* @Describe MainUnitTest2Activity
*/
public class MainUnitTest2Activity extends AppCompatActivity {
// ====================== 常量定义 ======================
public static final String TAG = "MainUnitTest2Activity";
public static final int REQUEST_CROP_IMAGE = 0;
private static final String ASSETS_TEST_IMAGE_PATH = "unittest/unittest-miku.png";
// ====================== 成员变量移除所有Uri相关 ======================
private MemoryCachedBackgroundView mMemoryCachedBackgroundView;
private String mAppPrivateDirPath;
private File mPrivateTestImageFile; // 仅用File不用Uri
private File mPrivateCropImageFile;
BackgroundBean mPreviewBackgroundBean;
LinearLayout mllBackgroundView;
// ====================== 生命周期方法 ======================
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LogUtils.d(TAG, "=== 页面 onCreate 启动 ===");
initBaseParams();
initViewAndEvent();
copyAssetsTestImageToPrivateDir();
//loadBackgroundByFile(); // 直接用File加载
mPreviewBackgroundBean = new BackgroundBean();
mPreviewBackgroundBean.setBackgroundFileName(mPrivateTestImageFile.getName());
mPreviewBackgroundBean.setBackgroundFilePath(mPrivateTestImageFile.getAbsolutePath());
mPreviewBackgroundBean.setBackgroundScaledCompressFileName(mPrivateCropImageFile.getName());
mPreviewBackgroundBean.setBackgroundScaledCompressFilePath(mPrivateCropImageFile.getAbsolutePath());
mPreviewBackgroundBean.setIsUseBackgroundFile(true);
doubleRefreshPreview();
ToastUtils.show("单元测试页面启动完成");
LogUtils.d(TAG, "=== 页面 onCreate 初始化结束 ===");
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
LogUtils.d(TAG, "=== onActivityResult 回调 ===");
if (requestCode == REQUEST_CROP_IMAGE) {
handleCropResult(resultCode);
}
}
// ====================== 初始化相关方法 ======================
private void initBaseParams() {
LogUtils.d(TAG, "初始化基础参数:工具类+私有目录+File");
// 私有目录无需权限无UID冲突
mAppPrivateDirPath = getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath() + "/PowerBellTest/";
File privateDir = new File(mAppPrivateDirPath);
if (!privateDir.exists()) {
privateDir.mkdirs();
LogUtils.d(TAG, "创建私有目录:" + mAppPrivateDirPath);
}
// 初始化File无Uri
File refFile = new File(ASSETS_TEST_IMAGE_PATH);
String uniqueTestName = FileUtils.createUniqueFileName(refFile) + ".png";
String uniqueCropName = uniqueTestName.replace(".png", "_crop.png");
mPrivateTestImageFile = new File(mAppPrivateDirPath, uniqueTestName);
mPrivateCropImageFile = new File(mAppPrivateDirPath, uniqueCropName);
LogUtils.d(TAG, "测试图File路径" + mPrivateTestImageFile.getAbsolutePath());
}
private void initViewAndEvent() {
LogUtils.d(TAG, "初始化布局与控件事件");
setContentView(R.layout.activity_mainunittest2);
mllBackgroundView = (LinearLayout) findViewById(R.id.ll_backgroundview);
mMemoryCachedBackgroundView = MemoryCachedBackgroundView.getInstance(this, "", false);
mllBackgroundView.addView(mMemoryCachedBackgroundView);
//mMemoryCachedBackgroundView = (BackgroundView) findViewById(R.id.backgroundview);
// 跳转主页面按钮
Button btnMain = (Button) findViewById(R.id.btn_main_activity);
btnMain.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LogUtils.d(TAG, "点击按钮:跳转主页面");
startActivity(new Intent(MainUnitTest2Activity.this, MainActivity.class));
}
});
// 裁剪按钮直接用File路径启动无Uri
Button btnCrop = (Button) findViewById(R.id.btn_test_cropimage);
btnCrop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LogUtils.d(TAG, "点击按钮启动裁剪File路径版");
ToastUtils.show("准备启动图片裁剪");
if (mPrivateTestImageFile.exists() && mPrivateTestImageFile.length() > 100) {
startCropTestByFile(); // 直接传File
} else {
ToastUtils.show("测试图片未准备好,重新拷贝");
copyAssetsTestImageToPrivateDir();
}
}
});
}
// 从assets拷贝图片不变确保File存在
private void copyAssetsTestImageToPrivateDir() {
LogUtils.d(TAG, "开始拷贝assets图片到私有目录");
if (mPrivateTestImageFile.exists() && mPrivateTestImageFile.length() > 100) {
LogUtils.d(TAG, "图片已存在,无需拷贝");
return;
}
InputStream inputStream = null;
try {
inputStream = getAssets().open(ASSETS_TEST_IMAGE_PATH);
FileUtils.copyStreamToFile(inputStream, mPrivateTestImageFile);
LogUtils.d(TAG, "图片拷贝成功,大小:" + mPrivateTestImageFile.length() + "字节");
} catch (IOException e) {
LogUtils.e(TAG, "图片拷贝失败:" + e.getMessage(), e);
ToastUtils.show("图片准备失败");
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
LogUtils.e(TAG, "关闭流失败:" + e.getMessage());
}
}
}
}
// ====================== 核心业务方法全改为File路径 ======================
/** 直接用File路径加载背景图无Uri无冲突 */
// private void loadBackgroundByFile() {
// LogUtils.d(TAG, "开始加载背景图File路径版");
// if (mPrivateTestImageFile.exists() && mPrivateTestImageFile.length() > 100) {
// mBackgroundView.loadImage(mPrivateTestImageFile.getAbsolutePath()); // 直接传路径
// LogUtils.d(TAG, "背景图加载成功:" + mPrivateTestImageFile.getAbsolutePath());
// ToastUtils.show("背景图加载成功");
// } else {
// LogUtils.e(TAG, "背景图加载失败:文件无效");
// ToastUtils.show("背景图加载失败");
// }
// }
/** 直接用File启动裁剪关键调用ImageCropUtils的File重载方法 */
private void startCropTestByFile() {
LogUtils.d(TAG, "启动裁剪File路径版原图" + mPrivateTestImageFile.getAbsolutePath());
// 确保输出目录存在
File cropParent = mPrivateCropImageFile.getParentFile();
if (!cropParent.exists()) {
cropParent.mkdirs();
}
// 调用ImageCropUtils的File参数方法核心绕开Uri
ImageCropUtils.startImageCrop(
this,
mPrivateTestImageFile, // 原图File
mPrivateCropImageFile, // 输出File
0,
0,
true,
REQUEST_CROP_IMAGE
);
LogUtils.d(TAG, "裁剪请求已发送,输出路径:" + mPrivateCropImageFile.getAbsolutePath());
ToastUtils.show("已启动图片裁剪");
}
/** 处理裁剪结果直接校验输出File */
private void handleCropResult(int resultCode) {
LogUtils.d(TAG, "裁剪回调处理resultCode=" + resultCode);
if (resultCode == RESULT_OK) {
if (mPrivateCropImageFile.exists() && mPrivateCropImageFile.length() > 100) {
mMemoryCachedBackgroundView.loadImage(mPrivateCropImageFile.getAbsolutePath());
LogUtils.d(TAG, "裁剪成功,加载裁剪图:" + mPrivateCropImageFile.getAbsolutePath());
ToastUtils.show("裁剪成功");
mPreviewBackgroundBean.setIsUseBackgroundScaledCompressFile(true);
doubleRefreshPreview();
} else {
LogUtils.e(TAG, "裁剪成功但输出文件无效");
ToastUtils.show("裁剪失败:输出文件无效");
}
} else if (resultCode == RESULT_CANCELED) {
LogUtils.d(TAG, "裁剪取消");
ToastUtils.show("裁剪已取消");
} else {
LogUtils.e(TAG, "裁剪失败resultCode异常");
ToastUtils.show("裁剪失败");
}
}
/**
* 双重刷新预览,确保背景加载最新数据
* 移除:缓存清空逻辑
*/
private void doubleRefreshPreview() {
// 第一重刷新
try {
mMemoryCachedBackgroundView.loadByBackgroundBean(mPreviewBackgroundBean, true);
mMemoryCachedBackgroundView.setBackgroundColor(mPreviewBackgroundBean.getPixelColor());
LogUtils.d(TAG, "【双重刷新】第一重完成");
} catch (Exception e) {
LogUtils.e(TAG, "【双重刷新】第一重异常:" + e.getMessage());
return;
}
// 第二重刷新(延迟执行)
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
if (mMemoryCachedBackgroundView != null && !isFinishing()) {
try {
mMemoryCachedBackgroundView.loadByBackgroundBean(mPreviewBackgroundBean, true);
mMemoryCachedBackgroundView.setBackgroundColor(mPreviewBackgroundBean.getPixelColor());
LogUtils.d(TAG, "【双重刷新】第二重完成");
} catch (Exception e) {
LogUtils.e(TAG, "【双重刷新】第二重异常:" + e.getMessage());
}
}
}
}, 200);
}
}

View File

@@ -221,7 +221,7 @@ public class MainUnitTestActivity extends AppCompatActivity {
// 第一重刷新
try {
mBackgroundView.loadBackgroundBean(mPreviewBackgroundBean, true);
mBackgroundView.loadByBackgroundBean(mPreviewBackgroundBean, true);
mBackgroundView.setBackgroundColor(mPreviewBackgroundBean.getPixelColor());
LogUtils.d(TAG, "【双重刷新】第一重完成");
} catch (Exception e) {
@@ -235,7 +235,7 @@ public class MainUnitTestActivity extends AppCompatActivity {
public void run() {
if (mBackgroundView != null && !isFinishing()) {
try {
mBackgroundView.loadBackgroundBean(mPreviewBackgroundBean, true);
mBackgroundView.loadByBackgroundBean(mPreviewBackgroundBean, true);
mBackgroundView.setBackgroundColor(mPreviewBackgroundBean.getPixelColor());
LogUtils.d(TAG, "【双重刷新】第二重完成");
} catch (Exception e) {

View File

@@ -104,11 +104,11 @@ public class BackgroundView extends RelativeLayout {
LogUtils.d(TAG, "=== initImageView 完成 ===");
}
public void loadBackgroundBean(BackgroundBean bean) {
loadBackgroundBean(bean, false);
public void loadByBackgroundBean(BackgroundBean bean) {
loadByBackgroundBean(bean, false);
}
public void loadBackgroundBean(BackgroundBean bean, boolean isRefresh) {
public void loadByBackgroundBean(BackgroundBean bean, boolean isRefresh) {
if (!bean.isUseBackgroundFile()) {
setDefaultTransparentBackground();
return;
@@ -149,7 +149,7 @@ public class BackgroundView extends RelativeLayout {
return;
}
//mIvBackground.setVisibility(View.GONE);
mIvBackground.setVisibility(View.GONE);
// ======================== 新增:路径判断逻辑 ========================
// 1. 路径未变化:直接使用缓存
@@ -269,7 +269,7 @@ public class BackgroundView extends RelativeLayout {
params.height = ivHeight;
mIvBackground.setLayoutParams(params);
mIvBackground.setScaleType(ScaleType.FIT_CENTER);
//mIvBackground.setVisibility(View.VISIBLE);
mIvBackground.setVisibility(View.VISIBLE);
}
}

View File

@@ -7,6 +7,7 @@ import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -14,6 +15,7 @@ import android.widget.RelativeLayout;
import android.widget.Switch;
import android.widget.TextView;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
import cc.winboll.studio.powerbell.services.ControlCenterService;
@@ -81,7 +83,8 @@ public class MainContentView {
// 视图控件(按「布局→开关→文本→进度条→图标」功能归类)
// 基础布局控件
public RelativeLayout mainLayout;
public BackgroundView backgroundView;
public MemoryCachedBackgroundView backgroundView;
LinearLayout mllBackgroundView;
// 容器布局控件
public LinearLayout llLeftSeekBar;
public LinearLayout llRightSeekBar;
@@ -144,7 +147,13 @@ public class MainContentView {
LogUtils.d(TAG, "bindViews() | rootView=" + rootView);
// 基础布局绑定
mainLayout = (RelativeLayout) rootView.findViewById(R.id.activitymainRelativeLayout1);
backgroundView = (BackgroundView) rootView.findViewById(R.id.fragmentmainviewBackgroundView1);
//backgroundView = (BackgroundView) rootView.findViewById(R.id.fragmentmainviewBackgroundView1);
mllBackgroundView = (LinearLayout) rootView.findViewById(R.id.ll_backgroundview);
backgroundView = App.sMemoryCachedBackgroundView.getLastInstance(mContext);
if (backgroundView.getParent() != null) {
((ViewGroup) backgroundView.getParent()).removeView(backgroundView);
}
mllBackgroundView.addView(backgroundView);
// 容器布局绑定
llLeftSeekBar = (LinearLayout) rootView.findViewById(R.id.fragmentmainviewLinearLayout1);
llRightSeekBar = (LinearLayout) rootView.findViewById(R.id.fragmentmainviewLinearLayout2);

View File

@@ -0,0 +1,229 @@
package cc.winboll.studio.powerbell.views;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.AttributeSet;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.models.BackgroundBean;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/21 20:43
* @Describe 单实例缓存版背景视图控件基于Java7
* 核心:通过静态属性保存当前缓存路径和实例,支持强制重载图片
* 新增SP持久化最后加载路径、获取最后加载实例功能
*/
public class MemoryCachedBackgroundView extends BackgroundView {
public static final String TAG = "MemoryCachedBackgroundView";
// 静态属性保存当前缓存的路径和实例替代原Map仅维护单实例
private static String sCachedImagePath;
private static MemoryCachedBackgroundView sCachedView;
// SP相关常量
private static final String SP_NAME = "MemoryCachedBackgroundView_SP";
private static final String KEY_LAST_LOAD_IMAGE_PATH = "last_load_image_path";
// ====================================== 构造器(继承并兼容父类) ======================================
private MemoryCachedBackgroundView(Context context) {
super(context);
LogUtils.d(TAG, "构造器1创建MemoryCachedBackgroundView实例");
}
private MemoryCachedBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
LogUtils.d(TAG, "构造器2创建MemoryCachedBackgroundView实例");
}
private MemoryCachedBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
LogUtils.d(TAG, "构造器3创建MemoryCachedBackgroundView实例");
}
// ====================================== 核心静态方法:获取/创建缓存实例 ======================================
/**
* 从缓存获取或创建MemoryCachedBackgroundView实例
* @param context 上下文
* @param imagePath 图片绝对路径(作为缓存标识)
* @param isReload 是否强制重新加载图片(路径匹配时仍刷新)
* @return 缓存/新创建的MemoryCachedBackgroundView实例
*/
public static MemoryCachedBackgroundView getInstance(Context context, String imagePath, boolean isReload) {
LogUtils.d(TAG, "getInstance() 调用 | 图片路径:" + imagePath + " | 是否重载:" + isReload);
if (TextUtils.isEmpty(imagePath)) {
LogUtils.e(TAG, "getInstance():图片路径为空,创建空实例");
return new MemoryCachedBackgroundView(context);
}
// 1. 路径匹配缓存 → 判断是否强制重载
if (imagePath.equals(sCachedImagePath) && sCachedView != null) {
LogUtils.d(TAG, "getInstance():路径已缓存,当前缓存实例有效");
if (isReload) {
LogUtils.d(TAG, "getInstance():强制重载图片 | " + imagePath);
sCachedView.loadImage(imagePath);
} else {
LogUtils.d(TAG, "getInstance():使用缓存实例,无需重载 | " + imagePath);
}
return sCachedView;
}
// 2. 路径不匹配/无缓存 → 新建实例并更新静态缓存
LogUtils.d(TAG, "getInstance():路径未缓存,新建实例 | " + imagePath);
sCachedView = new MemoryCachedBackgroundView(context);
sCachedImagePath = imagePath;
sCachedView.loadImage(imagePath);
return sCachedView;
}
// ====================================== 新增功能:获取最后加载的实例 ======================================
/**
* 获取最后一次loadImage的路径对应的实例
* 无实例则创建并加载图片,同时更新静态缓存
* @param context 上下文
* @return 最后加载路径对应的实例
*/
public static MemoryCachedBackgroundView getLastInstance(Context context) {
LogUtils.d(TAG, "getLastInstance() 调用");
// 1. 从SP获取最后加载的路径
String lastPath = getLastLoadImagePath(context);
if (TextUtils.isEmpty(lastPath)) {
LogUtils.e(TAG, "getLastInstance():无最后加载路径,创建空实例");
return new MemoryCachedBackgroundView(context);
}
// 2. 路径匹配当前缓存 → 直接返回
if (lastPath.equals(sCachedImagePath) && sCachedView != null) {
LogUtils.d(TAG, "getLastInstance():使用最后路径缓存实例 | " + lastPath);
return sCachedView;
}
// 3. 路径不匹配 → 新建实例并更新缓存
LogUtils.d(TAG, "getLastInstance():最后路径未缓存,新建实例并加载 | " + lastPath);
sCachedView = new MemoryCachedBackgroundView(context);
sCachedImagePath = lastPath;
sCachedView.loadImage(lastPath);
return sCachedView;
}
// ====================================== 工具方法SP持久化最后加载路径 ======================================
/**
* 保存最后一次loadImage的路径到SP
* @param context 上下文
* @param imagePath 图片路径
*/
private static void saveLastLoadImagePath(Context context, String imagePath) {
if (TextUtils.isEmpty(imagePath) || context == null) {
return;
}
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
sp.edit().putString(KEY_LAST_LOAD_IMAGE_PATH, imagePath).apply();
LogUtils.d(TAG, "saveLastLoadImagePath():已保存最后路径 | " + imagePath);
}
/**
* 从SP获取最后一次loadImage的路径
* @param context 上下文
* @return 最后加载的图片路径空则返回null
*/
public static String getLastLoadImagePath(Context context) {
if (context == null) {
return null;
}
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
String lastPath = sp.getString(KEY_LAST_LOAD_IMAGE_PATH, null);
LogUtils.d(TAG, "getLastLoadImagePath():获取最后路径 | " + lastPath);
return lastPath;
}
// ====================================== 工具方法:缓存管理 ======================================
/**
* 清除当前缓存实例和路径
*/
public static void clearCache() {
LogUtils.d(TAG, "clearCache() 调用 | 当前缓存路径:" + sCachedImagePath);
sCachedView = null;
sCachedImagePath = null;
LogUtils.d(TAG, "clearCache():已清除当前缓存实例");
}
/**
* 清除指定路径的缓存(仅当路径匹配当前缓存时生效)
* @param imagePath 图片路径
*/
public static void removeCache(String imagePath) {
LogUtils.d(TAG, "removeCache() 调用 | 图片路径:" + imagePath);
if (TextUtils.isEmpty(imagePath)) {
LogUtils.e(TAG, "removeCache():图片路径为空,清除失败");
return;
}
if (imagePath.equals(sCachedImagePath)) {
clearCache();
// 同步删除SP中最后路径记录
clearLastLoadImagePath(getContextFromCache());
LogUtils.d(TAG, "removeCache():已清除匹配路径的缓存 | " + imagePath);
} else {
LogUtils.d(TAG, "removeCache():路径不匹配当前缓存,无需清除 | " + imagePath);
}
}
/**
* 清除所有缓存同clearCache保持方法兼容性
*/
public static void clearAllCache() {
LogUtils.d(TAG, "clearAllCache() 调用");
clearCache();
clearLastLoadImagePath(getContextFromCache());
LogUtils.d(TAG, "clearAllCache():已清除所有缓存及最后路径记录");
}
/**
* 判断是否存在缓存实例
* @return 存在返回true否则返回false
*/
public static boolean hasCache() {
return sCachedView != null && !TextUtils.isEmpty(sCachedImagePath);
}
/**
* 清除SP中最后加载的路径记录
* @param context 上下文
*/
public static void clearLastLoadImagePath(Context context) {
if (context == null) {
return;
}
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
sp.edit().remove(KEY_LAST_LOAD_IMAGE_PATH).apply();
LogUtils.d(TAG, "clearLastLoadImagePath():已清除最后路径记录");
}
// ====================================== 辅助方法:从缓存获取上下文 ======================================
/**
* 从缓存实例中获取上下文用于无外部上下文时的SP操作
* @return 上下文实例无则返回null
*/
private static Context getContextFromCache() {
return sCachedView != null ? sCachedView.getContext() : null;
}
// ====================================== 重写父类方法:增强日志+SP持久化 ======================================
@Override
public void loadImage(String imagePath) {
LogUtils.d(TAG, "loadImage() 重载方法调用 | 图片路径:" + imagePath);
super.loadImage(imagePath);
// 保存最后加载路径到SP
saveLastLoadImagePath(getContext(), imagePath);
}
@Override
public void loadByBackgroundBean(BackgroundBean bean) {
LogUtils.d(TAG, "loadBackgroundBean() 重载方法调用 | BackgroundBean" + (bean == null ? "null" : bean.toString()));
super.loadByBackgroundBean(bean);
}
@Override
public void loadByBackgroundBean(BackgroundBean bean, boolean isRefresh) {
LogUtils.d(TAG, "loadBackgroundBean() 重载方法调用 | BackgroundBean" + (bean == null ? "null" : bean.toString()) + " | 是否刷新:" + isRefresh);
super.loadByBackgroundBean(bean, isRefresh);
}
}

View File

@@ -1,259 +1,247 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 顶部Toolbar首屏核心同步加载保留原有ASupportToolbar -->
<cc.winboll.studio.libaes.views.ASupportToolbar
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
android:id="@+id/toolbar"
android:gravity="center_vertical"
style="@style/DefaultAToolbar"/>
<cc.winboll.studio.libaes.views.ASupportToolbar
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
android:id="@+id/toolbar"
android:gravity="center_vertical"
style="@style/DefaultAToolbar"/>
<!-- 主内容区(优化层级,减少冗余RelativeLayout -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0">
<!-- 首屏核心容器(合并原冗余RelativeLayout,减少层级) -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/activitymainRelativeLayout1">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/activitymainRelativeLayout1">
<!-- 1. 背景视图(首屏核心,同步加载,保留原有) -->
<cc.winboll.studio.powerbell.views.BackgroundView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fragmentmainviewBackgroundView1"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/ll_backgroundview">
<!-- 2. 功能控件容器(首屏核心,同步加载,保留原有结构) -->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
<!-- 服务总开关布局 -->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/fragmentmainviewLinearLayout3"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="@drawable/bg_frame">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/fragmentmainviewLinearLayout3"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp">
<Switch
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/fragmentandroidviewSwitch1"
android:padding="10dp"
android:layout_weight="1.0"
android:textSize="@dimen/text_title_size"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="@drawable/bg_frame">
</LinearLayout>
<Switch
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/fragmentandroidviewSwitch1"
android:padding="10dp"
android:layout_weight="1.0"
android:textSize="@dimen/text_title_size"/>
</LinearLayout>
</LinearLayout>
<!-- 电量控制核心布局SeekBar+图标) -->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1.0">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<!-- 耗电提醒布局 -->
<LinearLayout
android:orientation="vertical"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:id="@+id/fragmentmainviewLinearLayout1">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1.0">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:background="@drawable/usege"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:id="@+id/fragmentmainviewLinearLayout1">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:id="@+id/fragmentmainviewCheckBox2"/>
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:background="@drawable/usege"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"/>
<cc.winboll.studio.powerbell.views.VerticalSeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/fragmentandroidviewVerticalSeekBar2"
android:progressTint="@color/colorUsege"
android:progressBackgroundTint="@color/colorUsege"
android:layout_weight="1.0"
android:layout_margin="10dp"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:id="@+id/fragmentmainviewCheckBox2"/>
</LinearLayout>
<cc.winboll.studio.powerbell.views.VerticalSeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/fragmentandroidviewVerticalSeekBar2"
android:progressTint="@color/colorUsege"
android:progressBackgroundTint="@color/colorUsege"
android:layout_weight="1.0"
android:layout_margin="10dp"/>
<!-- 耗电提醒数值+图标 -->
<LinearLayout
android:orientation="vertical"
android:layout_width="80dp"
android:layout_height="match_parent">
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="100%"
android:textSize="@dimen/text_title_size"
android:layout_gravity="center_horizontal"
android:id="@+id/fragmentandroidviewTextView3"
android:gravity="center_horizontal"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="80dp"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/fragmentandroidviewImageView2"
android:layout_weight="1.0"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="100%"
android:textSize="@dimen/text_title_size"
android:layout_gravity="center_horizontal"
android:id="@+id/fragmentandroidviewTextView3"
android:gravity="center_horizontal"/>
</LinearLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/fragmentandroidviewImageView2"
android:layout_weight="1.0"/>
<!-- 当前电量数值+图标 -->
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1.0">
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="100%"
android:textSize="@dimen/text_title_size"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:id="@+id/fragmentandroidviewTextView4"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1.0">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/fragmentandroidviewImageView1"
android:layout_weight="1.0"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="100%"
android:textSize="@dimen/text_title_size"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:id="@+id/fragmentandroidviewTextView4"/>
</LinearLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/fragmentandroidviewImageView1"
android:layout_weight="1.0"/>
<!-- 充电提醒数值+图标 -->
<LinearLayout
android:orientation="vertical"
android:layout_width="80dp"
android:layout_height="match_parent">
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="100%"
android:textSize="@dimen/text_title_size"
android:layout_gravity="center_horizontal"
android:id="@+id/fragmentandroidviewTextView2"
android:gravity="center_horizontal"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="80dp"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/fragmentandroidviewImageView3"
android:layout_weight="1.0"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="100%"
android:textSize="@dimen/text_title_size"
android:layout_gravity="center_horizontal"
android:id="@+id/fragmentandroidviewTextView2"
android:gravity="center_horizontal"/>
</LinearLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/fragmentandroidviewImageView3"
android:layout_weight="1.0"/>
<!-- 充电提醒布局 -->
<LinearLayout
android:orientation="vertical"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_marginBottom="20dp"
android:layout_marginTop="20dp"
android:id="@+id/fragmentmainviewLinearLayout2">
</LinearLayout>
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:background="@drawable/charge"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_marginBottom="20dp"
android:layout_marginTop="20dp"
android:id="@+id/fragmentmainviewLinearLayout2">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:id="@+id/fragmentmainviewCheckBox1"/>
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:background="@drawable/charge"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"/>
<cc.winboll.studio.powerbell.views.VerticalSeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/fragmentandroidviewVerticalSeekBar1"
android:progressTint="@color/colorCharge"
android:progressBackgroundTint="@color/colorCharge"
android:layout_weight="1.0"
android:layout_margin="10dp"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:id="@+id/fragmentmainviewCheckBox1"/>
</LinearLayout>
<cc.winboll.studio.powerbell.views.VerticalSeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/fragmentandroidviewVerticalSeekBar1"
android:progressTint="@color/colorCharge"
android:progressBackgroundTint="@color/colorCharge"
android:layout_weight="1.0"
android:layout_margin="10dp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- Tips文本 -->
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent">
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Tips"
android:textSize="@dimen/text_content_size"
android:id="@+id/fragmentandroidviewTextView1"
android:background="@drawable/bg_frame"
android:padding="10dp"/>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent">
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Tips"
android:textSize="@dimen/text_content_size"
android:id="@+id/fragmentandroidviewTextView1"
android:background="@drawable/bg_frame"
android:padding="10dp"/>
</LinearLayout>
</LinearLayout>
<!-- 3. 广告视图关键优化→用ViewStub延迟加载替代原直接加载的ADsBannerView -->
<!-- 首次启动仅占位1px不inflate真实广告视图减少首次耗时 -->
<ViewStub
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/stub_ads_banner"
android:layout_alignParentBottom="true"
android:layout="@layout/view_ads_banner"/> <!-- 广告视图独立布局文件 -->
</LinearLayout>
</RelativeLayout>
<ViewStub
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/stub_ads_banner"
android:layout_alignParentBottom="true"
android:layout="@layout/view_ads_banner"/>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
</LinearLayout>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF0C6BBF">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/ll_backgroundview">
</LinearLayout>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#AF4FDA4E">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Main"
android:id="@+id/btn_main_activity"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestCropImage"
android:id="@+id/btn_test_cropimage"/>
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
</LinearLayout>

View File

@@ -4,6 +4,10 @@
<item
android:id="@+id/action_unittestactivity"
android:title="@string/item_mainunittestactivity"/>
android:title="MainUnitTestActivity"/>
<item
android:id="@+id/action_unittest2activity"
android:title="MainUnitTest2Activity"/>
</menu>