【Android】广播机制

前言

广播机制是Android中一种非常重要的通信机制,用于在应用程序之间或应用程序的不同组件之间传递信息。广播可以是系统广播,也可以是自定义广播。广播机制主要包括标准广播和有序广播两种类型。

简介

在Android中,广播(Broadcast)是一种消息,任何应用程序都可以发送广播消息,任何应用程序也都可以接收广播消息。广播通常用于通知应用程序某些事件的发生,比如系统启动、电量低、网络状态改变等。

广播的主要组件包括:

  • Broadcast Receiver(广播接收器):用于接收广播消息并响应这些消息的组件。
  • Intent(意图):用于传递广播消息的数据结构。
  1. 标准广播:

    标准广播(Normal Broadcast)是完全异步的,所有接收器几乎同时接收广播,并且接收顺序是不确定的。标准广播的特点是速度快,因为它们不需要等待其他接收器处理完广播才能继续传递。

  2. 有序广播:

    有序广播(Ordered Broadcast)是同步的,一个接收器接收到广播并处理完后,广播才会继续传递给下一个接收器。接收器可以修改广播的数据或截断广播,使其不再传递给其他接收器。有序广播允许通过设置优先级来控制接收器的接收顺序,优先级高的接收器会先接收广播。

接收系统广播

监听网络变化

先新建BroadcastTest项目,修改MainActivity

java 复制代码
public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter; // 意图过滤器,用于监听特定广播事件
    private NetworkChangeReceiver networkChangeReceiver; // 广播接收器实例

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // 设置布局文件
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); // 添加网络连接变化的广播事件
        networkChangeReceiver = new NetworkChangeReceiver(); // 初始化广播接收器
        registerReceiver(networkChangeReceiver, intentFilter); // 注册广播接收器
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver); // 注销广播接收器
    }

    class NetworkChangeReceiver extends BroadcastReceiver { // 内部类,继承自BroadcastReceiver

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show(); // 网络变化时显示提示信息
        }
    }
}

动态注册的广播一定都要取消注册

取消注册原因:

防止内存泄漏

  • 如果广播接收器在不需要时未被注销,它会持有对 Context 的引用,可能会导致内存泄漏。特别是在 ActivityService 中,如果它们被销毁后广播接收器仍然存在,会导致这些组件无法被垃圾回收器回收,进而占用系统资源。

避免不必要的资源消耗

  • 如果不注销广播接收器,它仍然会继续接收广播,即使相关的 ActivityService 已经不再需要这些广播。这会导致不必要的系统资源消耗,因为每次接收到广播时都会触发 onReceive 方法的执行。

防止潜在的崩溃

  • 在一些情况下,如果广播接收器在 ActivityService 销毁后继续接收广播,可能会导致应用程序崩溃。例如,如果 onReceive 方法中试图访问已销毁的 Activity 的 UI 元素,会引发 NullPointerException 等异常。

良好的编程实践

  • 注销广播接收器是一种良好的编程习惯,有助于保持代码的整洁和可靠性。它确保每个资源都被合理管理和释放,避免因资源管理不当而导致的各种问题。

上面的代码只能提示网络是否变化,可以对上面的代码进行优化

java 复制代码
public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter; // 意图过滤器,用于监听特定广播事件
    private NetworkChangeReceiver networkChangeReceiver; // 广播接收器实例

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // 设置布局文件
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); // 添加网络连接变化的广播事件
        networkChangeReceiver = new NetworkChangeReceiver(); // 初始化广播接收器
        registerReceiver(networkChangeReceiver, intentFilter); // 注册广播接收器
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver); // 注销广播接收器
    }

    class NetworkChangeReceiver extends BroadcastReceiver { // 内部类,继承自BroadcastReceiver

        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); // 获取连接管理器
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); // 获取当前活动的网络信息
            if (networkInfo != null && networkInfo.isAvailable()) { // 检查网络是否可用
                Toast.makeText(context, "network is available", Toast.LENGTH_SHORT).show(); // 网络可用时显示提示信息
            } else {
                Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show(); // 网络不可用时显示提示信息
            }
        }
    }
}

就可以显式网络是否连接了

静态注册实现开机启动

