转载请注明出处:http://blog.csdn.net/cc_xz/article/details/61205788
前言:
上一篇学习了使用Intent在Activity间进行跳转,以及在跳转的时候进行传值,这些只使用了很少一部分的Intent功能,而本篇我们将继续深入学习Intent的一些其他功能。
在本篇中,你将了解到:
1.隐式跳转Intent。
2.通过Intent打开其他APP。
3.通过Intent跳转至其他Activity后,关闭该Activity时返回数据。
4.通过Intent发送Bundle类型的数据。
准备工作:
首先我们要创建两个Activity,以及他们的Layout,再到Layout中添加需要使用到的组件,代码如下:
MainActivity的Layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/TextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="这是主活动" />
<Button
android:id="@+id/ButtonIntentHide"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="隐式跳转" />
<Button
android:id="@+id/ButtonIntentHttp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="打开浏览器" />
<Button
android:id="@+id/ButtonIntentReturnData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="返回数据" />
</LinearLayout>
MainActivity:
public class MainActivity extends AppCompatActivity {
private String TAG = "来自于MainActivity";
private Button mButtonIntentHide, mButtonIntentHttp, mButtonIntentReturnData;
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonIntentHide = (Button) findViewById(R.id.ButtonIntentHide);
mButtonIntentHttp = (Button) findViewById(R.id.ButtonIntentHttp);
mButtonIntentReturnData = (Button) findViewById(R.id.ButtonIntentReturnData);
mTextView = (TextView) findViewById(R.id.TextView);
mButtonIntentHide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
mButtonIntentHttp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
mButtonIntentReturnData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
}
TwoActivity的Layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="这是第二个Activity" />
<Button
android:id="@+id/ButtonIntentReturn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="返回第一个Activity" />
</LinearLayout>
TwoActivity:
public class TwoActivity extends AppCompatActivity {
private Button mButtonIntentReturn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two);
mButtonIntentReturn = (Button) findViewById(R.id.ButtonIntentReturn);
mButtonIntentReturn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
}
在TextView组件中新添了三个属性,其中marginBottom是从本组件为中心,向下增加10dp的距离。即把下面的组件再往下挤10dp。marginTop同理,是以本组件为中心,往上填补出10dp。gravity是这个组件居中显示。实现效果如下:
除此之外以上的代码在之前的文章中都讲解过了,这里便不再复述了。
隐式Intent跳转:
在前一篇的学习中Intent跳转的方式,我们一般称之为显式Intent,很容易理解,我们明确的设定了跳转的源Activity和目标Activity,而隐式Intent,则是通过在AndroidManifest.xml中的Intent过滤器(intent-filter)来对不同的Activity进行标记,从而进行跳转。我想你可能感觉到了,这种方式比较繁琐,根本没有显式Intent使用起来方便(知道类名就可以了,对吧?),这是因为,隐式Intent常常被应用在不同APP之间的跳转。
你想一想,你使用一些程序的时候,在登录时,可以选择通过QQ、微信进行登录,那你使用的程序为什么能打开QQ或微信呢?使用显式Intent通过类名指定?这….不太可能吧?
现在你需要通过前面的知识来创建两个Activity,并且打开AndroidManifest.xml,并在第二个Activity中添加以下代码:
<activity android:name=".TwoActivity">
<intent-filter>
<action android:name="ACTION_START"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.MY_CATEGORY"/>
</intent-filter>
</activity>
现在来解释一下,第二行标签名很容易理解,就是创建一个Intent的过滤器,第三行是给这个Activity设置一个名称,在代码中使用过滤器时会使用到。第四行是当我们在代码中找到这个过滤器时,设置了一种过滤方式,即如果使用了隐式Intent,但是没有过滤出合适的Activity,就反馈跳转失败。第五行是我们将使用到的,通过这行来确定究竟要往哪里跳转。
现在来到MainActivity中,在mButtonIntentHide的监听器中添加如下代码:
mButtonIntentHide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("ACTION_START");
intent.addCategory("android.intent.category.MY_CATEGORY");
startActivity(intent);
}
});
这次初始化Intent的参数变成了我们在AndroidManifest.xml对第二个Activity定义的action标签中的内容。即通过此名称,来确定Intent要使用哪个过滤器。然后通过addCategory添加过滤器,即:通过“ACTION_START”找到TwoActivity,然后通过android.intent.category.MY_CATEGORY得知需要执行什么操作,这里是Intent跳转,而MY_CATEGORY是一个自定义名称。
接着到TwoActivity的mButtonIntentReturn的监听器中添加一行代码:
finish();
这行代码的作用是销毁当前的Activity。此时的效果为:
打开特定网址:
如果你掌握了隐式Intent跳转,那么相信通过Intent打开浏览器也是很简单的事情,代码如下:
mButtonIntentHttp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
}
});
这里Intent的参数变成Intent自带的一个参数,它的值为:
public static final String ACTION_VIEW = "android.intent.action.VIEW";
我们可以把它理解为,这是Android系统自带的过滤器,通过这个过滤器我们可以打开Android中的其他应用。而具体打开哪个应用,则是通过setData()中的参数来决定。
通过源码我们可以看到,setData()接收一个Uri的类型(统一资源标识符,注意不是Url),那么我们怎么获得一个Uri类型参数呢?就是通过Uri.pares(),通过这个方法我们可以把一个字符串转换成Uri参数。
例如,我们希望打开浏览器,则是http开头,后面是网址。如果希望拨打电话,则是tel开头,后面是电话号码。这里只演示如何打开我们希望看到的网站,打开其他程序的方式都很类型,你可以在网上查看相关教程。
效果如下:
返回Activity时获得数据:
如果我们通过源Activity跳转至目标Activity后,用户经过一些操作,仍会回到源Activity中,并且可能还需要带回一些数据,这个时候你可以通过前面所讲的内容完成这个需求,即:在目标Activity中创建Intent,并且给予Intent赋值。这样确实可以实现,不过下面我们要了解的是,直接在源Activity中定义,在返回时会收到某值,并且通过特定的方法来处理这个值。MainActivity中代码如下:
mButtonIntentReturnData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, TwoActivity.class);
startActivityForResult(intent, 10);
}
});
可以看出,确实只是启动Intent的方法不同了,并且除了Intent以外,还接受一个int类型的Key值。这很容易理解,而Key值的作用,请继续往下看。TwoActivity中的代码如下:
mButtonIntentReturn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra("ReturnData", "我觉得你叫第一个Activity更好听");
setResult(RESULT_OK, intent);
finish();
}
});
你发现了什么?使用Intent的方式变成了setResult(),并且这个方法还接受一个奇怪的参数,我们之前并没有定义这个变量,哦..那肯定是系统自带的变量了,这里你可以使用这个变量来确定你返回的Key值,也可以自己定义int类型的变量作为Key值。
如果你把finish();注释掉再运行程序你会发现什么?根本没有返回到第一个Activity。这是因为startActivityForResult()和setResult()是配套使用的,你并不能使用startActivity()来返回,因为那样MainActivity根本不会收到Key值,startActivityForResult()也就没有意义了。
不过这个时候你可能觉得这样做很繁琐,而且没有什么可以提高处理效率的代码发生,前面所说的10的Key值也没有被应用。不过通过下面的代码,你应该就了解了,下面是MainActivity的代码:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 10:
if (resultCode == -1) {
mTextView.setText(data.getStringExtra("ReturnData"));
}
break;
}
}
我们将重写一个叫onActivityResult的接口,这个接口在你使用了startActivityForResult()后就会被监听。它给了你三个参数,第一个参数requestCode是在startActivityForResult()中定义的Key值,它用来判断出第三个参数data是由哪个Activity反馈回来的(你可能使用多个startActivityForResult())。而第二个参数resultCode则是在TwoActivity中定义的Key值,用于确定当前的data是由TwoActivity中的哪个Intent发送的反馈(可能有多个)。
当你知道三个参数的作用,上面的代码就很好理解了,首先通过switch判断,来使用requestCode确定源Activity。再通过if判断resultCode是源Activity中哪个Intent。看到这里我想你可以理解了,在TwoActivity中使用的RESULT_OK变量,它的值就是-1。
后面就是把接收到的Intent的值收到,并且赋值给TextView。实现的效果如下:
传值Bundle类型的参数:
你可能会发现通过Intent传值是使用键值对的方式传递的,也就是Key值+Value之间相互绑定,通过Key值的判断来取出Value数据,而Bundle也是使用这种方式。
那么你可能要问了,既然我已经掌握了使用Intent传值,那么为什么还要学习Bundle传值呢?
这是因为,由于Intent的传值功能是封装了Bundle,所以使用起来更方便,但是缺点是并不能传递对象。而Bundle虽然可以把对象存储起来,但是其本身并不能在多个Activity或者类中传递。这时候就需要通过Intent配合Bundle来一起使用了。
概况的说:Intent旨在数据传递,bundle旨在存取数据,当然intent也提供一部分数据的存取,但比起bundle就显得不专业,不灵活。
首先来看MainActivity中的代码:
mButtonIntentReturnData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, TwoActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("BundleKey", 99);
intent.putExtra("IntentKey", bundle);
startActivityForResult(intent, 10);
}
});
可以看到,首先我们创建了一个Bundle的对象,并且使用putInt()存储了一个int类型的值。你可以自己通过Android Stuido的方法浏览功能查看Bundle都可以存储哪些类型的数据。接着Bundle将作为一个参数被放到了Intent中。
这个时候如果你看了Bundle都可以存储哪些数据后可能会发现,并没有找到存储某对象的方法,这是因为,如果要将对象存储到Bundle中,是需要将对象序列化,然后传递序列化值,从而实现的对象传递。此处不表。
然后TwoActivity中的代码如下:
mButtonIntentReturn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle bundle = getIntent().getBundleExtra("IntentKey");
int value = bundle.getInt("BundleKey", 1);
value = value * value;
Intent intent = new Intent();
intent.putExtra("ReturnData", "我觉得你叫第一个Activity更好听" + value);
setResult(RESULT_OK, intent);
finish();
}
});
我们首先通过getIntent()将Bundle取出,然后再通过Key值获取到里面存放的int类型数据,并且存放到一个int变量中。接着对这个值进行处理(….别吐槽我相乘处理….),然后在作为参数放到Intent中,接着返回。
实现效果如下:
后记:
相对前面的文章,本篇的篇幅较长,不过个人认为写的也比较细致,基本也通过两篇将Intent的日常应用到的东西全部写到了,如果你是大神,那么请吐槽….如果你是初学者,那么请多照着代码敲一敲。