一、故事起因

在一个伸手不见五指的早晨,我向宿舍群发了一张分屏图,如下。
在这里插入图片描述
结果,到了阳光明媚的晚上,我收到了一条短信。在这没有隐私的生活下,我居然相信了!!,相信了!!
在这里插入图片描述
但是想想又不对,这怎么是个锡盟号呢?怎么不是钉钉官方号呢?于是作为一个android的学习者,开始深刻的思考一个问题,android如何检测app处于分屏状态呢?

二、如何检测处于分屏状态?

由于每个版本的android都新增了不同功能,在android7.0中,引入了多窗口的功能。也就是下图。这样就可以实现一边看直播,一边干其他事。
在这里插入图片描述
但是!!! 对于学习类软件,对于学生是“好”的,但是对于教学者设不好的,所以,有必要警告他处于分屏状态。

判断分屏状态非常简单,在activity中重写onMultiWindowModeChanged,当切换到分屏下,会进行回调,参数isInMultiWindowMode为true则表示进入了分屏模式,(官方话是多窗口模式)。这时候就可警告了。

@Override
public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
    super.onMultiWindowModeChanged(isInMultiWindowMode);
    Log.i(TAG, "onMultiWindowModeChanged: "+isInMultiWindowMode);
}

但是,当进入分屏时,activity会重新创建,生命周期如下,但是有些小伙伴说,在onMultiWindowModeChanged回调后,onSaveInstanceState会执行,但是经过我两部真实手机测试,并不会进行回调。反而在之前回调。

onCreate:   第一次创建
onStart: 
onResume: 
onPause: 
onStop: 
onSaveInstanceState: 保存转台
onMultiWindowModeChanged: true 点击多窗口按钮,进入分屏模式回调
onDestroy:  销毁
onCreate: 二次重建
onStart: 
onResume: 

退出分屏生命周期,首先activity销毁重建后在回调onMultiWindowModeChanged。

onPause: 
onStop: 
onSaveInstanceState:  保存状态
onDestroy:  销毁
onCreate: 第三次重建
onStart: 
onResume: 
onMultiWindowModeChanged: false  重建后回调

也就是在进入分屏前,先回调onMultiWindowModeChanged,然后activity销毁重建,退出分屏时,先销毁重建后在回调onMultiWindowModeChanged(至少在我两部手机上是这样的)。

有些APP为了减少出错率,或者因为自己懒惰,将app禁用分屏,如职教x。

显然在这个方法由于activity的重建原因判断优点麻烦,所以还可以使用另一个activity中的方法isInMultiWindowMode();返回true则表示处于多屏状态。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Log.i(TAG, "onCreate: "+isInMultiWindowMode());
}
 onCreate: false  第一次进入,false
 onStart: 
 onResume: 
 onStop: 
 onSaveInstanceState: 
 onMultiWindowModeChanged: true
 onDestroy: 
 onCreate: true  进入分屏返回true,
 onStart: 
 onResume: 
 onPause: 
 onStop: 
 onSaveInstanceState: 

这时候可以启动一个定时器,超过指定秒后,则认定他在干其他事,进行处理(而我屏幕太大,想分屏缩小看怎么办?)。

完整实例如下,相对简单,或者进行自己逻辑上传到服务器进行统计。

public class MainActivity extends AppCompatActivity {
    private Handler mHandler =new Handler();
    private static final int MAX_SECOND = 5;
    private static final String TAG = MainActivity.class.getSimpleName();
    private Timer mTimer;
    private int mCurrentMulitWindowSecond = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mCurrentMulitWindowSecond=0;
        Log.i(TAG, "onCreate: "+isInMultiWindowMode());
        if (isInMultiWindowMode()){
            startTimer();
        }
    }
    private void startTimer() {
        if (mTimer == null) {
            mTimer = new Timer();
        }
        mTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                mCurrentMulitWindowSecond++;
                if (mCurrentMulitWindowSecond > MAX_SECOND) {
                     this.cancel();
                    showDialog();
                    Log.i(TAG, "run: "+mCurrentMulitWindowSecond);
                }
            }
        }, 0, 1000);
    }
    private  void showDialog(){
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                new AlertDialog.Builder(MainActivity.this)
                        .setTitle("警告")
                        .setMessage("你处于分屏模式")
                        .show();
            }
        },0);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy: ");
        if (mTimer != null) {
            mTimer.cancel();
            mTimer=null;
        }
    }
}

三、屏幕高度

为什么要说屏幕高度呢?且往下看。
android适配地点较多,就算简简单单获取屏幕高度都得十分注意。可能常用如下代码获取。

 DisplayMetrics outMetrics1 = new DisplayMetrics();
 getWindowManager().getDefaultDisplay().getMetrics(outMetrics1);
 Log.i(TAG, "getScreenHeight: "+outMetrics1.heightPixels);

这段代码看似没有问题,实在不然,最终可能会发现比真实高度小了十几个像素,我测试了三台手机,分别是:
小米8 :像素为2248x1080,上述代码获取到是2029。
模拟器:像素为1920x1080,上述代码获取为1776。
华为: 像素为2340x1080,上述代码获取为2255。
这是因为getDisplayMetrics().heightPixels会将虚拟按键的高度忽略掉。所以导致上述情况,还有一个坑。那就是在分屏情况下会更具实际而定,比如下图,会更具当前被用户分配的大小来决定,比如会获取到593,其实这也不是坑,假如一个View想获取屏幕高度,并做一些位置显示逻辑,如果用此方法返回真实的手机像素,并把View显示到那个地方,结果肯定是我们不想要的。
在这里插入图片描述
其他方法也是一样,如下面,有些方法过时了,我们就不要去使用他了。

//1
 int height1 = getResources().getDisplayMetrics().heightPixels;
//2
 Point point = new Point();
 getWindowManager().getDefaultDisplay().getSize(point);
 int height2=point.y;
//3
 int height3 = getWindowManager().getDefaultDisplay().getHeight();

上述情况在分屏情况下会根据被分配大小来计算,不在分屏下会忽略虚拟按键高度。
但是如果用getRealMetrics来获取,不管分不分屏,都返回实际的大小,也就是如2248、1920。所以这两个要使用注意

  DisplayMetrics outMetrics1 = new DisplayMetrics();
  getWindowManager().getDefaultDisplay().getRealMetrics(outMetrics1);
  Log.i(TAG, "getScreenHeight: "+outMetrics1.heightPixels);

四、如何禁止分屏?

在AndroidManifest的application下加入 android:resizeableActivity="false"即可
在这里插入图片描述

五、幕后凶手是谁?

知道了如何android如何检测分屏以一些注意事项后,我才开始怀疑这是谁在恶搞我
在这里插入图片描述
最后这崽子终于招了,提醒广大小伙伴,见到这种队友往冒烟的扁。
在这里插入图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