先在com/example/boardcasttest包下点击New→Other→Broadcast Receiver,修改名字为BootCompleteReceiver并且勾选Exported(是否允许这个广播接收器接收本程序以外的广播),Enabled(表示是否启用这个广播接收器)创建完成

修改BootCompleteReceiver中的代码:

java 复制代码
class NetworkChangeReceiver extends BroadcastReceiver {
    @Override
	public void onReceive(Context context, Intent intent) {
	Toast.makeText(context, "Boot Complete", Toast.LENGTH_SHORT).show();
	}
}

此外还需要在AndroidManifest文件中注册,但是由于我们使用的是快捷方式创建,所以这一步已经被自动完成了:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.BoardcastTest"
        tools:targetApi="31">
        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            
        </receiver>

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

新建了一个标签<receiver>

但是目前还是接收不到开机广播,需要对AndroidManifest进行修改:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>//
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.BoardcastTest"
        tools:targetApi="31">
        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>//
            </intent-filter>
        </receiver>

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

重新运行后就可以接收开机广播了

自定义广播

发送标准广播

首先需要定义一个广播接收器接收广播,新建MyBroadcastReceiver

java 复制代码
public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show();
    }
}

修改AndroidManifest中的代码:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.BoardcastTest"
        tools:targetApi="31">
        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>//
            </intent-filter>
        </receiver>

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

