zoukankan      html  css  js  c++  java
  • 【转】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
    來源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    mysql 远程登陆不上
    hdu 5339 Untitled【搜索】
    SqlServer 书目
    passwordauthentication yes
    oracle 11g RAC ocfs2
    Oracle 11g RAC database on ASM, ACFS or OCFS2
    CentOS ips bonding
    Oracle 11g RAC features
    openStack 王者归来之 trivial matters
    openstack windows 2008 img
  • 原文地址:https://www.cnblogs.com/stars-one/p/8270667.html
Copyright © 2011-2022 走看看