面试中Activity常见的坑你都知道吗?

1、activity生命周期?
Activity生命周期大家应该都知道,这里就不在啰嗦了,下面看看Google官网提供的一张经典的生命周期流程图:

①当启动Activity时,系统会依次调用onCreate-onStart-onResume,此时Activity处于可见状态

②当Activity被kill或者调用了本身的finish方法时,依次会调用onPause-onStop-onDestroy方法

下面来看看几个特殊情景下Activity的生命周期

2、点击home键、返回键、电源键时activity生命周期

下面结合一个实例,来看一下这几种状态下Activity的生命周期,实例很简单,定义一个BaseActivity类,重写了Activity所有生命周期方法,如下

  public class BaseActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Logger.d(this, "onCreate");
        }

        @Override
        protected void onStart() {
            super.onStart();
            Logger.d(this, "onStart");
        }

        @Override
        protected void onResume() {
            super.onResume();
            Logger.d(this, "onResume");
        }

        @Override
        protected void onPause() {
            super.onPause();
            Logger.d(this, "onPause");
        }

        @Override
        protected void onStop() {
            super.onStop();
            Logger.d(this, "onStop");
        }

        @Override
        protected void onDestroy() {
            super.onDestroy();
            Logger.d(this, "onDestroy");
        }

        @Override
        protected void onRestart() {
            super.onRestart();
            Logger.d(this, "onRestart");
        }

        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            Logger.d(this, "onNewIntent");
        }
    }

新建一个MainActivity继承BaseActivity,布局文件很简单,就一个button

   public class MainActivity extends BaseActivity implements View.OnClickListener {

        private Button mBtShowDialog;
        private static final String TAG = "MainActivity";

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            initView();
        }

        private void initView() {
            mBtShowDialog = (Button) findViewById(R.id.bt_show_dialog);
            mBtShowDialog.setOnClickListener(this);
        }
    }

下面通过log看下这几种情况下Activity的生命周期,点击home键

从上图可以出点击home键后,会依次调用onPause-onStop,再次进入时,Activity的onRestart-onStart-onResume会被依次调用

下面来看看点击back键

点击back键后会依次调用onPause-onStop-onDestroy

按电源键

从上图可以出点按电源键和点击home一样,会依次调用onPause-onStop,再次进入时,Activity的onRestart-onStart-onResume会被依次调用

3、Activity中弹出dialog,Activity的生命周期方法会走吗?
在Activity中弹出dialog时,activity的生命周期方法不会被调用;

private void showDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this).setTitle("Dialog Title").setMessage("Are you sure");
        builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        builder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(MainActivity.this, "you choose ok", Toast.LENGTH_SHORT).show();
            }
        });
        builder.create().show();
    }

当然如果是当前activity中跳转到另一个配置为dialog样式的activity时,对应的生命周期方法是会被掉用的,新建一个activity,配置theme为

  <activity android:name=".DialogActivity"         android:theme="@style/Theme.AppCompat.Dialog.Alert"/>


这种情况就和两个activity之间跳转时activity生命周期一样,就不在啰嗦了

4、旋转屏幕时Activity的生命周期?

屏幕旋转小插曲:
onConfigurationChanged事件并不是只有屏幕方向改变才可以触发,其他的一些系统设置改变也可以触发,比如打开或者隐藏键盘
在重写onConfigurationChanged需要注意下面几点:
第一:权限声明

<uses-permission Android:name="android.permission.CHANGE_CONFIGURATION"></uses-permission>

第二:声明activity要捕获的事件类型

<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="orientation|keyboard">  
     <intent-filter>  
<action android:name="android.intent.action.MAIN" />  
<categoryandroid:name="android.intent.category.LAUNCHER" />  
     </intent-filter>  
</activity>  

这里一定要声明Android:configChanges属性,该属性规定了我们可以在程序中捕获到的事件类型,多个事件类型用|分隔。

如果这里没有orientation,那么我们再程序中是无法捕获到屏幕改变的事件的。

第三:重写Activity中的onConfigurationChanged方法
android:configChanges,这个方法主要是负责列出
onConfigurationChanged监听的清单,当清单上用户指定的设置改变时,Activity会自己处理这些变化。

屏幕界面旋转(可能是用户手动旋转的),【注意:如果你的开发API等级等于或高于13,你还需要设置screenSize,因为screenSize会在屏幕旋转时改变】
keyboardHidden,键盘辅助功能改变

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            Logger.d(this, " current orientation is landscape");
        } else if(newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
            Logger.d(this, " current orientation is portrait");
        }
    }

运行后旋转屏幕截图:

通过log看,横竖屏切换,并不会调用activity生命周期方法,只会调用onConfigurationChanged

4、Activity常见启动模式区别
singleInstance:当activity A启动模式配置singleInstance后,如果B通过startActivity启动A,那么A和B不在同一栈中,可以通过dumpsys查看,A和B的taskId是不一样的

singleTask:任务栈中只允许有一个当前Activity实例,如果当前Activity实例 A不在栈顶,会清空A之上所有activity,这样A就在栈顶了

singleTop:singleTop Activity 的实例可以无限多,唯一的区别是如果在栈顶已经有一个相同类型的Activity实例,Intent不会再创建一个Activity,而是通过onNewIntent()被发送到现有的Activity

standard:通过这种方式启动的activity会放在同一栈中,最后启动的activity实例位于栈顶

5、启动activity时需要注意的的几个Flag
FLAG_ACTIVITY_TASK_ON_HOME:如果启动activity时设置了这个flag,会把新的任务置于home activity task顶部(如果home activity task存在的情况下),此时按back会返回到桌面

  /**
     * If set in an Intent passed to {@link Context#startActivity Context.startActivity()},
     * this flag will cause a newly launching task to be placed on top of the current
     * home activity task (if there is one).  That is, pressing back from the task
     * will always return the user to home even if that was not the last activity they
     * saw.   This can only be used in conjunction with {@link #FLAG_ACTIVITY_NEW_TASK}.
     */
    public static final int FLAG_ACTIVITY_TASK_ON_HOME = 0X00004000;

启动当前apk里的activity:

intent = new Intent("com.jason.activity.demo.ActivityWithFlag");    intent.setFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME|Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);

这时点击back键,返回到的是之前activity界面

启动别的apk里的activity:

intent = new Intent("android.telecom.action.CHANGE_PHONE_ACCOUNTS");
        intent.setPackage("com.android.phone");
 intent.setFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME|Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);

这时点击back键,返回到launcher界面
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:如果activity设置了这个flag,则不会显示在最近任务栏中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值