From c26f267774335efdeb5db6f01d6c4bce61c6e847 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Sat, 13 Dec 2025 11:35:51 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=90=AF=E5=8A=A8=E9=A1=B5?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E9=80=9F=E5=BA=A6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contacts/build.properties | 4 +- .../winboll/studio/contacts/MainActivity.java | 88 ++++++++++++--- .../contacts/fragments/CallLogFragment.java | 84 ++++++++++----- .../contacts/fragments/ContactsFragment.java | 101 ++++++++++++------ .../contacts/fragments/LogFragment.java | 52 ++++++--- 5 files changed, 244 insertions(+), 85 deletions(-) diff --git a/contacts/build.properties b/contacts/build.properties index fb0f2a9..669e3bd 100644 --- a/contacts/build.properties +++ b/contacts/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Sat Dec 13 03:05:50 GMT 2025 +#Sat Dec 13 03:34:07 GMT 2025 stageCount=1 libraryProject= baseVersion=15.12 publishVersion=15.12.0 -buildCount=78 +buildCount=80 baseBetaVersion=15.12.1 diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java index cd64583..154ae8b 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java @@ -11,6 +11,8 @@ import android.graphics.Color; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.telecom.TelecomManager; import android.view.Menu; import android.view.MenuItem; @@ -44,7 +46,8 @@ import java.util.List; * @Author ZhanGSKen&豆包大模型 * @Date 2025/08/30 14:32 * @Describe Contacts 主窗口(完全适配 API 30 + Java 7 语法) - * 核心优化:1. 移除电话状态监听 2. 移除通话筛选服务 3. 移除 MainService 所有相关逻辑 4. 保留原有页面结构 + * 核心优化:1. 移除电话状态监听 2. 移除通话筛选服务 3. 移除 MainService 所有相关逻辑 4. ViewPager 实现 Fragment 懒加载(仅首屏初始化) + * 问题修复:解决首屏 Fragment 空白问题(删除 setPrimaryItem 冲突逻辑+延迟首屏初始化) */ public final class MainActivity extends WinBollActivity implements IWinBoLLActivity, ViewPager.OnPageChangeListener, View.OnClickListener { @@ -85,6 +88,8 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv private int currentPoint = 0; private List fragmentList; private List tabTitleList; + // 记录已初始化的Fragment位置(避免重复初始化) + private boolean[] isFragmentInit; // ====================== 6. 接口实现区 ====================== @Override @@ -138,6 +143,16 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv mADsBannerView.releaseAdResources(); LogUtils.d(TAG, "onDestroy: 广告栏资源已释放"); } + // 清空Fragment相关引用,避免内存泄漏 + if (fragmentList != null) { + fragmentList.clear(); + fragmentList = null; + } + if (tabTitleList != null) { + tabTitleList.clear(); + tabTitleList = null; + } + isFragmentInit = null; LogUtils.d(TAG, "===== onDestroy: 主Activity销毁完成 ====="); } @@ -296,14 +311,15 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv } /** - * 初始化ViewPager与Tab数据(Java7规范,泛型完整声明) + * 初始化ViewPager与Tab数据(Java7规范,泛型完整声明),添加懒加载标记 + * 关键修改:延迟50ms初始化首屏,确保Fragment控件就绪;删除setPrimaryItem冲突逻辑 */ private void initViewPagerAndTabs() { LogUtils.d(TAG, "initViewPagerAndTabs: 开始初始化ViewPager数据"); fragmentList = new ArrayList(); tabTitleList = new ArrayList(); - // 添加Fragment与标题 + // 添加Fragment实例(仅创建对象,不初始化业务逻辑) fragmentList.add(CallLogFragment.newInstance(0)); fragmentList.add(ContactsFragment.newInstance(1)); fragmentList.add(LogFragment.newInstance(2)); @@ -311,13 +327,57 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv tabTitleList.add("联系人"); tabTitleList.add("应用日志"); - // 设置适配器 - MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager(), fragmentList, tabTitleList); + // 初始化懒加载标记数组(默认均未初始化) + int fragmentCount = fragmentList.size(); + isFragmentInit = new boolean[fragmentCount]; + for (int i = 0; i < fragmentCount; i++) { + isFragmentInit[i] = false; + } + + // 设置自定义适配器(已删除setPrimaryItem,避免初始化冲突) + LazyLoadPagerAdapter adapter = new LazyLoadPagerAdapter(getSupportFragmentManager(), fragmentList, tabTitleList); viewPager.setAdapter(adapter); - viewPager.setOffscreenPageLimit(2); + // 关闭预加载(设为0仅加载当前页,关键) + viewPager.setOffscreenPageLimit(0); viewPager.addOnPageChangeListener(this); - LogUtils.d(TAG, "initViewPagerAndTabs: ViewPager初始化完成,Fragment数量=" + fragmentList.size()); + // 关键优化:延迟50ms初始化首屏(确保Fragment已完成onCreateView,控件绑定就绪) + new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { + @Override + public void run() { + initFragmentByPosition(0); + LogUtils.d(TAG, "initViewPagerAndTabs: 延迟初始化首屏Fragment,位置=0"); + } + }, 50); + + LogUtils.d(TAG, "initViewPagerAndTabs: ViewPager初始化完成,等待延迟初始化首屏"); + } + + /** + * 根据位置初始化Fragment(调用Fragment的初始化逻辑,避免重复执行) + * 优化:添加isAdded判断,确保Fragment已附加到Activity,防止上下文空指针 + */ + private void initFragmentByPosition(int position) { + // 校验位置合法性 + 避免重复初始化 + 确保Fragment已附加到Activity + if (position < 0 || position >= fragmentList.size() || isFragmentInit[position]) { + return; + } + Fragment targetFragment = fragmentList.get(position); + if (targetFragment != null && targetFragment.isAdded()) { + // 触发Fragment初始化(调用各Fragment的initData方法) + if (targetFragment instanceof CallLogFragment) { + ((CallLogFragment) targetFragment).initData(); + } else if (targetFragment instanceof ContactsFragment) { + ((ContactsFragment) targetFragment).initData(); + } else if (targetFragment instanceof LogFragment) { + ((LogFragment) targetFragment).initData(); + } + // 标记为已初始化 + isFragmentInit[position] = true; + LogUtils.d(TAG, "initFragmentByPosition: 初始化Fragment,位置=" + position + ",标题=" + tabTitleList.get(position)); + } else { + LogUtils.w(TAG, "initFragmentByPosition: Fragment未附加到Activity/实例为空,位置=" + position); + } } // ====================== 10. 菜单相关函数区 ====================== @@ -338,7 +398,7 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv return super.onOptionsItemSelected(item); } - // ====================== 11. ViewPager页面回调区 ====================== + // ====================== 11. ViewPager页面回调区(切换时初始化对应Fragment) ====================== @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} @@ -346,6 +406,8 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv public void onPageSelected(int position) { currentPoint = position; LogUtils.d(TAG, "onPageSelected: 页面切换至[" + position + "],标题=" + tabTitleList.get(position)); + // 切换页面时,初始化当前页Fragment(未初始化过才执行) + initFragmentByPosition(position); } @Override @@ -420,17 +482,17 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv // ====================== 13. 内部类定义区(Java 7 规范,禁止Lambda) ====================== /** - * ViewPager适配器(静态内部类减少内存泄漏风险,Java7泛型完整声明) + * 自定义懒加载ViewPager适配器(删除setPrimaryItem方法,解决首屏初始化冲突) */ - private static class MyPagerAdapter extends FragmentPagerAdapter { + private class LazyLoadPagerAdapter extends FragmentPagerAdapter { private final List fragmentList; private final List tabTitleList; - public MyPagerAdapter(FragmentManager fm, List fragmentList, List tabTitleList) { + public LazyLoadPagerAdapter(FragmentManager fm, List fragmentList, List tabTitleList) { super(fm); this.fragmentList = fragmentList; this.tabTitleList = tabTitleList; - LogUtils.d(MainActivity.TAG, "MyPagerAdapter: 初始化完成,Fragment数量=" + fragmentList.size()); + LogUtils.d(MainActivity.TAG, "LazyLoadPagerAdapter: 初始化完成,Fragment数量=" + fragmentList.size()); } @Override @@ -447,6 +509,8 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv public CharSequence getPageTitle(int position) { return tabTitleList.get(position); } + + // 【已删除】移除setPrimaryItem方法,避免与手动初始化+onPageSelected回调冲突 } } diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/fragments/CallLogFragment.java b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/CallLogFragment.java index 00d1219..9e2ca6a 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/fragments/CallLogFragment.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/CallLogFragment.java @@ -28,7 +28,7 @@ import java.util.List; /** * @Author ZhanGSKen&豆包大模型 * @Date 2025/02/20 12:57:00 - * @Describe 通话记录区域视图 + * @Describe 通话记录区域视图(支持懒加载,仅切换到当前页才加载数据) */ public class CallLogFragment extends Fragment { @@ -51,6 +51,8 @@ public class CallLogFragment extends Fragment { // ====================== 业务逻辑成员区 ====================== private Handler mHandler; + // 懒加载标记:记录当前Fragment是否已初始化数据(避免重复加载) + private boolean isDataInited = false; // ====================== 单例与实例化函数区 ====================== CallLogFragment() { @@ -99,34 +101,28 @@ public class CallLogFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - LogUtils.d(TAG, "onViewCreated: 视图创建完成,初始化控件"); - // 初始化RecyclerView + LogUtils.d(TAG, "onViewCreated: 视图创建完成,仅初始化控件(不加载数据)"); + // 初始化RecyclerView(仅绑定控件、设置布局管理器,不设置数据/发起请求) recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + // 初始化适配器(传入空列表,后续懒加载时更新数据) callLogAdapter = new CallLogAdapter(getContext(), callLogList); recyclerView.setAdapter(callLogAdapter); - LogUtils.d(TAG, "onViewCreated: RecyclerView初始化完成"); - - // 权限检查与数据加载 - if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) { - LogUtils.w(TAG, "onViewCreated: 读取通话记录权限未授予,发起权限申请"); - ActivityCompat.requestPermissions(requireActivity(), new String[]{Manifest.permission.READ_CALL_LOG}, REQUEST_READ_CALL_LOG); - } else { - LogUtils.d(TAG, "onViewCreated: 权限已授予,发送更新消息"); - mHandler.sendEmptyMessage(MSG_UPDATE); - } + LogUtils.d(TAG, "onViewCreated: RecyclerView控件初始化完成(未加载数据)"); } @Override public void onResume() { super.onResume(); - LogUtils.d(TAG, "onResume: Fragment进入前台,刷新数据"); - if (callLogAdapter != null) { + LogUtils.d(TAG, "onResume: Fragment进入前台"); + // 已初始化过数据 → 仅刷新(避免重复初始化,优化性能) + if (isDataInited && callLogAdapter != null) { + LogUtils.d(TAG, "onResume: 数据已初始化,仅刷新列表"); callLogAdapter.relaodContacts(); - LogUtils.d(TAG, "onResume: 适配器数据重新加载"); + readCallLog(); // 刷新最新通话记录 + LogUtils.d(TAG, "onResume: 通话记录数据刷新完成"); } - readCallLog(); - LogUtils.d(TAG, "onResume: 通话记录数据刷新完成"); + // 未初始化 → 不操作(等待MainActivity调用initData触发初始化) } @Override @@ -137,7 +133,15 @@ public class CallLogFragment extends Fragment { mHandler.removeCallbacksAndMessages(null); LogUtils.d(TAG, "onDestroy: Handler消息已清空"); } + // 释放资源,避免内存泄漏 + if (callLogList != null) { + callLogList.clear(); + callLogList = null; + } + callLogAdapter = null; + recyclerView = null; _CallLogFragment = null; + isDataInited = false; LogUtils.d(TAG, "onDestroy: Fragment销毁完成"); } @@ -148,26 +152,52 @@ public class CallLogFragment extends Fragment { LogUtils.d(TAG, "onRequestPermissionsResult: 权限请求回调,requestCode=" + requestCode); if (requestCode == REQUEST_READ_CALL_LOG) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - LogUtils.d(TAG, "onRequestPermissionsResult: 通话记录权限授予成功,发送更新消息"); + LogUtils.d(TAG, "onRequestPermissionsResult: 通话记录权限授予成功,开始加载数据"); mHandler.sendEmptyMessage(MSG_UPDATE); } else { - LogUtils.e(TAG, "onRequestPermissionsResult: 通话记录权限被拒绝"); + LogUtils.e(TAG, "onRequestPermissionsResult: 通话记录权限被拒绝,无法加载数据"); } } } + // ====================== 懒加载核心方法(供MainActivity调用) ====================== + public void initData() { + // 避免重复初始化(双重防护:标记+判断) + if (isDataInited || getContext() == null) { + LogUtils.d(TAG, "initData: 数据已初始化/上下文为空,跳过"); + return; + } + LogUtils.d(TAG, "initData: 开始懒加载初始化通话记录数据"); + // 权限检查与数据加载(原onViewCreated中的核心逻辑迁移至此) + if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) { + LogUtils.w(TAG, "initData: 读取通话记录权限未授予,发起权限申请"); + ActivityCompat.requestPermissions(requireActivity(), new String[]{Manifest.permission.READ_CALL_LOG}, REQUEST_READ_CALL_LOG); + } else { + LogUtils.d(TAG, "initData: 权限已授予,发送更新消息加载数据"); + mHandler.sendEmptyMessage(MSG_UPDATE); + } + // 标记为已初始化(后续仅刷新,不重复初始化) + isDataInited = true; + LogUtils.d(TAG, "initData: 懒加载初始化流程完成"); + } + // ====================== 业务核心函数区 ====================== private void readCallLog() { LogUtils.d(TAG, "readCallLog: 开始读取系统通话记录"); + // 避免空指针(懒加载场景下,控件可能未初始化完成) + if (callLogList == null || callLogAdapter == null || getContext() == null) { + LogUtils.w(TAG, "readCallLog: 控件/列表为空,跳过读取"); + return; + } callLogList.clear(); Cursor cursor = null; try { cursor = requireContext().getContentResolver().query( - CallLog.Calls.CONTENT_URI, - null, - null, - null, - CallLog.Calls.DATE + " DESC" + CallLog.Calls.CONTENT_URI, + null, + null, + null, + CallLog.Calls.DATE + " DESC" ); if (cursor != null) { LogUtils.d(TAG, "readCallLog: 成功获取通话记录游标,数据条数=" + cursor.getCount()); @@ -211,7 +241,9 @@ public class CallLogFragment extends Fragment { // ====================== 外部调用函数区 ====================== public void triggerUpdate() { LogUtils.d(TAG, "triggerUpdate: 外部触发通话记录更新"); - mHandler.sendEmptyMessage(MSG_UPDATE); + if (isDataInited) { // 已初始化才触发更新(避免未加载时调用) + mHandler.sendEmptyMessage(MSG_UPDATE); + } } public static void updateCallLogFragment() { diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/fragments/ContactsFragment.java b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/ContactsFragment.java index 8d85c8b..1d177ed 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/fragments/ContactsFragment.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/ContactsFragment.java @@ -15,29 +15,26 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.app.ActivityCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - import cc.winboll.studio.contacts.R; import cc.winboll.studio.contacts.adapters.ContactAdapter; import cc.winboll.studio.contacts.model.ContactModel; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.ToastUtils; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * @Author ZhanGSKen&豆包大模型 * @Date 2025/08/30 14:32 - * @Describe 联系人区域视图 + * @Describe 联系人区域视图(支持懒加载,仅切换到当前页才加载数据) */ public class ContactsFragment extends Fragment { @@ -54,8 +51,9 @@ public class ContactsFragment extends Fragment { // ====================== 页面参数区 ====================== private int mPage; - private boolean isViewInitialized = false; // 视图初始化标记 - private boolean isDataLoaded = false; // 数据加载标记 + private boolean isViewInitialized = false; // 视图初始化标记(控件绑定完成) + private boolean isDataLoaded = false; // 数据加载标记(数据+功能初始化完成) + private boolean isLazyInitCompleted = false; // 懒加载总标记(供MainActivity判断) // ====================== UI控件区 ====================== private RecyclerView recyclerView; @@ -103,32 +101,38 @@ public class ContactsFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - LogUtils.d(TAG, "onViewCreated: 开始初始化UI控件"); - // 初始化RecyclerView + LogUtils.d(TAG, "onViewCreated: 开始初始化UI控件(仅绑定,不加载数据/功能)"); + // 初始化RecyclerView(仅绑定控件、设适配器,隐藏列表) recyclerView = (RecyclerView) view.findViewById(R.id.contacts_recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); contactAdapter = new ContactAdapter(getActivity(), contactList); recyclerView.setAdapter(contactAdapter); - recyclerView.setVisibility(View.GONE); // 初始隐藏列表 + recyclerView.setVisibility(View.GONE); - // 绑定搜索框和拨号按钮 + // 绑定搜索框和拨号按钮(仅赋值,不显示、不绑定事件) searchEditText = (EditText) view.findViewById(R.id.search_edit_text); btnDial = (Button) view.findViewById(R.id.btn_dial); searchEditText.setVisibility(View.GONE); btnDial.setVisibility(View.GONE); - LogUtils.d(TAG, "onViewCreated: UI控件初始化完成"); + + // 标记视图控件绑定完成 + isViewInitialized = true; + LogUtils.d(TAG, "onViewCreated: UI控件初始化完成(未加载数据/功能)"); } @Override public void onResume() { super.onResume(); LogUtils.d(TAG, "onResume: Fragment进入前台"); - if (!isViewInitialized) { - initSearchAndDial(); - checkContactPermission(); - isViewInitialized = true; - LogUtils.d(TAG, "onResume: 首次进入,完成视图和权限初始化"); + // 已完成懒加载 → 仅恢复缓存数据(切回页面时刷新) + if (isLazyInitCompleted && isDataLoaded) { + LogUtils.d(TAG, "onResume: 懒加载已完成,恢复缓存数据"); + contactList.clear(); + contactList.addAll(sCachedFilteredList); + contactAdapter.notifyDataSetChanged(); + recyclerView.setVisibility(View.VISIBLE); } + // 未完成懒加载 → 不操作(等待MainActivity调用initData触发) } @Override @@ -137,14 +141,28 @@ public class ContactsFragment extends Fragment { LogUtils.d(TAG, "onDestroy: Fragment开始销毁"); executor.shutdown(); // 关闭线程池 mainHandler.removeCallbacksAndMessages(null); // 清空Handler任务 - LogUtils.d(TAG, "onDestroy: 异步工具资源已释放"); + // 释放本地数据引用(保留静态缓存,全局复用) + if (contactList != null) { + contactList.clear(); + contactList = null; + } + if (originalContactList != null) { + originalContactList.clear(); + originalContactList = null; + } + // 重置标记 + isViewInitialized = false; + isDataLoaded = false; + isLazyInitCompleted = false; + LogUtils.d(TAG, "onDestroy: 异步工具+本地资源已释放"); } @Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); LogUtils.d(TAG, "onHiddenChanged: Fragment隐藏状态变更,hidden=" + hidden); - if (!hidden && isDataLoaded) { + // 已完成懒加载+显示状态 → 恢复缓存数据(兼容Tab切换场景) + if (!hidden && isLazyInitCompleted && isDataLoaded) { contactList.clear(); contactList.addAll(sCachedFilteredList); contactAdapter.notifyDataSetChanged(); @@ -177,10 +195,29 @@ public class ContactsFragment extends Fragment { LogUtils.e(TAG, "onRequestPermissionsResult: 联系人权限被拒绝"); ToastUtils.show("请授予联系人权限以查看联系人列表"); recyclerView.setVisibility(View.VISIBLE); + // 权限拒绝也标记懒加载完成(避免重复触发) + isLazyInitCompleted = true; } } } + // ====================== 懒加载核心方法(供MainActivity调用) ====================== + public void initData() { + // 双重防护:避免重复初始化(标记+视图就绪判断) + if (isLazyInitCompleted || !isViewInitialized || getContext() == null) { + LogUtils.d(TAG, "initData: 懒加载已完成/视图未就绪,跳过"); + return; + } + LogUtils.d(TAG, "initData: 开始懒加载初始化(功能+数据)"); + // 1. 初始化搜索、拨号功能(原onResume首次进入逻辑迁移至此) + initSearchAndDial(); + // 2. 检查权限+加载数据(原onResume首次进入逻辑迁移至此) + checkContactPermission(); + // 标记懒加载总流程完成(无论权限是否授予,仅执行一次) + isLazyInitCompleted = true; + LogUtils.d(TAG, "initData: 懒加载初始化流程启动完成"); + } + // ====================== UI功能初始化区 ====================== private void initSearchAndDial() { LogUtils.d(TAG, "initSearchAndDial: 初始化搜索和拨号功能"); @@ -217,7 +254,7 @@ public class ContactsFragment extends Fragment { // ====================== 数据加载与处理区 ====================== private void loadContacts() { - // 优先使用缓存数据 + // 优先使用缓存数据(保留原有缓存逻辑,提升性能) if (!sCachedOriginalList.isEmpty() && !sCachedFilteredList.isEmpty()) { LogUtils.d(TAG, "loadContacts: 存在缓存数据,直接复用"); originalContactList.clear(); @@ -230,7 +267,7 @@ public class ContactsFragment extends Fragment { return; } - // 无缓存时异步加载 + // 无缓存时异步加载(保留原有异步逻辑,避免主线程阻塞) if (!isDataLoaded) { LogUtils.d(TAG, "loadContacts: 无缓存,异步读取联系人数据"); recyclerView.setVisibility(View.GONE); @@ -270,14 +307,14 @@ public class ContactsFragment extends Fragment { Cursor cursor = null; try { cursor = requireContext().getContentResolver().query( - ContactsContract.CommonDataKinds.Phone.CONTENT_URI, - new String[]{ - ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, - ContactsContract.CommonDataKinds.Phone.NUMBER - }, - null, - null, - ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC" + ContactsContract.CommonDataKinds.Phone.CONTENT_URI, + new String[]{ + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, + ContactsContract.CommonDataKinds.Phone.NUMBER + }, + null, + null, + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC" ); if (cursor != null && cursor.moveToFirst()) { diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/fragments/LogFragment.java b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/LogFragment.java index ae6619b..625e327 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/fragments/LogFragment.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/LogFragment.java @@ -4,11 +4,9 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import cc.winboll.studio.contacts.R; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogView; @@ -16,7 +14,7 @@ import cc.winboll.studio.libappbase.LogView; /** * @Author ZhanGSKen&豆包大模型 * @Date 2025/02/20 12:58:15 - * @Describe 应用日志区域视图 + * @Describe 应用日志区域视图(支持懒加载,仅切换到当前页才启动日志) */ public class LogFragment extends Fragment { @@ -30,6 +28,11 @@ public class LogFragment extends Fragment { // ====================== UI控件区 ====================== private LogView mLogView; + // ====================== 懒加载标记区 ====================== + private boolean isViewInitialized = false; // 视图控件绑定完成标记 + private boolean isLazyInitCompleted = false; // 懒加载总流程完成标记 + private boolean isLogViewStarted = false; // LogView启动状态标记 + // ====================== 实例化函数区 ====================== public static LogFragment newInstance(int page) { LogUtils.d(TAG, "newInstance: 创建日志Fragment实例,页码=" + page); @@ -58,10 +61,11 @@ public class LogFragment extends Fragment { @Nullable Bundle savedInstanceState) { LogUtils.d(TAG, "onCreateView: 加载Fragment布局"); View view = inflater.inflate(R.layout.fragment_log, container, false); - // Java7 适配:添加强制类型转换 + // Java7 适配:添加强制类型转换,仅初始化LogView控件(不启动) mLogView = (LogView) view.findViewById(R.id.logview); - mLogView.start(); - LogUtils.d(TAG, "onCreateView: LogView已初始化并启动"); + LogUtils.d(TAG, "onCreateView: LogView控件初始化完成(未启动)"); + // 标记视图控件绑定完成 + isViewInitialized = true; return view; } @@ -69,12 +73,13 @@ public class LogFragment extends Fragment { public void onResume() { super.onResume(); LogUtils.d(TAG, "onResume: Fragment进入前台"); - if (mLogView != null) { + // 已完成懒加载 → 仅重启LogView(切回页面时恢复日志显示) + if (isLazyInitCompleted && mLogView != null && !isLogViewStarted) { mLogView.start(); - LogUtils.d(TAG, "onResume: LogView已重启"); - } else { - LogUtils.w(TAG, "onResume: LogView实例为空,跳过启动"); + isLogViewStarted = true; + LogUtils.d(TAG, "onResume: LogView已重启,恢复日志显示"); } + // 未完成懒加载 → 不操作(等待MainActivity调用initData触发) } @Override @@ -82,11 +87,32 @@ public class LogFragment extends Fragment { super.onDestroy(); LogUtils.d(TAG, "onDestroy: Fragment开始销毁"); if (mLogView != null) { - // 若LogView有停止方法,建议在此处调用,避免资源泄漏 - // mLogView.stop(); - LogUtils.d(TAG, "onDestroy: LogView资源已处理"); + // 若LogView有停止方法,必须调用(避免后台持续占用资源,根据实际API调整) + // mLogView.stop(); // 关键:释放LogView资源,防止内存泄漏 + LogUtils.d(TAG, "onDestroy: LogView资源已释放"); } + // 重置所有标记,避免重建时状态异常 + mLogView = null; + isViewInitialized = false; + isLazyInitCompleted = false; + isLogViewStarted = false; LogUtils.d(TAG, "onDestroy: Fragment销毁完成"); } + + // ====================== 懒加载核心方法(供MainActivity调用) ====================== + public void initData() { + // 双重防护:避免重复初始化(标记+视图就绪+控件非空) + if (isLazyInitCompleted || !isViewInitialized || mLogView == null || getContext() == null) { + LogUtils.d(TAG, "initData: 懒加载已完成/视图未就绪,跳过"); + return; + } + LogUtils.d(TAG, "initData: 开始懒加载初始化,启动LogView"); + // 核心:启动LogView(原onCreateView中的start逻辑迁移至此) + mLogView.start(); + isLogViewStarted = true; + // 标记懒加载总流程完成(仅执行一次) + isLazyInitCompleted = true; + LogUtils.d(TAG, "initData: 懒加载初始化完成,LogView正常启动"); + } }