Android onNewIntent()需要注意的一些问题

来源:互联网 发布:交易宝行情软件 编辑:程序博客网 时间:2024/05/29 13:36

一、场景
  最近遇到一个需求:有A、B、C三个页面,A能跳到B,然后B会跳到C,C还能跳到B,反正B和C两个页面能互相跳,但是C页面点击返回的时候要回到A。(ps:页面之间有数据的传递)
  拿到需求我一下就想到的方案就是 把 B、C两个页面的启动模式设置成SignleTask: android:launchMode="singleTask" , 在B Intent跳转C时将B finish()掉,因为C在Activity栈里面永远也只有一个实例,这样当C点击返回时就会返回A了。~~细细一想没发现什么问题,很完美。

二、遇到问题
  然而事实总是残酷的,测试总是牛批的。当测试拿着数据来找我的时候我也懵了。经过调试我发现数据有点不对劲,因为B跳转C的时候会传递一个值(这里记为第一次给C传值),C里面会做一些操作然后更新数据传给B,B接收到数据然后更新第一次传递的值再传给C(这里记为第二次传值)。但是通过log发现第一次和第二次传递的值根本没有变化!
  经过查找我发现了onNewIntent()的问题,这里看看文档怎么解释的:

/**     * This is called for activities that set launchMode to "singleTop" in     * their package, or if a client used the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP}     * flag when calling {@link #startActivity}.  In either case, when the     * activity is re-launched while at the top of the activity stack instead     * of a new instance of the activity being started, onNewIntent() will be     * called on the existing instance with the Intent that was used to     * re-launch it.     *     * <p>An activity will always be paused before receiving a new intent, so     * you can count on {@link #onResume} being called after this method.     *     * <p>Note that {@link #getIntent} still returns the original Intent.  You     * can use {@link #setIntent} to update it to this new Intent.     *     * @param intent The new intent that was started for the activity.     *     * @see #getIntent     * @see #setIntent     * @see #onResume     */    protected void onNewIntent(Intent intent) {    }
翻译:  当Activity启动方式设置成 singleTop,或者程序里面调用startActivity时使用FLAG_ACTIVITY_SINGLE_TOP标签时这个方法会被调用。无论哪种情况只要当Activity在Activity栈的栈顶被重新启动而不是重新生成一个新的Activity实例时,onNewIntent()就会在之前那个已经启动过的Activity里面被调用。    在接收到新意图之前,Activity将始终处于暂停状态,因此您可以依赖此方法后调用onResume。  注意:getIntent() 始终返回的是之前的intent所传的数据,你可以使用setIntent(intent)去更新数据

  通过文档我们需要了解到的信息是:onNewIntent() 这个方法只有当进入一个已经打开过的Activity时才会调用,也就是第一次进入这个Activity时不会调用。而且如果两个acticity之间使用intent传值的话,第二次通过getIntent()获取的值将还是上一次的值!!!

  终于在这里发现了我所遇到的问题所在,开篇我说过我的C使用的SingleTask,而B在跳转前都会finish() 掉自己,所以C一直处于栈顶,所以当第二次跳转C时我的getIntent获取的还是旧的值,所以导致数据没变。

三、实验
下面通过实验来测试下,因为代码简单这里只提供主要的实验思路:
思路:定义两个Activity:A和B。启动模式都设置成SingleTask,A点击跳转B并传一个参数,然后finish A;B在点击跳转A也传递一个参数,用于判断修改第一次A传递给B的值。然后在B里面打印两次获取参数的值。

1、重写的几个主要的生命周期:

public class TestActivity extends BaseActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        LogUtil.zLog().e("onCreate");    }    @Override    protected void onStart() {        super.onStart();        LogUtil.zLog().e("onStart");    }    @Override    protected void onRestart() {        super.onRestart();        LogUtil.zLog().e("onRestart");    }    @Override    protected void onNewIntent(Intent intent) {        super.onNewIntent(intent);        LogUtil.zLog().e("onNewIntent");    }    @Override    protected void onResume() {        super.onResume();        LogUtil.zLog().e("onResume");    }    @Override    protected void onPause() {        super.onPause();        LogUtil.zLog().e("onPause");    }    @Override    protected void onStop() {        super.onStop();        LogUtil.zLog().e("onStop");    }}

这里第一次我传递的是“1”,第二次传递的是“2”。

结果:(这里打印的只有TestActivity 的生命周期)

第一次进入 TestActivity 06-16 13:58:58.889 15959-15959/zz.mk.zgarden E/TAG:  - onCreate06-16 13:58:58.889 15959-15959/zz.mk.zgarden E/TAG:  - onStart06-16 13:58:58.909 15959-15959/zz.mk.zgarden E/TAG:  - onResume//点击离开页面后06-16 13:59:19.239 15959-15959/zz.mk.zgarden E/TAG:  - onPause06-16 13:59:20.060 15959-15959/zz.mk.zgarden E/TAG:  - onStop第二次进入TestActivity 06-16 13:59:31.171 15959-15959/zz.mk.zgarden E/TAG:  - onNewIntent06-16 13:59:31.181 15959-15959/zz.mk.zgarden E/TAG:  - onRestart06-16 13:59:31.181 15959-15959/zz.mk.zgarden E/TAG:  - onStart06-16 13:59:31.191 15959-15959/zz.mk.zgarden E/TAG:  - onResume

根据结果我们能够看到第二次进入的时候onCreate方法压根都没走,onNewIntent正如文档所说第一次也没走。而我们一般获取参数都在onCreate里面获取,所以这样会导致参数不会变化。

既然知道了问题出在哪了,我们就知道怎么解决了。
这里我们只要在onCreate和onNewIntent里面都调用同一个获取参数的方法就好了:

    @Override    protected void onCreate(@Nullable Bundle savedInstanceState){        super.onCreate(savedInstanceState);        getExtraData();    }    @Override    protected void onNewIntent(Intent intent) {        super.onNewIntent(intent);        setIntent(intent);        // intent.getStringExtra("TEST");        getExtraData();    }    private void getExtraData(){        test = getIntent().getStringExtra("TEST");        TextView.setText(test);    }

上面注意在onNewIntent方法里面要调用下setIntent(intent); 不然数据还是不会变化,当然也可以直接使用intent.getStringExtra("TEST"); 获取的数据也是新的。不过充代码复用角度来看的话还是setIntent比较好点。

今天的分享就到这里了,有问题欢迎指出~~