TooLargeTool 源码分析

902 阅读3分钟

1. 简介

ToolargeTool 是一个 Android 库,用于检测 Bundle 或 Intent 传输的数据是否过大,以防止 TransactionTooLargeException。该异常通常发生在 Activity、Fragment 或 Service 之间传输大数据时,可能导致应用崩溃。ToolargeTool 提供了简便的方法来监控和调试此类问题。

2. 项目结构

ToolargeTool 的项目结构如下:

toolargetool/
│
├── src/main/java/com/gu/toolargetool/
│   ├── ToolargeTool.java
│   ├── ActivityLifecycleCallbacksImpl.java
│   ├── FragmentLifecycleCallbacksImpl.java
│   ├── LogProxy.java
│   └── Util.java

各个文件的功能如下:

  • ToolargeTool.java:库的主类,提供初始化和监控功能。
  • ActivityLifecycleCallbacksImpl.java:用于监听 Activity 生命周期事件。
  • FragmentLifecycleCallbacksImpl.java:用于监听 Fragment 生命周期事件。
  • LogProxy.java:日志代理类,用于输出日志信息。
  • Util.java:工具类,提供辅助功能。

3. 核心类分析

3.1 ToolargeTool 类

ToolargeTool 类是库的核心类,负责初始化和监控功能。


public final class ToolargeTool {
    private static final String TAG = "ToolargeTool";

    private ToolargeTool() {
    }

    public static void startLogging(Application application) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            registerActivityLifecycleCallbacks(application);
            registerFragmentLifecycleCallbacks(application);
        } else {
            Log.w(TAG, "ToolargeTool requires Android O or higher");
        }
    }

    private static void registerActivityLifecycleCallbacks(Application application) {
        application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksImpl());
    }

    private static void registerFragmentLifecycleCallbacks(Application application) {
        FragmentManager.FragmentLifecycleCallbacks fragmentLifecycleCallbacks = new FragmentLifecycleCallbacksImpl();
        for (Activity activity : application.getActivityLifecycleCallbacks()) {
            if (activity instanceof FragmentActivity) {
                ((FragmentActivity) activity).getSupportFragmentManager()
                        .registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true);
            }
        }
    }
}

startLogging 方法是入口方法,用于初始化监控。它注册了 Activity 和 Fragment 的生命周期回调,以便在生命周期事件中检测数据大小。

3.2 ActivityLifecycleCallbacksImpl 类

ActivityLifecycleCallbacksImpl 类实现了 Application.ActivityLifecycleCallbacks 接口,用于监听 Activity 的生命周期事件。


public class ActivityLifecycleCallbacksImpl implements Application.ActivityLifecycleCallbacks {
    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        if (outState != null) {
            int size = Util.getBundleSize(outState);
            if (size > Util.THRESHOLD) {
                LogProxy.log(activity.getLocalClassName() + " onSaveInstanceState bundle size: " + size + " bytes");
            }
        }
    }

    // 其他生命周期方法省略
}

onActivitySaveInstanceState 方法在保存 Activity 状态时调用,通过 Util.getBundleSize 方法计算 Bundle 大小,并在超过阈值时输出日志。

3.3 FragmentLifecycleCallbacksImpl 类

FragmentLifecycleCallbacksImpl 类实现了 FragmentManager.FragmentLifecycleCallbacks 接口,用于监听 Fragment 的生命周期事件。


public class FragmentLifecycleCallbacksImpl extends FragmentManager.FragmentLifecycleCallbacks {
    @Override
    public void onFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) {
        if (outState != null) {
            int size = Util.getBundleSize(outState);
            if (size > Util.THRESHOLD) {
                LogProxy.log(f.getClass().getSimpleName() + " onSaveInstanceState bundle size: " + size + " bytes");
            }
        }
    }

    // 其他生命周期方法省略
}

onFragmentSaveInstanceState 方法在保存 Fragment 状态时调用,通过 Util.getBundleSize 方法计算 Bundle 大小,并在超过阈值时输出日志。

3.4 LogProxy 类

LogProxy 类用于输出日志信息,可以替换为自定义的日志处理逻辑。


public class LogProxy {
    public static void log(String message) {
        Log.d("ToolargeTool", message);
    }
}

3.5 Util 类

Util 类提供辅助功能,如计算 Bundle 大小。


public class Util {
    public static final int THRESHOLD = 512 * 1024; // 512KB

    public static int getBundleSize(Bundle bundle) {
        Parcel parcel = Parcel.obtain();
        bundle.writeToParcel(parcel, 0);
        int size = parcel.dataSize();
        parcel.recycle();
        return size;
    }
}

getBundleSize 方法通过将 Bundle 写入 Parcel 并获取其数据大小来计算 Bundle 大小。

4. 具体实现分析

4.1 初始化监控

ToolargeTool 的初始化通过调用 startLogging 方法实现。该方法首先判断当前 Android 版本是否高于 O,然后注册 Activity 和 Fragment 的生命周期回调。


public static void startLogging(Application application) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        registerActivityLifecycleCallbacks(application);
        registerFragmentLifecycleCallbacks(application);
    } else {
        Log.w(TAG, "ToolargeTool requires Android O or higher");
    }
}

4.2 监听 Activity 和 Fragment 生命周期

registerActivityLifecycleCallbacksregisterFragmentLifecycleCallbacks 方法中,分别注册了 ActivityLifecycleCallbacksImplFragmentLifecycleCallbacksImpl


private static void registerActivityLifecycleCallbacks(Application application) {
    application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksImpl());
}

private static void registerFragmentLifecycleCallbacks(Application application) {
    FragmentManager.FragmentLifecycleCallbacks fragmentLifecycleCallbacks = new FragmentLifecycleCallbacksImpl();
    for (Activity activity : application.getActivityLifecycleCallbacks()) {
        if (activity instanceof FragmentActivity) {
            ((FragmentActivity) activity).getSupportFragmentManager()
                    .registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true);
        }
    }
}

4.3 计算 Bundle 大小

ActivityLifecycleCallbacksImplFragmentLifecycleCallbacksImpl 中,分别在 onActivitySaveInstanceStateonFragmentSaveInstanceState 方法中计算 Bundle 大小。


@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    if (outState != null) {
        int size = Util.getBundleSize(outState);
        if (size > Util.THRESHOLD) {
            LogProxy.log(activity.getLocalClassName() + " onSaveInstanceState bundle size: " + size + " bytes");
        }
    }
}

@Override
public void onFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) {
    if (outState != null) {
        int size = Util.getBundleSize(outState);
        if (size > Util.THRESHOLD) {
            LogProxy.log(f.getClass().getSimpleName() + " onSaveInstanceState bundle size: " + size + " bytes");
        }
    }
}

通过 Util.getBundleSize 方法计算 Bundle 大小,并在超过阈值时输出日志。

5. 使用示例

在应用程序中使用 ToolargeTool 非常简单,只需在 Application 类中调用 ToolargeTool.startLogging 方法。


public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ToolargeTool.startLogging(this);
    }
}

6. 总结

ToolargeTool 是一个轻量级的 Android 库,提供了简便的方法来监控 Bundle 或 Intent 数据的大小,防止 TransactionTooLargeException。通过对其源码的分析,我们可以看到它通过注册 Activity 和 Fragment 的生命周期回调,在数据保存时计算 Bundle 大小,并在超过阈值时输出日志,帮助开发者及时发现和解决问题。其实现简单高效,适合在项目中集成和使用。