From 0dac650877ca911e7fb30e6f37709d0d95b30721 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Sun, 7 Dec 2025 23:56:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=B1=B3=E7=9B=9F=E5=B9=BF?= =?UTF-8?q?=E5=91=8ASDK,=E6=B7=BB=E5=8A=A0=E4=B8=BB=E9=A2=98=E9=A3=8E?= =?UTF-8?q?=E6=A0=BC=E8=AE=BE=E7=BD=AE=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- positions/build.gradle | 13 ++ positions/build.properties | 4 +- positions/src/main/AndroidManifest.xml | 11 +- .../studio/positions/MainActivity.java | 60 +++++++- .../activities/LocationActivity.java | 131 ++++++++++------- .../activities/SettingsActivity.java | 51 +++++++ .../positions/activities/WinBoLLActivity.java | 32 ++++- .../src/main/res/layout/activity_location.xml | 132 ++++++++++-------- .../src/main/res/layout/activity_main.xml | 61 ++++---- .../src/main/res/layout/activity_settings.xml | 21 +++ positions/src/main/res/menu/toolbar_main.xml | 9 ++ positions/src/main/res/values/dimens.xml | 7 + positions/src/main/res/values/styles.xml | 8 ++ 13 files changed, 389 insertions(+), 151 deletions(-) create mode 100644 positions/src/main/java/cc/winboll/studio/positions/activities/SettingsActivity.java create mode 100644 positions/src/main/res/layout/activity_settings.xml create mode 100644 positions/src/main/res/menu/toolbar_main.xml create mode 100644 positions/src/main/res/values/dimens.xml diff --git a/positions/build.gradle b/positions/build.gradle index e4f159b..8893ea5 100644 --- a/positions/build.gradle +++ b/positions/build.gradle @@ -38,9 +38,22 @@ android { } } + // 米盟 SDK + packagingOptions { + doNotStrip "*/*/libmimo_1011.so" + } } dependencies { + // 米盟 + api 'com.miui.zeus:mimo-ad-sdk:5.3.+'//请使用最新版sdk + //注意:以下5个库必须要引入 + //api 'androidx.appcompat:appcompat:1.4.1' + api 'androidx.recyclerview:recyclerview:1.0.0' + api 'com.google.code.gson:gson:2.8.5' + api 'com.github.bumptech.glide:glide:4.9.0' + //annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0' + // https://mvnrepository.com/artifact/com.jzxiang.pickerview/TimePickerDialog api 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' diff --git a/positions/build.properties b/positions/build.properties index bf8a130..d80758c 100644 --- a/positions/build.properties +++ b/positions/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Sun Dec 07 21:00:59 HKT 2025 +#Sun Dec 07 15:55:26 GMT 2025 stageCount=1 libraryProject= baseVersion=15.12 publishVersion=15.12.0 -buildCount=0 +buildCount=5 baseBetaVersion=15.12.1 diff --git a/positions/src/main/AndroidManifest.xml b/positions/src/main/AndroidManifest.xml index 336e451..764c31b 100644 --- a/positions/src/main/AndroidManifest.xml +++ b/positions/src/main/AndroidManifest.xml @@ -112,7 +112,7 @@ - + @@ -134,16 +134,15 @@ - + - + - + + - + \ No newline at end of file diff --git a/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java b/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java index d105d63..22e8f5e 100644 --- a/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java +++ b/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java @@ -6,6 +6,8 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.CompoundButton; @@ -15,11 +17,14 @@ import androidx.annotation.NonNull; import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; +import cc.winboll.studio.libaes.utils.AESThemeUtil; +import cc.winboll.studio.libaes.utils.DevelopUtils; import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; +import cc.winboll.studio.libaes.views.ADsBannerView; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.positions.activities.LocationActivity; +import cc.winboll.studio.positions.activities.SettingsActivity; import cc.winboll.studio.positions.activities.WinBoLLActivity; -import cc.winboll.studio.positions.services.MainService; import cc.winboll.studio.positions.utils.AppConfigsUtil; import cc.winboll.studio.positions.utils.ServiceUtil; @@ -34,7 +39,7 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity { // 权限请求码(建议定义为类常量,避免魔法值) private static final int REQUEST_LOCATION_PERMISSIONS = 1001; private static final int REQUEST_BACKGROUND_LOCATION_PERMISSION = 1002; - + // UI 控件:服务控制开关、顶部工具栏 private Switch mServiceSwitch; private Button mManagePositionsButton; @@ -42,6 +47,7 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity { // 服务相关:服务实例、绑定状态标记 //private DistanceRefreshService mDistanceService; private boolean isServiceBound = false; + ADsBannerView mADsBannerView; @Override @@ -93,11 +99,18 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity { } // 4. 绑定服务(仅用于获取服务实时状态,不影响服务独立运行) //bindDistanceService(); + + mADsBannerView = findViewById(R.id.adsbanner); + } @Override protected void onDestroy() { super.onDestroy(); + if (mADsBannerView != null) { + mADsBannerView.releaseAdResources(); + } + // 页面销毁时解绑服务,避免Activity与服务相互引用导致内存泄漏 // if (isServiceBound) { // unbindService(mServiceConn); @@ -106,6 +119,16 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity { // } } + @Override + protected void onResume() { + super.onResume(); + if (mADsBannerView != null) { + mADsBannerView.resumeADs(MainActivity.this); + } + } + + + // ---------------------- 核心功能1:初始化UI组件(Toolbar + 服务开关) ---------------------- /** * 初始化顶部 Toolbar,设置页面标题 @@ -155,6 +178,39 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity { } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // 主题菜单 + AESThemeUtil.inflateMenu(this, menu); + // 调试工具菜单 + if (App.isDebugging()) { + DevelopUtils.inflateMenu(this, menu); + } + // 应用其他菜单 + getMenuInflater().inflate(R.menu.toolbar_main, menu); + + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int menuItemId = item.getItemId(); + if (AESThemeUtil.onAppThemeItemSelected(this, item)) { + recreate(); + } if (DevelopUtils.onDevelopItemSelected(this, item)) { + LogUtils.d(TAG, String.format("onOptionsItemSelected item.getItemId() %d ", item.getItemId())); + } else if (item.getItemId() == R.id.item_settings) { + Intent intent = new Intent(); + intent.setClass(this, SettingsActivity.class); + startActivity(intent); + } else { + // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 + return super.onOptionsItemSelected(item); + } + return true; + } + + /** * 绑定服务(仅用于获取服务状态,不启动服务) */ diff --git a/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java b/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java index c254e8a..8f49ffd 100644 --- a/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java +++ b/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java @@ -16,8 +16,10 @@ import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.TextView; import android.widget.Toast; +import androidx.appcompat.widget.Toolbar; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.positions.R; @@ -33,12 +35,14 @@ import java.util.concurrent.atomic.AtomicBoolean; * 2. Adapter 初始化传入 MainService 实例,确保数据来源唯一 * 3. 所有位置/任务操作通过 MainService 接口执行 */ -public class LocationActivity extends Activity { +public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivity { public static final String TAG = "LocationActivity"; + private Toolbar mToolbar; + private RecyclerView mRvPosition; private PositionAdapter mPositionAdapter; - + // MainService 引用+绑定状态(AtomicBoolean 确保多线程状态可见性) private MainService mMainService; private final AtomicBoolean isServiceBound = new AtomicBoolean(false); @@ -96,11 +100,34 @@ public class LocationActivity extends Activity { } }; + @Override + public Activity getActivity() { + return this; + } + + @Override + public String getTag() { + return TAG; + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_location); + mToolbar = findViewById(R.id.toolbar); + setSupportActionBar(mToolbar); + mToolbar.setSubtitle(getTag()); + mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + mToolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + LogUtils.d(TAG, "【导航栏】点击返回"); + finish(); + } + }); + // 1. 初始化视图(优先执行,避免Adapter初始化时视图为空) initView(); // 2. 初始化GPS监听(提前创建,避免绑定服务后空指针) @@ -167,7 +194,7 @@ public class LocationActivity extends Activity { } } LogUtils.d(TAG, "数据同步完成:服务位置数=" + (servicePosList == null ? 0 : servicePosList.size()) - + ",本地缓存数=" + mLocalPosCache.size()); + + ",本地缓存数=" + mLocalPosCache.size()); } catch (Exception e) { LogUtils.d(TAG, "同步服务数据失败:" + e.getMessage()); @@ -183,9 +210,9 @@ public class LocationActivity extends Activity { // 1. 多重安全校验(避免销毁后初始化/重复初始化/依赖未就绪) if (isAdapterInited.get() || !isServiceBound.get() || mMainService == null || mRvPosition == null) { LogUtils.w(TAG, "Adapter初始化跳过:" - + "已初始化=" + isAdapterInited.get() - + ",服务绑定=" + isServiceBound.get() - + ",视图就绪=" + (mRvPosition != null)); + + "已初始化=" + isAdapterInited.get() + + ",服务绑定=" + isServiceBound.get() + + ",视图就绪=" + (mRvPosition != null)); return; } @@ -195,54 +222,54 @@ public class LocationActivity extends Activity { // 3. 设置删除回调(删除时同步服务+本地缓存+Adapter) mPositionAdapter.setOnDeleteClickListener(new PositionAdapter.OnDeleteClickListener() { - @Override - public void onDeleteClick(int position) { - // 安全校验(索引有效+服务绑定+缓存非空) - if (position < 0 || position >= mLocalPosCache.size() || !isServiceBound.get() || mMainService == null) { - LogUtils.w(TAG, "删除位置失败:索引无效/服务未就绪(索引=" + position + ",缓存量=" + mLocalPosCache.size() + ")"); - return; - } + @Override + public void onDeleteClick(int position) { + // 安全校验(索引有效+服务绑定+缓存非空) + if (position < 0 || position >= mLocalPosCache.size() || !isServiceBound.get() || mMainService == null) { + LogUtils.w(TAG, "删除位置失败:索引无效/服务未就绪(索引=" + position + ",缓存量=" + mLocalPosCache.size() + ")"); + return; + } - PositionModel deletePos = mLocalPosCache.get(position); - if (deletePos != null && !deletePos.getPositionId().isEmpty()) { - // 步骤1:调用服务删除(确保服务数据一致性) - mMainService.removePosition(deletePos.getPositionId()); - // 步骤2:删除本地缓存(确保缓存与服务同步) - synchronized (mLocalPosCache) { - mLocalPosCache.remove(position); - } - // 步骤3:通知Adapter刷新(基于缓存操作,避免空数据) - mPositionAdapter.notifyItemRemoved(position); - showToast("删除位置成功:" + deletePos.getMemo()); - LogUtils.d(TAG, "删除位置完成:ID=" + deletePos.getPositionId() + "(服务+缓存已同步)"); - } - } - }); + PositionModel deletePos = mLocalPosCache.get(position); + if (deletePos != null && !deletePos.getPositionId().isEmpty()) { + // 步骤1:调用服务删除(确保服务数据一致性) + mMainService.removePosition(deletePos.getPositionId()); + // 步骤2:删除本地缓存(确保缓存与服务同步) + synchronized (mLocalPosCache) { + mLocalPosCache.remove(position); + } + // 步骤3:通知Adapter刷新(基于缓存操作,避免空数据) + mPositionAdapter.notifyItemRemoved(position); + showToast("删除位置成功:" + deletePos.getMemo()); + LogUtils.d(TAG, "删除位置完成:ID=" + deletePos.getPositionId() + "(服务+缓存已同步)"); + } + } + }); // 4. 设置保存回调(保存时同步服务+本地缓存+Adapter) mPositionAdapter.setOnSavePositionClickListener(new PositionAdapter.OnSavePositionClickListener() { - @Override - public void onSavePositionClick(int position, PositionModel updatedPos) { - // 安全校验(索引有效+服务绑定+数据非空) - if (!isServiceBound.get() || mMainService == null - || position < 0 || position >= mLocalPosCache.size() || updatedPos == null) { - LogUtils.w(TAG, "保存位置失败:服务未就绪/索引无效/数据空"); - showToast("服务未就绪,保存失败"); - return; - } + @Override + public void onSavePositionClick(int position, PositionModel updatedPos) { + // 安全校验(索引有效+服务绑定+数据非空) + if (!isServiceBound.get() || mMainService == null + || position < 0 || position >= mLocalPosCache.size() || updatedPos == null) { + LogUtils.w(TAG, "保存位置失败:服务未就绪/索引无效/数据空"); + showToast("服务未就绪,保存失败"); + return; + } - // 步骤1:调用服务更新(确保服务数据一致性) - mMainService.updatePosition(updatedPos); - // 步骤2:更新本地缓存(确保缓存与服务同步) - synchronized (mLocalPosCache) { - mLocalPosCache.set(position, updatedPos); - } - // 步骤3:通知Adapter刷新(基于缓存操作,避免空数据) - mPositionAdapter.notifyItemChanged(position); - showToast("保存位置成功:" + updatedPos.getMemo()); - LogUtils.d(TAG, "保存位置完成:ID=" + updatedPos.getPositionId() + "(服务+缓存已同步)"); - } - }); + // 步骤1:调用服务更新(确保服务数据一致性) + mMainService.updatePosition(updatedPos); + // 步骤2:更新本地缓存(确保缓存与服务同步) + synchronized (mLocalPosCache) { + mLocalPosCache.set(position, updatedPos); + } + // 步骤3:通知Adapter刷新(基于缓存操作,避免空数据) + mPositionAdapter.notifyItemChanged(position); + showToast("保存位置成功:" + updatedPos.getMemo()); + LogUtils.d(TAG, "保存位置完成:ID=" + updatedPos.getPositionId() + "(服务+缓存已同步)"); + } + }); // 5. 设置Adapter到RecyclerView(最后一步,确保Adapter已配置完成) mRvPosition.setAdapter(mPositionAdapter); @@ -268,7 +295,7 @@ public class LocationActivity extends Activity { } Toast.makeText(this, content, Toast.LENGTH_SHORT).show(); } - + // ---------------------- 页面交互(新增位置逻辑保留,适配GPS数据) ---------------------- /** * 新增位置(调用服务addPosition(),可选:用当前GPS位置初始化新位置) @@ -395,9 +422,7 @@ public class LocationActivity extends Activity { LogUtils.d(TAG, "onResume:服务已绑定但Adapter未初始化,重新同步数据"); syncDataFromMainService(); initPositionAdapter(); - } - // 2. 服务已绑定且Adapter已初始化:刷新数据(确保与服务同步) - else if (isServiceBound.get() && mMainService != null && isAdapterInited.get() && mPositionAdapter != null) { + } else if (isServiceBound.get() && mMainService != null && isAdapterInited.get() && mPositionAdapter != null) { syncDataFromMainService(); mPositionAdapter.notifyDataSetChanged(); LogUtils.d(TAG, "onResume:刷新位置数据(与服务同步)"); diff --git a/positions/src/main/java/cc/winboll/studio/positions/activities/SettingsActivity.java b/positions/src/main/java/cc/winboll/studio/positions/activities/SettingsActivity.java new file mode 100644 index 0000000..9b432f1 --- /dev/null +++ b/positions/src/main/java/cc/winboll/studio/positions/activities/SettingsActivity.java @@ -0,0 +1,51 @@ +package cc.winboll.studio.positions.activities; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import androidx.appcompat.widget.Toolbar; +import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.ToastUtils; +import cc.winboll.studio.positions.R; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/12/07 23:29 + * @Describe 应用设置活动窗口 + */ +public class SettingsActivity extends WinBoLLActivity implements IWinBoLLActivity { + + public static final String TAG = "SettingsActivity"; + + private Toolbar mToolbar; + + @Override + public Activity getActivity() { + return this; + } + + @Override + public String getTag() { + return TAG; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_settings); + + mToolbar = findViewById(R.id.toolbar); + setSupportActionBar(mToolbar); + mToolbar.setSubtitle(getTag()); + mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + mToolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + LogUtils.d(TAG, "【导航栏】点击返回"); + finish(); + } + }); + } +} diff --git a/positions/src/main/java/cc/winboll/studio/positions/activities/WinBoLLActivity.java b/positions/src/main/java/cc/winboll/studio/positions/activities/WinBoLLActivity.java index 3cf13b7..fba149f 100644 --- a/positions/src/main/java/cc/winboll/studio/positions/activities/WinBoLLActivity.java +++ b/positions/src/main/java/cc/winboll/studio/positions/activities/WinBoLLActivity.java @@ -10,6 +10,8 @@ import android.os.Bundle; import android.view.MenuItem; import androidx.appcompat.app.AppCompatActivity; import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; +import cc.winboll.studio.libaes.models.AESThemeBean; +import cc.winboll.studio.libaes.utils.AESThemeUtil; import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; import cc.winboll.studio.libappbase.LogUtils; @@ -17,6 +19,8 @@ public class WinBoLLActivity extends AppCompatActivity implements IWinBoLLActivi public static final String TAG = "WinBoLLActivity"; + protected volatile AESThemeBean.ThemeType mThemeType; + @Override public Activity getActivity() { return this; @@ -27,6 +31,22 @@ public class WinBoLLActivity extends AppCompatActivity implements IWinBoLLActivi return TAG; } + @Override + protected void onCreate(Bundle savedInstanceState) { + mThemeType = getThemeType(); + setThemeStyle(); + super.onCreate(savedInstanceState); + } + + AESThemeBean.ThemeType getThemeType() { + return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext())); + } + + void setThemeStyle() { + setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext())); + } + + @Override protected void onResume() { super.onResume(); @@ -36,12 +56,12 @@ public class WinBoLLActivity extends AppCompatActivity implements IWinBoLLActivi @Override public boolean onOptionsItemSelected(MenuItem item) { /*if (item.getItemId() == R.id.item_log) { - WinBoLLActivityManager.getInstance().startLogActivity(this); - return true; - } else if (item.getItemId() == R.id.item_home) { - startActivity(new Intent(this, MainActivity.class)); - return true; - }*/ + WinBoLLActivityManager.getInstance().startLogActivity(this); + return true; + } else if (item.getItemId() == R.id.item_home) { + startActivity(new Intent(this, MainActivity.class)); + return true; + }*/ // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 return super.onOptionsItemSelected(item); } diff --git a/positions/src/main/res/layout/activity_location.xml b/positions/src/main/res/layout/activity_location.xml index e751f33..e7842f6 100644 --- a/positions/src/main/res/layout/activity_location.xml +++ b/positions/src/main/res/layout/activity_location.xml @@ -1,67 +1,81 @@ - + android:layout_height="match_parent"> - - - - - - - - - - - + android:layout_height="@dimen/toolbar_height" + android:id="@+id/toolbar" + android:gravity="center_vertical"/> -