我们让MyBroadcastReceiver接收值为`的广播

修改activity_main中的代码

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send BoardCast"/>

</LinearLayout>

定义了一个按钮用于作为发送广播的触发点

修改MainActivity中的代码:

java 复制代码
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                intent.setPackage(getPackageName());
                sendBroadcast(intent);
            }
        });
    }
}

首先创建intent对象,将要发送的广播的值传入,然后调用sendBroadcast()进行发送,我们之前设置的接收器就可以接收到广播了

还要注意 的是setPackage的作用是指定这条广播发送给哪个程序 ,使得隐式广播转化为显式广播。因为Android8.0以后,静态注册的BroadcastReceiver是无法接受广播的

发送有序广播

修改MainActivity中的代码:

java 复制代码
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                sendOrderedBroadcast(intent, null);
            }
        });
    }
}

我们将sendBroadcast()方法改成了sendOrderedBroadcast()

新建一个类AnotherBroadcastReceiver继承BroadcastReceiver:

java 复制代码
public class AnotherBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "receciver in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show();
        abortBroadcast();//表示截断广播
    }
}

修改AndroidManifest:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.BoardcastTest"
        tools:targetApi="31">
        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

        <receiver
            android:name=".AnotherBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="100">
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

可以通过修改

xml 复制代码
<intent-filter android:priority="100">

来确定接收广播的优先级,数字大的先接收

使用本地广播

java 复制代码
public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter; // 意图过滤器,用于监听特定广播事件
    private LocalReceiver localReceiver; // 本地广播接收器实例
    private LocalBroadcastManager localBroadcastManager; // 本地广播管理器实例

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // 设置布局文件
        localBroadcastManager = LocalBroadcastManager.getInstance(this); // 获取本地广播管理器实例
        
        // 获取按钮并设置点击监听器
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 创建一个意图,并通过本地广播发送
                Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                localBroadcastManager.sendBroadcast(intent);
            }
        });

        // 初始化意图过滤器,并添加广播事件
        intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcasttest.MY_BROADCAST");

        // 初始化本地广播接收器
        localReceiver = new LocalReceiver();
        
        // 注册本地广播接收器
        localBroadcastManager.registerReceiver(localReceiver, intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 注销本地广播接收器
        localBroadcastManager.unregisterReceiver(localReceiver);
    }

    // 定义本地广播接收器类,继承自BroadcastReceiver
    class LocalReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            // 接收到本地广播时显示提示信息
            Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show();
        }
    }
}

广播的最佳实践------强制下线功能

先创建一个ActivityCollector类管理所有活动

java 复制代码
public class ActivityCollector {

    public static List<Activity>  activities = new ArrayList<>();

    public static void addActivity(Activity activity) {
        activities.add(activity);
    }

    public static void removeActivity(Activity activity) {
        activities.remove(activity);
    }

    public static void finishAll() {
        for (Activity activity : activities) {
            if (!activity.isFinishing()) {
                activity.finish();
            }
        }
        activities.clear();
    }
}

然后创建BaseActivity类作为所有活动的父类

java 复制代码
public class BaseActivity extends AppCompatActivity {
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
        ActivityCollector.addActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }
}

创建LoginActivity,并自动生成activity_login布局文件,修改如下:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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="60dp">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:text="Account:"
            android:textSize="18sp"/>

        <EditText
            android:id="@+id/account"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"/>
    </LinearLayout>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:text="Password:"
            android:textSize="18sp"/>

        <EditText
            android:id="@+id/password"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"/>
    </LinearLayout>

    <Button
        android:id="@+id/login"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:text="Login"/>

</LinearLayout>

这个布局就不多做解释了

下来修改LoginActivity中的代码:

java 复制代码
public class LogActivity extends BaseActivity {

    private EditText accountEdit;
    private EditText passwordEdit;
    private Button login;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_log);
        accountEdit = (EditText) findViewById(R.id.account);
        passwordEdit = (EditText) findViewById(R.id.password);
        login = (Button) findViewById(R.id.login);
        login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String account = accountEdit.getText().toString();
                String password = passwordEdit.getText().toString();
                if (account.equals("123") && password.equals("123")) {
                    Intent intent = new Intent(LogActivity.this, MainActivity.class);
                    startActivity(intent);
                    finish();
                } else {
                    Toast.makeText(LogActivity.this, "account or password is invalid", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

模拟了一个点单的登录功能,账号为123且密码为123则登陆成功,跳转到MainActivity

下来修改activity_main中的代码:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/force_offline"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send force offline broadcast"/>

</LinearLayout>

只用实现一个按钮用来触发强制下线功能

修改MainActivity中的代码:

java 复制代码
public class MainActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button forceOffline = (Button) findViewById(R.id.force_offline);
        forceOffline.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcastbestpractice.FORCE_OFFLINE");
                intent.setPackage(getPackageName());
                sendBroadcast(intent);
            }
        });
    }
}

其中come.example.broadcastbestpractice.FORCE_OFFLINE是用来通知程序强制下线的

下来需要创建广播接收器来接收广播,但是如果创建一个静态注册的广播接收器是没有办法在onReceive()里弹出对话框那样的UI控件,是不现实的

我们只需要在BaseActivity中动态注册一个广播接收器就可以了,因为所有活动继承自BaseActivity

修改BaseActivity中的代码:

java 复制代码
public class BaseActivity extends AppCompatActivity {

    private ForceOfflineReceiver receiver; // 广播接收器实例

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
        ActivityCollector.addActivity(this); // 将活动添加到活动管理器中
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this); // 将活动从活动管理器中移除
    }

    @Override
    protected void onResume() {
        super.onResume();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE"); // 添加广播事件
        receiver = new ForceOfflineReceiver(); // 初始化广播接收器
        registerReceiver(receiver, intentFilter); // 注册广播接收器
    }

    @Override
    protected void onPause() {
        super.onPause();
        if(receiver != null) {
            unregisterReceiver(receiver); // 注销广播接收器
            receiver = null; // 将接收器置为空
        }
    }

    class ForceOfflineReceiver extends BroadcastReceiver { // 定义内部类,继承自BroadcastReceiver
        @Override
        public void onReceive(final Context context, Intent intent) {
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setTitle("Warning"); // 设置对话框标题
            builder.setMessage("You are forced to be offline!"); // 设置对话框消息
            builder.setCancelable(false); // 设置对话框不可取消
            builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { // 设置对话框确认按钮
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    ActivityCollector.finishAll(); // 关闭所有活动
                    Intent i = new Intent(context, LogActivity.class); // 创建意图,启动LogActivity
                    context.startActivity(i); // 启动LogActivity
                }
            });
            builder.show(); // 显示对话框
        }
    }
}

下来对AndroidManifest文件进行修改:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.BroadcastBestPractice"
        tools:targetApi="31">
        <activity android:name=".MainActivity" >
        </activity>
        <activity android:name=".LogActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

完成了所有代码,当我们登录后点击按钮,就可以实现强制退出了。

下面是实现的效果:


已经到底啦!!

相关推荐
还鮟3 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡4 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi005 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil6 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你6 小时前
Android View的绘制原理详解
android
移动开发者1号9 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号9 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best14 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk14 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭19 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin