Intent使用

本文详细介绍了Android中Intent的使用,包括显式Intent和隐式Intent的创建与启动,如何在Activity间传递数据,如简单参数、数组、集合、对象(包括Json转换和Serializable、Parcelable序列化),以及Bitmap的传递方法。此外,还讨论了通过全局数据(如Application对象和单例模式)来传递参数的场景和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

I am a slow walker, but I never walk back.
我走得很慢,但是我从来不会后退。 ——林肯

1. Intent基本使用

1.1 使用显式Intent

Intent事Android程序中各组件之间进行交互的一种重要方式,不仅可以指明当前组件想要执行的动作,还可以在不同组件之间进行传递数据。被用于启动活动,启动服务以及发送广播等场景

Activity类中提供一个startActivity()方法,专门用于启动活动,接受一个Intent参数,构建好的Intent传入该方法就可以启动目标活动了。创建一个新的Activity——SecondActivity。

  • 直接使用startActivity()方法跳转:
    public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                startActivity(intent);
            }
    
  • 通过IntentComponentName来启动
    	ComponentName cn = new ComponentName("com.vivo.a11085273.activitytest","com.vivo.a11085273.activitytest.ThirdActivity");
    	Intent intent = new Intent();
    	intent.setComponent(cn);
    	startActivity(intent);
    
  • 通过初始化Intent时指定包名
    Intent intent = new Intent("android.intent.action.MAIN");
    intent.setClassName("com.vivo.a11085273.activitytest", "com.vivo.a11085273.activitytest.ThirdActivity");
    startActivity(intent);
    

1.2 使用隐式Intent

不明确指出我们想要启动哪一个活动,指定了一系列更为抽象的actioncategory等信息,交由系统分析这个Intent,找出合适的Intent去启动。通过Intent的Intent-filter实现。

@Override
            public void onClick(View v) {
                Intent intent = new Intent("com.vivo.a11085273.activitytest.ACTION_START");
                intent.addCategory("com.vivo.a11085273.activitytest.MY_CATEGORY");
                startActivity(intent);
            }

每个Intent只能指定一个action,但是却能指定多个category。可以调用Intent中的addCategory()方法来添加category。

2. Activity间传递数据

一个app一般都是由多个Activity构成,这就涉及到多个Acitivity间数据传递。

返回数据给上一个活动

Activity中还有一个startActivityForResult()方法也适用于启动活动,但是该方法期望活动销毁的时候返回一个结果给上一个活动。

示例:

  • 首先在FirstActivity中设置跳转:
 @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                startActivityForResult(intent,1);
            }
  • 其次,在SecondActivity中设置返回数据:
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_activity);
        Button button2 = (Button) findViewById(R.id.button_2);
        button2.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.putExtra("data_return","Hello FirstActivity");
                setResult(RESULT_OK, intent);
                finish();
            }
        });
    }
  • 最后在FirstActivity中重写onActivityResult()方法得到返回数据:
 @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        switch(requestCode) {
            case 1:
                if (resultCode == RESULT_OK) {
                    String returnedData = data.getStringExtra("data_return");
                    Log.d("FritstActivity",returnedData);
                }
                break;
            default:
        }
    }

如果在SecondActivity中是通过back键返回的,则可以通过在SecondActivity中重写onBackPressed()来解决:

 @Override
    public void onBackPressed() {
        Intent intent = new Intent();
        intent.putExtra("data_return","Hello FirstActivity");
        setResult(RESULT_OK, intent);
        finish();
    }

3. Intent传递复杂数据

3.1 传递简单参数


直接通过调用Intent的putExtra()方法存入数据,然后在获得Intent后调用getXxxExtra获得 对应类型的数据;传递多个的话,可以使用Bundle对象作为容器,通过调用Bundle的putXxx先将数据 存储到Bundle中,然后调用Intent的putExtras()方法将Bundle存入Intent中,然后获得Intent以后, 调用getExtras()获得Bundle容器,然后调用其getXXX获取对应的数据!

3.2 传递数组

  • 写入数组

    bd.putStringArray("StringArray", new String[]{"呵呵","哈哈"});
    //可把StringArray换成其他数据类型,比如int,float等等...
    
  • 读取数组

    String[] str = bd.getStringArray("StringArray")
    

3.3 传递集合

3.3.1 List<基本数据类型或String>

  • 写入集合
intent.putStringArrayListExtra(name, value)
intent.putIntegerArrayListExtra(name, value)
  • 读取集合
 intent.getStringArrayListExtra(name)
 intent.getIntegerArrayListExtra(name)

3.3.2 List<Object>

将list强转成Serializable类型,然后传入(可用Bundle做媒介)

  • 写入集合
 public void onClick(View v) {
                 Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                 Bundle bd = new Bundle();
                 list = new ArrayList<Object>();
                 list.add("nice");
                 list.add("boy");
                 bd.putSerializable("list",list);
                 intent.putExtras(bd);
                 startActivity(intent);
             }
  • 读取集合
