Android--设置显示大小导致APP crash

问题原因:

在设置中修改显示大小,APP需要重新刷新界面,app是作为一种异常走的onDestroy()方法,并不是正常的按返回键进行的退出执行的onDestroy(),这个时候系统会自动在onSaveInstanceState()方法里面临时性的保存之前的界面状态或者变量信息,方便在onCreate()的时候,从bundle里面直接取出来使用。但是毕竟是异常的状态,有些实体的信息或者fragment堆栈的状态恢复的时候就有可能错乱,导致显示效果出错或者crash。

解决办法:复写onSaveInstanceState()方法,去掉其中的保存super.onSaveInstanceState(savedInstanceState);代码,防止恢复出错。

方法一:

@Override   
public void onSaveInstanceState(Bundle savedInstanceState) {   
} 

方法二:如果数据必须保存有用:

public class MainActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.main);
        
        //状态 判断
        if (savedInstanceState != null) {
            Log.d("HELLO", "HELLO:应用进程被回收后,状态恢复");
            String string = savedInstanceState.getString("username");
            if (string != null) {
     
widget 内存泄漏如何避免和修改03-07 20:12:32.610 20343 20343 E CrashReport: java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 549112 bytes 03-07 20:12:32.610 20343 20343 E CrashReport: --------- Stack trace --------- 03-07 20:12:32.610 20343 20343 E CrashReport: 1. android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:679) 03-07 20:12:32.610 20343 20343 E CrashReport: 2. com.neusoft.widget.NavigationWidgetProvider.A(NavigationWidgetProvider.java:3) 03-07 20:12:32.610 20343 20343 E CrashReport: 3. com.neusoft.widget.NavigationWidgetProvider.c(NavigationWidgetProvider.java:1) 03-07 20:12:32.610 20343 20343 E CrashReport: 4. com.neusoft.widget.NavigationWidgetProvider$c.b(NavigationWidgetProvider.java:10) 03-07 20:12:32.610 20343 20343 E CrashReport: 5. com.neusoft.navigation.viewmodel.manager.v$a.o(NavigationManager.java:8) 03-07 20:12:32.610 20343 20343 E CrashReport: 6. x4.v0.onTurnInfoUpdated(NeuGuidanceListener.java:32) 03-07 20:12:32.610 20343 20343 E CrashReport: 7. com.neusoft.nmasdk.guidance.NMAGuidanceThriftListenerImpl.lambda$onTurnInfoUpdated$9(NMAGuidanceThriftListenerImpl.java:2) 03-07 20:12:32.610 20343 20343 E CrashReport: 8. com.neusoft.nmasdk.guidance.NMAGuidanceThriftListenerImpl.e0(Unknown Source:0) 03-07 20:12:32.610 20343 20343 E CrashReport: 9. com.neusoft.nmasdk.guidance.n0.run(Unknown Source:6) 03-07 20:12:32.610 20343 20343 E CrashReport: 10. android.os.Handler.handleCallback(Handler.java:883) 03-07 20:12:32.610 20343 20343 E CrashReport: 11. android.os.Handler.dispatchMessage(Handler.java:100) 03-07 20:12:32.610 20343 20343 E CrashReport: 12. android.os.Looper.loop(Looper.java:214) 03-07 20:12:32.610 20343 20343 E CrashReport: 13. android.app.ActivityThread.main(ActivityThread.java:7386) 03-07 20:12:32.610 20343 20343 E CrashReport: 14. java.lang.reflect.Method.invoke(Native Method) 03-07 20:12:32.610 20343 20343 E CrashReport: 15. com.android.internal.os.
最新发布
03-11
<think>好的,我现在需要帮助用户解决Android Widget开发中的内存泄漏和TransactionTooLargeException异常的问题。首先,我需要回顾一下用户提供的引用内容,看看有没有相关的信息。 用户引用了四篇文章,其中两篇是关于Widget开发的,特别是支持ListView滑动的Widget。引用[1]和[4]提到了Widget作为Android的七大组件之一,开发步骤和可能的问题。引用[3]中的代码展示了如何处理下拉刷新和加载更多,这可能涉及到ListView或RecyclerView的使用,而这类组件在Widget中如果处理不当,可能会导致内存泄漏或者数据传输过大的问题。 接下来,我需要分析用户提到的两个问题:内存泄漏和TransactionTooLargeException。首先,内存泄漏在Android中通常是由于长时间持有Context引用,比如在静态变量中保存了Activity的Context。在Widget中,可能是在更新Widget时持有了ApplicationContext以外的Context,或者没有正确释放资源。 然后是TransactionTooLargeException,这通常发生在通过Binder传输的数据量过大时。在Widget开发中,使用RemoteViews更新界面时,如果一次性传输过大的数据,比如ListView中包含大量数据项,就可能触发这个异常。 针对内存泄漏,解决方案可能包括使用正确的Context(Application Context),避免在静态成员中持有Context,及时注销广播接收器,以及使用弱引用等。对于ListView的滑动支持,可能需要优化数据加载,分页加载,避免一次性加载过多数据。 对于TransactionTooLargeException,需要检查在更新Widget时是否传输了过大的数据,比如ListView的项数过多或者每个项的内容太复杂。解决办法可能是减少数据量,分批次加载,或者使用其他方式管理数据,比如通过数据库或文件存储,只传输必要的信息。 另外,用户提供的引用[3]中提到了分页加载和刷新监听,这可能与处理大数据量有关,可以借鉴这种分页加载的思路来解决TransactionTooLargeException的问题。例如,在Widget中每次只加载部分数据,当用户滑动时再加载更多,而不是一次性加载所有数据。 还需要注意,在Widget中使用RemoteViews时,某些操作可能受到限制,比如不能直接使用自定义View,只能使用系统提供的组件。因此,ListView的适配器需要使用RemoteViewsService和RemoteViewsFactory,并且在实现这些组件时要确保数据的高效管理和释放,避免内存泄漏。 可能还需要检查PendingIntent的使用是否正确,比如是否使用了不恰当的Flag,导致Intent被重复使用或持有旧的Context引用,从而引发内存泄漏。此外,确保在Widget的onDisabled方法中释放资源,比如停止服务或注销接收器,这也是防止内存泄漏的重要步骤。 总结一下,解决方案可能包括以下几点: 1. 使用Application Context来更新Widget,避免持有Activity的Context。 2. 在RemoteViewsFactory中及时释放资源,如关闭数据库连接或清空数据集合。 3. 分页加载数据,减少每次传输的数据量,避免TransactionTooLargeException。 4. 使用WeakReference来持有Context,防止静态引用导致的内存泄漏。 5. 正确管理广播接收器和服务,确保在不需要时及时注销和停止。 同时,用户可能需要检查他们的代码,特别是在更新Widget时是否在后台线程执行,避免在主线程中进行耗时操作,这虽然不会直接导致内存泄漏,但可能影响性能,间接导致资源无法及时释放。 最后,需要参考用户提供的引用中的代码示例,例如引用[3]中的分页加载和刷新逻辑,应用到Widget的数据加载过程中,确保每次更新只处理合理数量的数据项,从而避免异常的发生。</think>### 解决Android Widget内存泄漏及TransactionTooLargeException问题 #### 一、内存泄漏问题分析及解决方案 **原因**: 1. **静态Context引用**:在静态变量(如单例、广播接收器)中持有Activity或View的Context,导致组件无法释放[^1]。 2. **未注销监听器**:未及时注销广播接收器或服务绑定。 3. **RemoteViewsFactory资源未释放**:自定义$RemoteViewsFactory$未关闭数据库或释放数据集合。 **解决方案**: 1. **使用Application Context**:更新Widget时优先使用$getApplicationContext()$,避免持有Activity引用: ```java context = context.getApplicationContext(); AppWidgetManager.getInstance(context).updateAppWidget(widgetId, remoteViews); ``` 2. **弱引用持有Context**:在单例或工具类中使用$WeakReference<Context>$: ```java private WeakReference<Context> weakContext; ``` 3. **及时释放资源**:在$RemoteViewsFactory$的$onDestroy()$中关闭数据库或清空集合: ```java @Override public void onDestroy() { database.close(); dataList.clear(); } ``` 4. **注销广播接收器**:在Widget的$onDisabled()$中注销: ```java @Override public void onDisabled(Context context) { context.unregisterReceiver(broadcastReceiver); } ``` --- #### 二、TransactionTooLargeException异常处理 **原因**: 通过Binder传输的$RemoteViews$数据量超过1MB限制,常见于ListView/GridView加载过多项或复杂布局[^3]。 **优化方案**: 1. **分页加载数据**:模仿引用[3]的分页逻辑,每次仅加载部分数据: ```java private static final int PAGE_SIZE = 20; // 每页加载20项 @Override public int getCount() { return Math.min(data.size(), PAGE_SIZE); } ``` 2. **简化布局层级**:使用扁平化布局,避免嵌套$LinearLayout$,优先用$RelativeLayout$。 3. **延迟加载图片**:使用$Glide$等库时,仅在可见项加载图片: ```java // 在RemoteViewsFactory的getViewAt()中异步加载 Glide.with(context).asBitmap().load(imageUrl).into(new SimpleTarget<Bitmap>() { @Override public void onResourceReady(Bitmap bitmap, Transition<? super Bitmap> transition) { remoteViews.setImageViewBitmap(R.id.imageView, bitmap); } }); ``` 4. **使用占位符替代大资源**:对未加载的图片使用低分辨率占位图。 --- #### 三、代码示例:安全更新Widget ```java public class MyWidgetProvider extends AppWidgetProvider { @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { Context appContext = context.getApplicationContext(); // 使用Application Context for (int widgetId : appWidgetIds) { RemoteViews remoteViews = new RemoteViews(appContext.getPackageName(), R.layout.widget_layout); // 设置点击事件时使用PendingIntent的FLAG_IMMUTABLE Intent intent = new Intent(appContext, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(appContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); remoteViews.setOnClickPendingIntent(R.id.button, pendingIntent); // 分批更新ListView数据 Intent serviceIntent = new Intent(appContext, MyWidgetService.class); remoteViews.setRemoteAdapter(R.id.listView, serviceIntent); // 触发局部更新 appWidgetManager.partiallyUpdateAppWidget(widgetId, remoteViews); } } } ``` --- #### 四、关键检查点 1. **静态代码扫描**:使用Android Studio的**Analyze > Run Inspection by Name > Memory Leak**检测工具。 2. **Binder数据量监控**:通过$adb shell dumpsys binder transactions$查看传输大小。 3. **Profiler分析**:使用Android Profiler的**Memory**选项卡追踪Widget相关对象是否持续增长。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值