美文网首页
Intent基本使用

Intent基本使用

作者: 者文_ | 来源:发表于2019-08-10 16:07 被阅读0次

    1. Intent使用

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

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

    1.2 显式Intent

    显示Intent指明了要启动的目标类。

    例如:创建一个新的Activity——SecondActivity

    • 直接使用startActivity()跳转

      Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                      startActivity(intent);
      
    • 通过Intent的ComponentName来启动

      ComponentName cn = new ComponentName("com.baiheng.activitytest","com.baiheng.activitytest.ThirdActivity");
        Intent intent = new Intent();
        intent.setComponent(cn);
        startActivity(intent);
      
    • 通过初始化Intent指定包名

      Intent intent = new Intent("android.intent.action.MAIN");
      intent.setClassName("com.baiheng.activitytest", "com.baiheng.activitytest.ThirdActivity");
      startActivity(intent);
      

    以上的几种方法都指明了要跳转的目标活动,这种处理方式也叫做显式Intent。

    1.2 隐式Intent

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

    <activity android:name=".SecondActivity">
                <intent-filter>
                    <action android:name="com.baiheng.activitytest.action.START" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>
    
    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_START);     intent.addCategory(Intent.CATEGORY_DEFAULT);
                    startActivity(intent);
    

    每个Intent只能指定一个action,但是却能指定多个category

    <intent-filter>标签中再配置一个<data>标签,用于更精准地指定当前活动能够响应什么类型的数据。<data>标签中主要可以配置一下内容:

    • android:scheme:用于指定数据的协议部分,如示例:http
    • android:host:用于指定数据的主机名部分,如示例www.baidu.com
    • android:port:用于指定数据的端口部分,一般紧随在主机名之后
    • android:path:用于指定主机名和端口之后的部分,如一段网址跟在主机名之后的内容
    • android:mimeType:用于指定可以处理的数据类型,允许使用通配符的方式进行指定。

    只有<data>标签中指定的内容和Intent中携带的Data完全一致,当前活动才能够相应该Intent。一般不会在<data>标签中指定过多内容

    2. 传递数据

    在Activity的基本使用章节里简单介绍了Intent是如何传递数据的,Intent中提供了一系列putExtra()方法的重载,可以把传递的数据暂存在Intent中,启动了另一个活动等即可将数据从中取出。

    这里介绍一下Intent传递的数据类型与方法

    2.1 简单数据

    image

    简单数据的存取示例如上图所示。

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

    2.2 传递数组

    • 写入数组

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

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

    总结

    调用Bundle的putXXXArray()写入数组,通过getXXXArray()读取数组

    2.3 传递集合

    2.3.1 List<基本数据类型/String>

    • 写入集合

      intent.putStringArrayListExtra(name, value)
      intent.putIntegerArrayListExtra(name, value)
      
    • 读取集合

       intent.getStringArrayListExtra(name)
       intent.getIntegerArrayListExtra(name)
      

    总结

    调用Intent的putXXXArrayListExtra()写入集合,最后通过getXXXArrayListExtra()读取集合。

    2.3.2 List<Object>

    如果要传递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接口

    2.3.3 Map<String, Object>,或更复杂

    如果要传递这种类型的数据,解决的方法是:在外层套一个list

    • 传递数据
    public class MainActivity extends AppCompatActivity {
    
        private ArrayList bundleList;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button sendValue = (Button) findViewById(R.id.button_sendValue);
            sendValue.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Map<String, Object> map1 = new HashMap<String, Object>();
                    map1.put("key1", "value1");
                    map1.put("key2", "value2");
                    //在map数据外层套一层List
                    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);
                }
            });
        }
    }
    
    • 读取数据
    public class SecondActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
            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"));
        }
    }
    

    总结

    • 对于map<String, Object>或者更复杂的数据,Intent在暂存数据时,首先在数据外围套一层List,将套层过的数据作为新建ArrayList的元素添加进去,然后调用Bundle的putParcelableArrayList()
    • 如果要取数据,先获取Bundle,然后调用getParcelableArrayList(),接着调用get()方法获取到添加了套层的数据,接着调用get()方法,即可获得map数据

    2.4 传递对象

    传递对象的方式又两种:

    • 将对象转换为Json字符串
    • 通过Serializable,Parcelable序列化

    2.4.1 转为Json字符串

    示例:

    假定Intent要传递的数据对象如下:

    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));    //转为Json字符串
    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());
    

    2.4.2 Serializable、Parcelable序列化

    • Parceable序列化

      对于使用了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");
      
    • Serializable序列化

      实现对象的Serializable序列化比较简单,只要让自定义的对象实现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虽然简单,但是效率不容乐观,它会把整个对象序列化,开销大

    2.5 传递Bitmap

    关于Bitmap数据,Intent有两种传递方式:

    • 直接传递
    • 将Bitmap写进字节流传递

    2.5.1 直接传递

    因为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");
    

    2.5.2 字节流传递

    关于Bitmap的Intent另一种传递方式就是写进字节流传递出去:

    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);
    

    数据的恢复方式为:

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

    2.6 定义全局数据

    如果你想某个数据可以在任何地方都能获取到,你就可以考虑使用 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变量会这样,单例对象以及公共静态变量 也会这样~

    2.7 单例模式传参

    上面的Application就是基于单例的,单例模式的特点就是可以保证系统中一个类有且只有一个实例。 这样很容易就能实现,在A中设置参数,在B中直接访问了。这是几种方法中效率最高的。

    示例

    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");  
    

    相关文章

      网友评论

          本文标题:Intent基本使用

          本文链接:https://www.haomeiwen.com/subject/mhmrjctx.html