Intent intent = getIntent();
        Bundle bd = intent.getExtras();
        List str = (List<Object>) bd.getSerializable("list");
        System.out.println(str.get(0));

Object类需要实现Serializable接口

3.3.3 Map<String, Object>或更复杂

解决方法:在外层套一个List

  • 传递数据
 Map<String, Object> map1 = new HashMap<String, Object>();
                  map1.put("key1", "value1");
                  map1.put("key2", "value2");
                  List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
                  list.add(map1);
                  Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                  Bundle bd = new Bundle();
                  //须定义一个list用于在budnle中传递需要传递的ArrayList<Object>,这个是必须要的
                  bundleList = new ArrayList<>();
                  bundleList.add(list);
                  bd.putParcelableArrayList("list", bundleList);
                  intent.putExtras(bd);
                  startActivity(intent);
  • 读取数据
Intent intent = getIntent();
          Bundle bd = intent.getExtras();
          ArrayList bundleList = bd.getParcelableArrayList("list");
          List<Map<String, Object>> list =(List) bundleList.get(0);
          Map<String, Object> map = list.get(0);
          System.out.println(map.containsKey("key1"));

3.4 传递对象

传递对象的方式有两种:

  • 将对象转换为Json字符串
  • 通过Serializable,Parcelable序列化 不建议使用Android内置的抠脚Json解析器,可使用fastjson或者Gson第三方库!

3.4.1 将对象转换为Json字符串

  • Model:

    public class Book{
        private int id;
        private String title;
        //...
    }
    
    public class Author{
        private int id;
        private String name;
        //...
    }
    
  • 写入数据:

    Book book=new Book();
    book.setTitle("Java编程思想");
    Author author=new Author();
    author.setId(1);
    author.setName("Bruce Eckel");
    book.setAuthor(author);
    Intent intent=new Intent(this,SecondActivity.class);
    intent.putExtra("book",new Gson().toJson(book));
    startActivity(intent);
    
  • 读取数据

    String bookJson=getIntent().getStringExtra("book");
    Book book=new Gson().fromJson(bookJson,Book.class);
    Log.d(TAG,"book title->"+book.getTitle());
    Log.d(TAG,"book author name->"+book.getAuthor().getName());
    

3.4.2 使用Serializable、Parcelable序列化对象

对于使用Parcelable序列化对象,必须重写两个方法:

  • describeContents():用于描述内容接口,一般直接return 0 即可。
  • writeToParcel():用于将想要传递的数据写入到一个Parcelable容器中。

除了这两个方法外,还需要创建一个Parcelable.Creator接口的实现,这个接口中需要实现两个方法:

  • createFromParcel():用于将写入Parcel容器中的数据读出来,用读出来的数据实例化一个对象,并且返回
  • newArray():创建一个长度为size的数组并返回,一般直接返回return T[size] 即可

示例

public class Person implements Parcelable{
        private String mName;
        private String mAddress;
 
        public String getName() {
            return mName;
        }
 
        public void setName(String name) {
            mName = name;
        }
 
        public String getAddress() {
                return mAddress;
        }
 
        public void setAddress(String address) {
            mAddress = address;
        }
 		
 		// 重写describeContents()方法
       @Override
       public int describeContents() {
            return 0;
        }
 		// 重写writeToParcel()方法
        @Override
        public void writeToParcel(Parcel parcel, int i) {
            parcel.writeString(mName);
            parcel.writeString(mAddress);
        }
 		// 创建一个Parcelable.Creator接口
    public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>(){
            @Override
                public Person createFromParcel(Parcel parcel) {
                    Person person = new Person();
                    person.mName = parcel.readString();
                    person.mAddess = parcel.readString();
                    return person;
            }
 
            @Override
            public Person[] newArray(int i) {
                    return new Person[i];
            }
        };
}

这时候对象的传递方式为:

Person obj=new Person();
                obj.setName("Parcelable");
                Intent mIntent = new Intent(MainActivity.this,Activity2.class);
                mIntent.putExtra("Par",obj);
                startActivity(mIntent);

接收数据的方法为:

Person personObject = (Person)getIntent().getParcelableExtra("Par");

前述展示了实现Parcelable接口的方式,这里让自定义的对象实现Serializable接口。

public class Person implements Serializable{
        private String mName;
        private String mAddress;
 
        public String getName() {
            return mName;
        }
 
        public void setName(String name) {
                mName = name;
        }
 
        public String getAddress() {
                return mAddress;
        }
 
        public void setAddress(String address) {
                mAddress = address;
        }
}

这时候就可以使用Intent的putExtra()方法传递这个自定义对象了,在Activity中这样使用:

Person person = new Person();
            person.setName("Hwaphon");
            person.setAddress("Anhui");
 
            Intent intent = new Intent(MainActivity.this,SecondActivity.class);
            intent.putExtra("person",person);
            startActivity(intent);

