• 【转】Android 之最新最全的Intent传递数据方法


    原文地址:https://www.jianshu.com/p/1169dba99261

    intent传递数据

    为什么要和intent单独拿出来讲,因为Intent传递数据也是非常重要的

    一、简单的传递数据

    二、传递数组

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

    读取数组:

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

    三、传递集合

    1)List<基本数据类型或String>

    intent.putStringArrayListExtra(name, value)
    intent.putIntegerArrayListExtra(name, value)
    

    读取集合:

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

    2)List< Object>

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

    写入集合:

    putExtras(key, (Serializable)list)
    

    读取集合:

    (List<Object>) getIntent().getSerializable(key)
    

    PS:Object类需要实现Serializable接口

    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();  
    intent.setClass(MainActivity.this,ComplexActivity.class);  
    Bundle bundle = new Bundle();  
    
    //须定义一个list用于在budnle中传递需要传递的ArrayList<Object>,这个是必须要的  
    ArrayList bundlelist = new ArrayList();   
    bundlelist.add(list);   
    bundle.putParcelableArrayList("list",bundlelist);  
    intent.putExtras(bundle);                
    startActivity(intent); 
    

    四、Intent传递对象

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


    1)将对象转换为Json字符串

    Gson解析的例子:

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

    2)使用Serializable,Parcelable序列化对象

    但是不知道你有没有发现,putExtra()方法中所支持的数据类型是有限的,虽然常用的一些数据类型它都会支持,但是当你想去传递一些自定义对象的时候就会发现无从下手。不用担心,下面我们就学习一下使用Intent 来传递对象的技巧。

    方式一:Serializable 方式

    Serializable 是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。至于序列化的方法也很简单,只需要让一个类去实现Serializable 这个接口就可以了。
    比如说有一个Person 类,其中包含了name 和age 这两个字段,想要将它序列化就可以这样写:

    public class Person implements Serializable{  
    private String name;  
    private int age;  
    public String getName() {  
            return name;  
        }  
    public void setName(String name) {  
            this.name = name;  
        }  
    public int getAge() {  
            return age;  
            }  
    public void setAge(int age) {  
            this.age = age;  
        }  
    }  
    

    其中get、set 方法都是用于赋值和读取字段数据的,最重要的部分是在第一行。这里让Person 类去实现了Serializable 接口,这样所有的Person 对象就都是可序列化的了。

    接下来在FirstActivity 中的写法非常简单:

    Person person = new Person();  
    person.setName("Tom");  
    person.setAge(20);  
    Intent intent = new Intent(FirstActivity.this, SecondActivity.class);  
    intent.putExtra("person_data", person);  
    startActivity(intent); 
    

    可以看到,这里我们创建了一个Person 的实例,然后就直接将它传入到putExtra()方法中了。由于Person 类实现了Serializable 接口,所以才可以这样写。

    接下来在SecondActivity 中获取这个对象也很简单,写法如下:

    Person person = (Person) getIntent().getSerializableExtra("person_data"); 
    
    方式二:Parcelable

    除了Serializable 之外,使用Parcelable 也可以实现相同的效果,不过不同于将对象进行序列化,Parcelable 方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent 所支持的数据类型,这样也就实现传递对象的功能了。
    下面我们来看一下Parcelable 的实现方式,修改Person 中的代码,如下所示:

    public class Person implements Parcelable {  
        private String name;  
        private int age;  
          
        @Override  
        public int describeContents() {  
            // TODO Auto-generated method stub  
            return 0;  
        }  
      
        @Override  
        public void writeToParcel(Parcel dest, int flags) {  
            // TODO Auto-generated method stub  
            dest.writeString(name);  
            dest.writeInt(age);  
        }  
        public static final Parcelable.Creator<Person> CREATOR=new Parcelable.Creator<Person>() {  
      
            @Override  
            public Person createFromParcel(Parcel source) {  
                // TODO Auto-generated method stub  
                Person person=new Person();  
                person.name=source.readString();  
                person.age=source.readInt();  
                return person;  
            }  
      
            @Override  
            public Person[] newArray(int size) {  
                // TODO Auto-generated method stub  
                return new Person[size];  
            }  
        };  
      
    }  
    

    Parcelable 的实现方式要稍微复杂一些。可以看到,首先我们让Person 类去实现了Parcelable 接口,这样就必须重写describeContents()和writeToParcel()这两个方法。其中describeContents()方法直接返回0 就可以了,而writeToParcel()方法中我们需要调用Parcel的writeXxx()方法将Person 类中的字段一一写出。注意字符串型数据就调用writeString()方法,整型数据就调用writeInt()方法,以此类推。

    除此之外,我们还必须在Person 类中提供一个名为CREATOR 的常量,这里创建了Parcelable.Creator 接口的一个实现,并将泛型指定为Person。接着需要重写createFromParcel()和newArray()这两个方法,在createFromParcel()方法中我们要去读取刚才写出的name 和age字段,并创建一个Person 对象进行返回,其中name 和age 都是调用Parcel 的readXxx()方法读取到的,注意这里读取的顺序一定要和刚才写出的顺序完全相同。而newArray()方法中的实现就简单多了,只需要new 出一个Person 数组,并使用方法中传入的size 作为数组大小就可以了。

    接下来在FirstActivity 中我们仍然可以使用相同的代码来传递Person 对象,只不过在SecondActivity 中获取对象的时候需要稍加改动,如下所示:

    Person person = (Person) getIntent().getParcelableExtra("person_data");  
    

    注意这里不再是调用getSerializableExtra()方法,而是调用getParcelableExtra()方法来获取传递过来的对象了,其他的地方都完全相同。这样我们就把使用Intent 来传递对象的两种实现方式都学习完了,对比一下,Serializable的方式较为简单,在这里强调一下,网上很多博客很多文章都说Parcelable要比Serializable效率要高,其实不然,在读取速度方面Serializable其实他要比Parcelable更快,具体我们可以看一下这篇文章
    http://www.jianshu.com/p/fcc59fb523b6

    五、Intent传递Bitmap

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

    Bitmap bitmap = null;
    Intent intent = new Intent();
    Bundle bundle = new Bundle();
    bundle.putParcelable("bitmap", bitmap);
    intent.putExtra("bundle", bundle);
    

    六、定义全局数据,传递数据

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

    显然不科学是吧,如果你想某个数据可以在任何地方都能获取到,你就可以考虑使用 Application全局对象了!

    关键部分代码:

    第一步自定义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">
    
    第三步在需要的地方调用:
    class Blah extends Activity {
        @Override
        public void onCreate(Bundle b){
            ...
        MyApp appState = ((MyApp)getApplicationContext());
        String state = appState.getState();
            ...
        }
    }
    

    高逼格写法
    :在任何位置都能获取到Application全局对象。

    Applicaiton是系统的一个组件,他也有自己的一个生命周期,我们可以在onCraete里获得这个 Application对象。贴下修改后的代码吧!

    class MyApp extends Application {
        private String myState;
        private static MyApp instance;
        
        public static MyApp getInstance(){
            return instance;
        }
        
        
        public String getState(){
            return myState;
        }
        public void setState(String s){
            myState = s;
        }
        
        @Override
        public void onCreate(){
            onCreate();
            instance = this;
        }
     
    }
    

    然后在任意地方我们就可以直接调用:MyApp.getInstance()来获得Application的全局对象!

    注意事项:
    Application对象是存在于内存中的,也就有它可能会被系统杀死,比如这样的场景:
    我们在Activity1中往application中存储了用户账号,然后在Activity2中获取到用户账号,并且显示!

    如果我们点击home键,然后过了N久候,系统为了回收内存kill掉了我们的app。这个时候,我们重新 打开这个app,这个时候很神奇的,回到了Activity2的页面,但是如果这个时候你再去获取Application 里的用户账号,程序就会报NullPointerException,然后crash掉~
    之所以会发生上述crash,是因为这个Application对象是全新创建的,可能你以为App是重新启动的, 其实并不是,仅仅是创建一个新的Application,然后启动上次用户离开时的Activity,从而创造App 并没有被杀死的假象!所以如果是比较重要的数据的话,建议你还是进行本地化,另外在使用数据的时候 要对变量的值进行非空检查!还有一点就是:不止是Application变量会这样,单例对象以及公共静态变量 也会这样~

    七、单例模式传参

    上面的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");  



    作者:侯蛋蛋_
    链接:https://www.jianshu.com/p/1169dba99261
    來源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    javascript无提示关闭窗口,兼容IE,Firefox
    vbs简单制作U灵大盗带发送功能的代码
    正则表达式提取网址、标题、图片等一例(.Net Asp Javascript/Js)的实现
    在asp.net中保持Session的有效期
    批处理编程 介绍
    IIS日志清理CMD版,VBS版,JS版,WSH版
    正则表达式提取图片地址
    用U盘安装GNU/Linux
    三核浏览器Lunascape新版发布
    黑客基础之DOS(最齐全)
  • 原文地址:https://www.cnblogs.com/stars-one/p/8270667.html
Copyright © 2020-2023  润新知