• 整理之Activity


    基础

    生命周期

    执行层次 退
    创建与销毁 onCreate() onDestroy()
    是否可见 onStart() onStop()
    是否在前台(可交互) onResume() onPause()
    1.异常情况之配置改变

    比如屏幕旋转后Activity会重建。常见操作的生命周期变化:

    1.屏幕关闭/打开时:pause -> Save -> stop -> start -> resume,异常时save和pause顺序不确定
    2.屏幕旋转时:pause -> save -> stop -> destroy -> start -> restore -> resume
    3.弹出dialig:不产生变化
    4.添加fragment:不产生变化
    

    是否可以在发生配置变化后不重建Activity?可以的。

    指定android:configChanges属性,比如希望屏幕旋转后配置不变。加入orientation|screenSize,其他常见属性还有:

    locale 设备的本地位置发生了改变,一般指切换了系统语言 keyboard 键盘类型发生改变,比如外插键盘
    keyboardHidden 键盘的可访问性发生了改变,如调出了键盘 fontScale 用户选择了一个新字号
    uiMode 用户界面模式发生了改变,比如是否开启了夜间模式

    设置之后,旋转屏幕Activity并没有重建,也没吊用onSaveInstanceState和onRestoreInstanceState方法,取而代之的是onConfigurationChanged方法,在这个里面可以做一些处理。

    2.异常情况之内存紧张导致Activity被杀死

    被杀的优先级:空进程 > 后台Activity > 不可操作Activity > 前台进程

    跳转

    //简单跳转
    startActivity(Intent(this, That::class.java).apply{
        Bundle().apply{
            putXXX()
        }
    })
    //接收返回结果的跳转
    A.startActivityForResult(intent, requestCode, options)		//发送
    A.onActivityResult(requestCode, resultCode, data: Intent)	//接收返回结果
    B.setResult(resultCode)										//设置返回结果
    B.finish()													//退出
    

    启动模式

    1.standerd:每次启动都创建一个实例插入task中
    2.singleTop:栈顶复用,即不允许多个相同Activity叠加

    ​ 如果Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其onNewIntent方法。

    ​ 生命周期顺序:onCreate ---> onStart ---> onResume --- onPause ---> onNewIntent ---> onResume

    3.singleTask:栈内复用,即栈内只能有一个这A的实例。

    ​ 在同一个应用程序中启动A的时候,若A不存在,则会在当前task创建一个新的实例,若存在,则会把task中在其之上的其它所有Activity destory掉并调用它的onNewIntent方法。

    ​ 如果是在别的应用程序中启动它,则会新建一个task,并在该task中启动这个Activity,singleTask允许别的Activity与其在一个task中共存,也就是说,如果我在这个singleTask的实例中再打开新的Activity,这个新的Activity还是会在singleTask的实例的task中。

    ​ 生命周期顺序:onCreate ---> onStart ---> onResume ---> 按下Home键 ---> onPause ---> onstop ---> onNewIntent---> onRestart ---> onstart ---> onResume

    4.signleInstance:独占使用

    ​ 任务站中只能有一个A,不能有其他的。生命周期顺序同singleTask

    生命周期参考这篇文章

    特别需要注意:

    注意onNewIntent()中的陷阱:

    有时候,我们在多次启动同一个栈唯一模式下的activity时,在onNewIntent()里面的getIntent()得到的intent感觉都是第一次的那个数据。对,这里就是这个陷阱。因为它就是会返回第一个intent的数据。就是这么坑。

    原因就是我们没有在onNewIntent()里面设置setIntent(),将最新的intent设置给这个activity实例。

    protected void onNewIntent(Intent intent) {
       super.onNewIntent(intent);
       setIntent(intent);//设置新的intent
       int data = getIntent().getIntExtra("tanksu", 0);//此时的到的数据就是正确的了
    }
    

    在这里,如果你没有调用setIntent()方法的话,则getIntent()获取的intent都只会是最初那个intent(Note that getIntent() still returns the original Intent. You can use setIntent(Intent) to update it to this new Intent.)

    5.如何给Activity指定启动模式?

    ​ 1.通过AndroidMenifest。android:launchMode="singleTask"

    ​ 2.通过Intent中设置标志位来为Activity指定启动模式。

    intent = new Intent(MainActivity.this,Handler_01.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
    

    两者区别:
    优先级:第二种方式的优先级要高于第一种;
    限定范围:第一种方式无法直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识,而第二种无法为Activity指定singleInstance模式。

    常见操作

    双击返回键退出Activity

    思路:

    设置两次点击之间的时间间隔k,临时变量b=true保存返回按键是否被点击过。

    当按下返回键时,如果b=true,直接退出;否则设置b=true,并在k时间后设置b为false。

    当两次点击时间间隔小鱼k时,b的状态被保存,会触发退出事件。否则b会被重置,无法退出。

    private int isDoubleClickExit = 0;      //是否双击退出App。0为不退出,大于0时为双击之间的时间间隔
    protected void setDoubleClickExit(int ms) {	
        isDoubleClickExit = ms;
    }
    
    private boolean isBackButtonClicked = false;
    
    @Override
    public void onBackPressed() {
        if (isDoubleClickExit != 0) {
            if (isBackButtonClicked) {
                exitApp();
                return;
            }
            isBackButtonClicked = true;
            toastShort(R.string.double_clikc_exit);
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    isBackButtonClicked = false;
                }
            }, isDoubleClickExit);
        } else {
            super.onBackPressed();
        }
    }
    

    滑动返回

    private boolean mSlideBack = false;
    private boolean isBackArrowShow = false;
    private boolean isFirstShow = true;
    public void setSlideBack(boolean slideBack){
        mSlideBack = slideBack;
    }
    private float fx, fy;       //手指按下的坐标
    
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (mSlideBack) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    fx = event.getX();
                    fy = event.getY();
                    //Log.d("MOTION", "按下" + event.getX() + "  " + event.getY());
                    break;
    
                case MotionEvent.ACTION_MOVE:
                    if (fx < 100) {
                        if (Math.abs(event.getY() - fy) < 900) {
                            showArrow();
                        } else {
                            removeArrow();
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    Log.d("MOTION", "松开" + event.getX() + "  " + event.getY());
                    Log.d("MOTION", "距离" + Math.abs(event.getX() - fx ) + "  " + Math.abs(event.getY() - fy));
                    if (isBackArrowShow) {
                        this.finish();
                    }
                    //手指松开,恢复原样
                    removeArrow();
                    isFirstShow = true;
                    break;
                default:break;
            }
        }
        return super.dispatchTouchEvent(event);
    }
    

    关闭所有Activity

    1.BaseActivity中用一个栈记录所有打开的Activity
    2.MainActivity设置启动模式为singleTask,重新调用MainActivity即可退出所有
    3.本地广播通知所有Activity关闭
    

    保存Activity状态

    1.saveInstanceState
    2.SharePreference
    3.Jetpack ViewModel
    class MyViewModel(var handle : SavedStateHandle) : ViewModel() {
        init {
            if (!handle.contains("NUMBER"))
                handle.set("NUMBER", 0)
        }
        fun getNumber() : LiveData<Int> = handle.getLiveData("NUMBER")
        fun add() {
            val number : Int = handle.get("NUMBER")!!
            handle.set("NUMBER", number + 1)
        }
    }
    
  • 相关阅读:
    Oracle ORA07445 [evaopn3()+384] 错误 分析
    Openfiler iscsiadm: No portals found 解决方法
    Openfiler iscsiadm: No portals found 解决方法
    ORA00600 [kmgs_parameter_update_timeout_1], [27072] ORA27072 解决方法
    Oracle 安装 Error in writing to directory /tmp/OraInstall 错误 说明
    Oracle alert log ALTER SYSTEM SET service_names='','SYS$SYS.KUPC$C_...' SCOPE=MEMORY SID='' 说明
    Oracle latch:library cache 导致 数据库挂起 故障
    ORA600 [4194] 说明
    ORA00600:[32695], [hash aggregation can't be done] 解决方法
    Oracle 10g Rac root.sh Failure at final check of Oracle CRS stack 10 解决方法
  • 原文地址:https://www.cnblogs.com/lizhenxin/p/12433752.html
Copyright © 2020-2023  润新知