接收数据的方法为:

  Intent intent = getIntent();
Person person = (Person) intent.getSerializableExtra("person");

使用Serializable方法虽然简单,但是效率不容乐观,它会把整个对象序列化,开销大。

3.5 Intent传递Bitmap

方法一
bitmap默认实现Parcelable接口,直接传递即可

Resources res=getResources();
		Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.ic_launcher);
		
		Bundle b = new Bundle();
        b.putParcelable("bitmap", bmp);
        
        Intent intent = new Intent(this, MainActivity2.class);
        intent.putExtras(b);
        startActivity(intent);

数据的接收为:


Intent intent=getIntent();
		Bundle b=intent.getExtras();
		Bitmap bmp=(Bitmap) b.getParcelable("bitmap");

这种传递方式的缺陷:只能传递相对较小的Bitmap,如果Bitmap大小尺寸过大就会引起代码崩溃。

方式二
首先将Bitmap写进字节流传递出去:

Resources res=getResources();
		Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.ic_launcher);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        //图片大小压缩
        bmp.compress(Bitmap.CompressFormat.PNG, 100, baos);
        byte[] bytes=baos.toByteArray();
        
        Bundle b = new Bundle();
        b.putByteArray("bitmap", bytes);
        
        Intent intent = new Intent(this, MainActivity2.class);
        intent.putExtras(b);
        startActivity(intent);

将bitmap从字节流中恢复:

Intent intent=getIntent();
		Bundle b=intent.getExtras();
		byte[] bytes=b.getByteArray("bitmap");
		
		Bitmap bmp=BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

3.6 定义全局的数据

如果是传递简单的数据,有这样的需求,Activity1 -> Activity2 -> Activity3 -> Activity4, 你想在Activity中传递某个数据到Activity4中,怎么破,一个个页面传么?

如果你想某个数据可以在任何地方都能获取到,你就可以考虑使用 Application全局对象了!
Android系统在每个程序运行的时候创建一个Application对象,而且只会创建一个,所以Application 是单例(singleton)模式的一个类,而且Application对象的生命周期是整个程序中最长的,他的生命 周期等于这个程序的生命周期。如果想存储一些比静态的值(固定不改变的,也可以变),如果你想使用 Application就需要自定义类实现Application类,并且告诉系统实例化的是我们自定义的Application 而非系统默认的,而这一步,就是在AndroidManifest.xml中卫我们的application标签添加:name属性

  • 自定义Application类
class MyApp extends Application {
    private String myState;
    public String getState(){
        return myState;
    }
    public void setState(String s){
        myState = s;
    }
}
  • AndroidManifest.xml中声明:
<application android:name=".MyApp" android:icon="@drawable/icon" 
  android:label="@string/app_name">
  • 在需要的地方调用
final MyApp appState = (MyApp)getApplicationContext();
appState.setState("hello MainActivity");
final String state = appState.getState();
appState.setState("hello secondActivity");
textView1.setText(state);
sendValue.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {

        Intent intent = new Intent(MainActivity.this, SecondActivity.class);
        startActivity(intent);
    }
});	

Application对象是存在于内存中的,也就有它可能会被系统杀死,比如这样的场景:

我们在Activity1中往application中存储了用户账号,然后在Activity2中获取到用户账号,并且显示!

如果我们点击home键,然后过了N久候,系统为了回收内存kill掉了我们的app。这个时候,我们重新 打开这个app,这个时候很神奇的,回到了Activity2的页面,但是如果这个时候你再去获取Application 里的用户账号,程序就会报NullPointerException,然后crash掉~

之所以会发生上述crash,是因为这个Application对象是全新创建的,可能你以为App是重新启动的, 其实并不是,仅仅是创建一个新的Application,然后启动上次用户离开时的Activity,从而创造App 并没有被杀死的假象!所以如果是比较重要的数据的话,建议你还是进行本地化,另外在使用数据的时候 要对变量的值进行非空检查!还有一点就是:不止是Application变量会这样,单例对象以及公共静态变量 也会这样~

3.7 单例模式传参

单例模式的特点就是可以保证系统中一个类有且只有一个实例。

示例

public class XclSingleton  
{  
    //单例模式实例  
    private static XclSingleton instance = null;  
      
    //synchronized 用于线程安全,防止多线程同时创建实例  
    public synchronized static XclSingleton getInstance(){  
        if(instance == null){  
            instance = new XclSingleton();  
        }     
        return instance;  
    }     
      
    final HashMap<String, Object> mMap;  
    private XclSingleton()  
    {  
        mMap = new HashMap<String,Object>();  
    }  
      
    public void put(String key,Object value){  
        mMap.put(key,value);  
    }  
      
    public Object get(String key)  
    {  
        return mMap.get(key);  
    }  
      
} 

设置参数:

XclSingleton.getInstance().put("key1", "value1");  
XclSingleton.getInstance().put("key2", "value2");  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值