Android 《回到桌面与切换到任务列表》

App不但能监测手机屏幕的方向变更,还能获知回到桌面的事件,连打开任务列表的事件也能实时得知。回到桌面与打开任务列表都由按键触发,例如按下主页键会回到桌面,按下任务键会打开任务列表。虽然这两个操作看起来属于按键事件,但系统并未提供相应的按键处理方法,而是通过广播发出事件信息。因此,若想知晓是否回到桌面,以及是否打开任务列表,均需收听系统广播Intent.ACTION_CLOSE_SYSTEM_DIALOGS。至于如何区分当前广播究竟是回到桌面还是打开任务列表,则要从广播意图中获取原因reason字段,该字段值为homekey时表示回到桌面,值为recentapps时表示打开任务列表。接下来演示一下此类广播的接收过程。首先定义一个广播接收器,只处理动作为Intent.ACTION_CLOSE_SYSTEM_DIALOGS的系统广播,并判断它是主页键来源还是任务键来源。该接收器的代码定义示例如下:

// 定义一个返回到桌面的广播接收器
private class DesktopRecevier extends BroadcastReceiver {
   // 在收到返回桌面广播时触发
   @Override
   public void onReceive(Context context, Intent intent) {
       if (intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
           String reason = intent.getStringExtra("reason"); // 获取变更原因
           // 按下了主页键或者任务键
           if (!TextUtils.isEmpty(reason) && (reason.equals("homekey")|| reason.equals("recentapps"))) {
               showChangeStatus(reason); // 显示变更的状态 
      		}
      	  } 
 	} 
}

接着在活动页面的onCreate方法中注册接收器,在onDestroy方法中注销接收器,其中接收器的注册代码如下所示:

private DesktopRecevier desktopRecevier; // 声明一个返回桌面的广播接收器对象 
// 初始化桌面广播
private void initDesktopRecevier() {
   desktopRecevier = new DesktopRecevier(); // 创建一个返回桌面的广播接收器 
   // 创建一个意图过滤器,只接收关闭系统对话框(即返回桌面)的广播
   IntentFilter intentFilter = new
IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
   registerReceiver(desktopRecevier, intentFilter); // 注册接收器,注册之后才能正常接收广播
}

可是监听回到桌面的广播能用来干什么呢?一种用处是开启App的画中画模式,比如原先应用正在播放视频,回到桌面时势必要暂停播放,有了画中画模式之后,可将播放界面缩小为屏幕上的一个小方块,这样即使回到桌面也能继续观看视频。注意从Android 8.0开始才提供画中画模式,故而代码需要判断系统版本,下面是进入画中画模式的代码例子:

// 显示变更的状态
private void showChangeStatus(String reason) {
   mDesc = String.format("%s%s 按下了%s键\n", mDesc, DateUtil.getNowTime(), 
reason);
   tv_monitor.setText(mDesc);
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
       && !isInPictureInPictureMode()) { // 当前未开启画中画,则开启画中画模式 
       // 创建画中画模式的参数构建器
       PictureInPictureParams.Builder builder = new 
PictureInPictureParams.Builder();
       // 设置宽高比例值,第一个参数表示分子,第二个参数表示分母 
       // 下面的10/5=2,表示画中画窗口的宽度是高度的两倍
       Rational aspectRatio = new Rational(10,5);
       builder.setAspectRatio(aspectRatio); // 设置画中画窗口的宽高比例
       // 进入画中画模式,注意enterPictureInPictureMode是Android8.0之后新增的方法 
       enterPictureInPictureMode(builder.build());
 } 
}

以上代码用于开启画中画模式,但有时希望在进入画中画之际调整界面,则需重写活动的onPictureInPictureModeChanged方法,该方法在应用进入画中画模式或退出画中画模式时触发,在此可补充相应的处理逻辑。重写后的方法代码示例如下:

// 在进入画中画模式或退出画中画模式时触发
@Override
public void onPictureInPictureModeChanged(boolean isInPicInPicMode, 
Configuration newConfig) {
   Log.d(TAG, "onPictureInPictureModeChanged 
isInPicInPicMode="+isInPicInPicMode);
   super.onPictureInPictureModeChanged(isInPicInPicMode, newConfig); 
   if (isInPicInPicMode) { // 进入画中画模式
  } else { // 退出画中画模式 
 }
}

另外,画中画模式要求在AndroidManifest.xml中开启画中画支持,也就是给activity节点添加supportsPictureInPicture属性并设为true,添加新属性之后的activity配置示例如下:

<activity
         android:name=".ReturnDesktopActivity"
         android:configChanges="orientation|screenLayout|screenSize" 
         android:supportsPictureInPicture="true"
         android:theme="@style/AppCompatTheme" />

image

完整代码

AndroidManifest.xml

<activity
            android:name=".ui.ReturnDeskActivity"
            android:exported="true"
            android:configChanges="orientation|screenLayout|screenSize"
            android:supportsPictureInPicture="true"
            />

ReturnDeskActivity.java

public class ReturnDeskActivity extends AppCompatActivity {
    private DesktopReceiver desktopRecevier;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_return_desk);
        desktopRecevier = new DesktopReceiver();
        IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        registerReceiver(desktopRecevier, filter);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(desktopRecevier);
    }

    // 在进入画中画模式或退出画中画模式时触发
    @Override
    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
        super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
        if (isInPictureInPictureMode){
            Log.d("xian","进入画中画模式");
        }else{
            Log.d("xian","退出画中画模式");
        }
    }


    /**
     * 定义一个返回桌面的广播接收器
     */
    private  class DesktopReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent!=null && intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)){
                String reason = intent.getStringExtra("reason");
                if (!TextUtils.isEmpty(reason) &&
                        (reason.equals("homekey") || reason.equals("recentapps"))){
                    // Android 8.0开始才提供画中画模式
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
                            && !isInPictureInPictureMode()){
                        // 创建画中画模式的参数构建器
                        PictureInPictureParams.Builder builder = new PictureInPictureParams.Builder();
                        // 设置宽高比例值,第一个参数表示分子,第二个参数表示分母
                        // 下面的10/5=2,表示画中画窗口的宽度是高度的两倍
                        // 设置画中画窗口的宽高比例
                        Rational ratio = new Rational(10, 5);
                        builder.setAspectRatio(ratio);
                        // 进入画中画模式
                        enterPictureInPictureMode(builder.build());
                    }
                }

            }
        }
    }
}
posted @ 2024-03-11 15:05  一个小笨蛋  阅读(118)  评论(0编辑  收藏  举报