记得刚开始学的时候,感觉intent还挺简单,结果现在总是被intent困扰,发现自己太天真了,为了弄清楚,总结一下,
一、onNewIntent
老规矩,先看官方:
大概意思是当Activity被设以singleTop
模式启动,当需要再次响应此Activity启动需求时,会复用栈顶的已有Activity,还会调用onNewIntent方法。并且,再接受新发送来的intent(onNewIntent方法)之前,一定会先执行onPause方法。
二、onNewIntent与启动模式
前提:ActivityA已经启动过,处于当前应用的Activity任务栈中;
当ActivityA的LaunchMode为Standard时:
由于每次启动ActivityA都是启动新的实例,和原来启动的没关系,所以不会调用原来ActivityA的onNewIntent方法
当ActivityA的LaunchMode为SingleTop时:
如果ActivityA在栈顶,且现在要再启动ActivityA,这时会调用onNewIntent()方法 ,生命周期顺序为:
onCreate—>onStart—>onResume—onPause
—>onNewIntent
—>onResume
当ActivityA的LaunchMode为SingleInstance
,SingleTask
:
如果ActivityA已经在任务栈中,再次启动ActivityA,那么此时会调用onNewIntent()方法,生命周期调用顺序为:
onPause—>跳转其它页面—>onCreate—>onStart—>onResume—onPause—>跳转A—>onNewIntent
—>onRestart
—>onStart
—>onResume
总的来说,只对SingleTop
(且位于栈顶),SingleTask
和SingleInstance
(且已经在任务栈中存在实例)的情况下,再次启动它们时才会调用,即只对startActivity有效,对仅仅从后台切换到前台而不再次启动的情形,不会触发onNewIntent。
三、实例:
在android中,从另一个activity开始一个新的activity并向它传递一些数据是一件简单而基本的事情。但是,如果你希望一个已经运行的活动出现在前台,并向它传递数据,这可能有点棘手。
首先,在默认情况下,如果你使用intent调用一个activity,即使另一个实例已经在运行,也会创建并显示该activity的一个新的istance。为了避免这种情况,必须将活动标记为不应该多次实例化。为了实现这一点,我们将在AndroidManifest.xml中将活动的launchMode设置为singleTop
<activity android:name=".SecondActivity"
android:launchMode="singleTop"
></activity>
<activity
android:name=".FirstActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
这样,当我们使用intent调用此活动时,如果存在现有实例,系统将把请求跳转到它。我们通常的onCreate方法这次将不会运行。
正如其名称所示,它在创建活动时运行,而这一次它已经存在,因此将调用onNewIntent()方法。
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);//must store the new intent unless getIntent() will return the old one
processExtraData();
}
不要忘记,我们可以在onCreate中以正常的方式接收数据,当活动第一次创建时,由于系统可以很容易地在回轮中终止活动,如果发生这种情况,将调用onCreate方法而不是onNewIntent。
因此,一个优雅的解决方案可以调用相同的函数来处理来自onCreate和onNewIntent的跳转。
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
processExtraData();
}
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);//must store the new intent unless getIntent() will return the old one
processExtraData()
}
private void processExtraData(){
Intent intent = getIntent();
//use the data received here
}
完整代码如下:
FirstActivity.java
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
displayIntentData();
findViewById(R.id.sendButton).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("key",((EditText)findViewById(R.id.dataToSend)).getText().toString());
startActivity(intent);
//注意我们在这里没有调用finish()方法
}
});
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e("onNewIntent","First Activity OnNewIntent is called");
setIntent(intent);//must store the new intent unless getIntent() will return the old one
displayIntentData();
}
private void displayIntentData(){
Intent intent = getIntent();
TextView tv = (TextView)findViewById(R.id.intentData);
Bundle extras=intent.getExtras();
if(extras!=null){
tv.setText("Data received: "+extras.getString("key"));
}else{
tv.setText("No extradata received");
}
}
}
SecondActivity.java
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
displayIntentData();
findViewById(R.id.sendButton).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this,FirstActivity.class);
intent.putExtra("key",((EditText)findViewById(R.id.dataToSend)).getText().toString());
startActivity(intent);
//注意我们在这里没有调用finish()方法
}
});
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
displayIntentData();
}
private void displayIntentData(){
Intent intent = getIntent();
TextView tv = (TextView)findViewById(R.id.intentData);
Bundle extras=intent.getExtras();
if(extras!=null){
tv.setText("Data received: "+extras.getString("key"));
}else{
tv.setText("No extradata received");
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myonnewintenttest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".SecondActivity"
android:launchMode="singleTop"
></activity>
<activity
android:name=".FirstActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FirstActivity">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/intentData"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<EditText
android:layout_height="wrap_content"
android:id="@+id/dataToSend"
android:layout_width="fill_parent"
android:hint="Data to send"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/intentData"
/>
<Button
android:text="Send"
android:id="@+id/sendButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/dataToSend"
/>
</androidx.constraintlayout.widget.ConstraintLayout>