精华内容
下载资源
问答
  • 通过创建了一个manager来统一回调,整个app用同一份机制来同步UI代码:/*** Created by jing on 2017/6/20.* 页面间回调 以及传递~~*/import android.app.Activity;import and...

    第一句

    剑走偏锋~

    需求:实现下级页面回调更新上级页面

    难点:无法获取上级页面的实例对象,通过上级页面的实例对象调用其public方法的路走不通了

    实现:通过创建了一个manager来统一回调,整个app用同一份机制来同步UI

    代码:

    /**

    * Created by jing on 2017/6/20.

    * 页面间回调 以及传递~~

    */

    import android.app.Activity;

    import android.content.Context;

    import android.content.Intent;

    import java.util.HashMap;

    import java.util.Map;

    public class KapActivityInfoTransferManager {

    /***************************************************************************************************/

    /*********************************************回调更新***********************************************/

    /***************************************************************************************************/

    /**

    * InfoTransferModelInterface 不带tag的回调

    * InfoTransferTagModelInterface 带tag的回调

    * */

    public interface InfoTransferModelInterface{

    void changeUIByModel(T model);

    }

    // ************* 经过我的使用发现 想法有点错误,于是改了改,原因自己体会~~ **************

    // /**

    // * 上级页面绑定更新

    // * BindChangeModel 上级页面注册回调

    // * @param context 上级页面

    // * */

    // public static void BindChangeModel(Context context, InfoTransferModelInterface changeModel){

    // String key = keyByContext(context);

    // BindAction(key,changeModel);

    // }

    // public static void BindChangeModel(String activityName,InfoTransferModelInterface changeModel){

    // BindAction(activityName,changeModel);

    // }

    /**

    * 上级页面绑定更新

    *

    * @param activityClass 下级页面的activity Class

    * @param changeModel 回调更新注册

    */

    public static void BindChangeModel(Class activityClass, InfoTransferModelInterface changeModel){

    String key = keyByContext(activityClass);

    BindAction(key,changeModel);

    }

    public static void BindChangeModel(String activityName,InfoTransferModelInterface changeModel){

    BindAction(activityName,changeModel);

    }

    public static void BindChangeModel(Intent activityIntent,InfoTransferModelInterface changeModel){

    String key = activityIntent.getComponent().getClassName();

    if (key == null) return;

    BindAction("class " + key,changeModel);

    }

    // ************* 经过我的使用发现 想法有点错误,于是改了改,原因自己体会~~ **************

    // /**

    // * 下一级页面更新上级页面的函数

    // *

    // * PostChangeByModel 下级页面发起回调

    // * @param activityClass 上级页面的class

    // * */

    // public static void PostChangeByModel(Class activityClass,T model){

    // String key = keyByContext(activityClass);

    // PostAction(model,key);

    // }

    // public static void PostChangeByModel(String activityName,T model) {

    // PostAction(model,activityName);

    // }

    /**

    * 下一级页面更新上级页面的函数

    *

    * @param model的范型

    * @param context 当前页面的context

    * @param model 回调更新的model

    */

    public static void PostChangeByModel(Context context,T model){

    String key = keyByContext(context);

    PostAction(model,key);

    }

    public static void PostChangeByModel(String activityName,T model) {

    PostAction(model,activityName);

    }

    /***************************************************************************************************/

    /*********************************************下面都是私有方法 不用管的***********************************************/

    /***************************************************************************************************/

    /**

    * 页面间消息传递

    * 采用匿名累,超微量级别的,用于页面间回调更新

    * 实时回调,startActivityForResult是等待上一个页面finish才会调用

    * */

    // 变量

    private static KapActivityInfoTransferManager share = new KapActivityInfoTransferManager();

    private KapActivityInfoTransferManager(){}//单利模式

    private Map hashMap = new HashMap<>();

    /**

    * 下面都是私有方法了::::

    *

    * BindAction 上级页面注册回调

    * PostAction 下级页面发起回调

    * */

    private static void BindAction(String key,InfoTransferModelInterface changeModel){

    if (changeModel == null) return;

    if (key == null) return;

    share.hashMap.put(key,changeModel);

    }

    private static void PostAction(T model,String key){

    if (key == null) return;

    InfoTransferModelInterface infoTransferModelInterface = share.hashMap.get(key);

    if (infoTransferModelInterface == null) return;// 不存在

    try {

    infoTransferModelInterface.changeUIByModel(model);

    }catch (Exception e){// 野指针

    share.hashMap.remove(infoTransferModelInterface);

    }

    }

    /**

    * keyByContext 辅助方法,获取key

    */

    private static String keyByContext(Context context){

    if (context == null) return null;

    return context.getClass().toString();

    }

    private static String keyByContext(Class activityClass){

    if (activityClass == null) return null;

    return activityClass.toString();

    }

    }

    使用(一):

    场景:a activity start b activity

    b获取了一张图片 在 a的image上显示出来

    a: KapMineCenterActivity

    b: KapChangeImageActivity

    // a 页面

    KapActivityInfoTransferManager.BindChangeModel(KapChangeImageActivity.class, new KapActivityInfoTransferManager.InfoTransferModelInterface() {

    @Override

    public void changeUIByModel(Bitmap model) {

    KapMineCenterActivity.this.imageView.setImageBitmap(model);

    }

    });

    // b页面

    // KapMineCenterActivity.class 就是a的class(类名绑定的)

    KapActivityInfoTransferManager.PostChangeByModel( this,bitmap);

    使用(二):

    场景:注册页面和忘记密码页面都跳转到设置密码页面,设置密码页面有个确定按钮。

    当注册页面跳转到设置密码时候,点击确定跳到完善资料

    当忘记密码跳转的设置密码时候,点击确定跳到主页

    a:

    b:KapPasswordSetActivity.class

    代码:

    // 注册页面

    private void startPassWordSetingActivity(){

    // 跳到设置密码

    startActivity(new Intent(this, KapPasswordSetActivity.class));

    KapActivityInfoTransferManager.BindChangeModel("KapPasswordSetActivity", new KapActivityInfoTransferManager.InfoTransferModelInterface() {

    @Override

    public void changeUIByModel(KapPasswordSetActivity model) {

    //跳到完成资料页面

    startActivity(new Intent(model, KapCompleteMaterialActivity.class));

    }

    });

    }

    // 忘记密码页面

    private void startPassWordSetingActivity(){

    // 跳到设置密码

    startActivity(new Intent(this, KapPasswordSetActivity.class));

    KapActivityInfoTransferManager.BindChangeModel("KapPasswordSetActivity", new KapActivityInfoTransferManager.InfoTransferModelInterface() {

    @Override

    public void changeUIByModel(KapPasswordSetActivity model) {

    KapApplication.homeActivityChangeAction();//跳到主页

    }

    });

    }

    // 设置密码页面

    private void okButtonAction(){

    KapActivityInfoTransferManager.PostChangeByModel(this,"KapPasswordSetActivity");

    }

    更多使用:看你们需要了~

    注意!!! 因为,我的这些操作都是在mainthread的,所以这个类没有处理线程

    在主线程更新UI

    展开全文
  • Intent意图 可用于Activity之间数据传递,一般可分为下面两种情况,从当前Activity传递到目标Activity后有无返回值:1.传递后无返回值的情况:在起始Activity中,发送数据protectedvoidonCreate...

    Intent意图 可用于Activity之间的数据传递,一般可分为下面两种情况,从当前Activity传递到目标Activity后有无返回值:

    1.传递后无返回值的情况:在起始Activity中,发送数据

    protected void onCreate(Bundle saveInstanceState){

    super.onCreate(saveInstanceState);

    setContentView(R.layout.thisactivity);

    Intent intent = new Intent();

    //设置起始Activity和目标Activity,表示数据从这个Activity传到下个Activity

    intent.setClass(ThisActivity.this,TargetActivity.class);

    //绑定数据

    intent.putExtra("username",username);//也可以绑定数组

    intent.putExtra("userpass",userpass);

    //打开目标Activity

    startActivity(intent);

    }

    在目标Activity中,接收数据:

    protected void onCreate(Bundle saveInstanceState){

    super.onCreate(saveInstanceState);

    setContentView(R.layout.targetactivity);

    //获得意图

    Intent intent = getIntent();

    //读取数据

    String name = intent.getStringExtra("username");

    String pass = intent.getStringExtra("userpass);

    }

    也可以适用Bundle(捆)

    在起始Activity中,发送数据:

    protected void onCreate(Bundle saveInstanceState){

    super.onCreate(saveInstanceState);

    setContentView(R.layout.thisactivity);

    Intent intent = new Intent();

    //设置起始Activity和目标Activity,表示数据从这个Activity传到下个Activity

    intent.setClass(ThisActivity.this,TargetActivity.class);

    //一次绑定多个数据

    Bundle bundle = new Bundle();

    bundle.putString("username",username);

    bundle.putString("userpass",userpass);

    intent.putExtras(bundle);

    //打开目标Activity

    startActivity(intent);

    }

    在目标Activity中,接收数据:

    protected void onCreate(Bundle saveInstanceState){

    super.onCreate(saveInstanceState);

    setContentView(R.layout.targetactivity);

    //获得意图

    Intent intent = getIntent();

    //读取数据

    Bundle bundle = intent.getExtras();

    String name = bundle.getString("username");

    String pass = bundle.getString("userpass");

    }

    2.传递后有返回值的情况:

    当需要从目标Activity回传数据到原Activity时,可以使用上述方法定义一个新的Intent来传递数据,也可以使用startActivityForResult (Intent intent, int requestCode);方法。在起始Activity中,发送数据:

    protected void onCreate(Bundle saveInstanceState){

    super.onCreate(saveInstanceState);

    setContentView(R.layout.thisactivity);

    Intent intent = new Intent();

    //设置起始Activity和目标Activity,表示数据从这个Activity传到下个Activity

    intent.setClass(ThisActivity.this,TargetActivity.class);

    //绑定数据

    intent.putExtra("username",username);//也可以绑定数组

    intent.putExtra("userpass",userpass);

    //打开目标Activity

    startActivityForResult(intent,1);

    }

    //需要重写onActivityResult方法

    protected void onActivityResult(int requestCode, int resultCode, Intent intent){

    super.onActivityResult(requestCode,resultCode,intent);

    //判断结果码是否与回传的结果码相同

    if(resultCode == 1){

    //获取回传数据

    String name = intent.getStringExtra("name");

    String pass = intent.getStringExtra("pass);

    //对数据进行操作

    ......

    }

    在目标Activity中,接收数据:

    protected void onCreate(Bundle saveInstanceState){

    super.onCreate(saveInstanceState);

    setContentView(R.layout.targetactivity);

    //获得意图

    Intent intent = getIntent();

    //读取数据

    String name = intent.getStringExtra("username");

    String pass = intent.getStringExtra("userpass);

    //从EditText中获取新的数据给name和pass

    name = editText1.getText().toString();

    pass = editText2.getText().toString()

    //数据发生改变,需要把改变后的值传递回原来的Activity

    intent.putExtra("name",name);

    intent.putExtra("pass",pass);

    //setResult(int resultCode,Intent intent)方法

    setResult(1,intent);

    //销毁此Activity,摧毁此Activity后将自动回到上一个Activity

    finish();

    }

    展开全文
  • Activity传递数据一般比较简单,但是有时候实际开发中也会传一些比较复杂的数据,本节一起来学习更多Activity数据传递方法。 1、通过 Intent 传递 我们在进行 Activity 跳转时,是要有 Intent,此时 ...

    在Activity间传递的数据一般比较简单,但是有时候实际开发中也会传一些比较复杂的数据,本节一起来学习更多Activity间数据的传递方法。

    1、通过 Intent 传递

    我们在进行 Activity 跳转时,是要有 Intent,此时 Intent 是可以携带数据的,我们可以利用它将数据传递给其它Activity。Intent 应该是系统提供的支持类型最广,功能最全面的传递方式了。基本数据类型、复杂数据类型(如数组、集合)、自定义数据类型等等都能支持,而且使用起来也不复杂。下面将通过几个小栗子分别介绍一下这几种方法。

    1.1、基本数据类型传递

    String 不是基本数据类型,Java 的基本数据类型有且仅有8种,Intent 都做了很好的支持。这8种基本类型都有自己的包装类型(Wrap Class,复杂类型),而且包装类型也实现了 Serializable 接口(后面再说),使得 Intent 也能很好的支持包装类型。

    8种基本类型及其包装类对应关系如下:

    容我煮个栗子:

    假设有 Activity1,Activity2 两个 Activity;如果要在 Activity1 中启动 Activity2,并传过去几个基本类型的数据,就可以这么写:

    Intent intent = new Intent(this, Activity2.class);
    intent.putExtra(String name, boolean value);
    intent.putExtra(String name, byte value);
    intent.putExtra(String name, char value);
    intent.putExtra(String name, short value);
    intent.putExtra(String name, int value);
    intent.putExtra(String name, float value);
    intent.putExtra(String name, long value);
    intent.putExtra(String name, double value);
    startActivity(intent);
    

    在 Activity2 的 onCreate 中就可以通过如下方式接收:

    Intent intent = getIntent();
    boolean bool = intent.getBooleanExtra(String name, boolean defaultValue);
    byte bt = intent.getByteExtra(String name, byte defaultValue);
    char ch = intent.getCharExtra(String name, char defaultValue);
    short sh = intent.getShortExtra(String name, short defaultValue);
    int i = intent.getIntExtra(String name, int defaultValue);
    float fl = intent.getFloatExtra(String name, float defaultValue);
    long lg = intent.getLongExtra(String name, long defaultValue);
    double db = intent.getDoubleExtra(String name, double defaultValue);
    

    PS:上面发送和接收的时候,同一个字段必须使用相同的 name,比如:intent.putExtra(“BOOLEAN”, true);intent.getBooleanExtra(“BOOLEAN”, false);

    1.2、复杂数据类型传递

    Java 中也定义了一些常用的复杂类型,比如 String、基本数据类型的数组、ArrayList、HashMap 等等,Intent 也对它们做了支持,使得我们能很容易的通过 Intent 传递这些复杂类型。方法与上面基本类型类似,比如:

    intent.putExtra(String name, String value);
    intent.putExtra(String name, int[] value);
    intent.putExtra(String name, Parcelable value);
    intent.putExtra(String name, Serializable value);
    intent.putExtra(String name, CharSequence value);
    intent.putStringArrayListExtra(String name, ArrayList<String> value);
    

    接收方式也类似,这里就不再一一列举了。

    不过,像 ArrayList、HashMap 这种,本身还能存放复杂类型的数据结构,要想通过 Intent 传递,得确保它们内部存放的类型也是能支持序列化和反序列化的。

    1.3、自定义数据类型传递

    上面已经列举了很多 Intent 支持的类型,但是默认提供的这些类型,总归是不够用的,很多时候我们会定义自己的数据类型,比如定义一个 Student:

    public class Student{
     public String name;
     public int age;
    }
    

    那么这个时候我们应该如何通过Intent来传递呢?

    1.3.1、实现 Serializable 接口

    我们先看一下默认提供并被 Intent 支持的复杂数据类型的实现方式:

    public final class String
     implements java.io.Serializable, Comparable<String>, CharSequence
    public class ArrayList<E> extends AbstractList<E>
     implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    public class HashMap<K,V>
     extends AbstractMap<K,V>
     implements Map<K,V>, Cloneable, Serializable
    

    我们可以看到它们有一个共同的特点,都 implement 了 Serializable 接口。

    Serializable 是一个空接口,它没有定义任何方法,知识用来标记其实现类是支持序列化和反序列化的。

    因此当我们想让自定义的类型也能通过 Intent 传递时,只需要让该类实现 Serializable 接口即可。

    依旧用 Student 来煮个栗子:

    public class Student implements Serializable{
     private static final long serialVersionUID = 1L;
     public String name;
     public int age;
    }
    

    传递方法就是:

    intent.putExtra(String name, Serializable value);
    intent.getSerializableExtra(String name);
    

    PS:关于 Serializable 还有一些知识点,比如:serialVersionUID、静态变量序列化、transient 关键字、继承问题等等,这里就不介绍了,有兴趣的可以自行去查阅。

    1.3.2、实现 Parcelable 接口

    上面介绍了 Serializable 接口,但 Serializable 是 Java 的实现,Android 下能正常使用,没毛病,但 Google 觉得 Serializable 在 Android 内存不大性能不强的情况下的效率不太够,于是为 Android 量身定制了一个专用的接口——Parcelable。

    还是用 Student 来煮栗子:

    要想实现 Parcelable 接口,只需要先写好 Student 类和属性,然后让 Student 实现Parcelable,再然后根据 AS 的两步提示:第一步重写 describeContents 和 writeToParcel,第二步创建 CREATOR 就大功告成了。写好的类如下:

    public class Student implements Parcelable{
     public String name;
     public int age;
     protected Student(Parcel in) {
     name = in.readString();
     age = in.readInt();
     }
     public static final Creator<Student> CREATOR = new Creator<Student>() {
     @Override
     public Student createFromParcel(Parcel in) {
     return new Student(in);
     }
     @Override
     public Student[] newArray(int size) {
     return new Student[size];
     }
     };
     @Override
     public int describeContents() {
     return 0;
     }
     @Override
     public void writeToParcel(Parcel dest, int flags) {
     dest.writeString(name);
     dest.writeInt(age);
     }
    }
    

    此时通过 Intent 去传递就可以使用如下方法:

    intent.putExtra(String name, Parcelable value);
    intent.getParcelableExtra(String name);
    

    这两种实现序列化的方法的使用原则:

    1)在使用内存的时候,Parcelable 比 Serializable 性能高,所以推荐使用 Parcelable。

    2)Serializable 在序列化的时候会产生大量的临时变量,从而引起频繁的 GC。

    3)Parcelable 不能使用在要将数据存储在磁盘上的情况,因为 Parcelable 不能很好的保证数据的持续性在外界有变化的情况下。尽管 Serializable 效率低点,但此时还是建议使用 Serializable 。

    PS:Intent 还支持通过 Bundle 封装数据,然后传递 Bundle,但是查看 intent.putExtra 的实现,我们会发现,其实 intent.putExtra 的内部也是维护的一个 Bundle,因此,通过 putExtra 放入的数据,取出时也可以通过 Bundle 去取。

    2、通过全局变量传递

    顾名思义,就是借助一个全局变量做中转,去传递数据。还是以前面的两个 Activity 为例,传递不支持序列化的 Student 对象。我们可以先创建一个工具类,比如:

    public class Transmitter {
     public static Student student;
    }
    

    那么传递和接收时,就可以这么操作:

    //传递
    Student stu = new Student();
    Transmitter.student = stu;
    Intent intent = new Intent(this, Activity2);
    startActivity(intent);
    //接收
    onCreate(...){
     Student stu = Transmitter.student;
    }
    

    可以看到使用起来非常的方便快捷。

    但是,全局变量在 APP 运行期间一直存在,如果通过全局变量存放的数据量比较大,变量个数多;并且在不需要使用后,没有及时的将全局变量置为 null,好让 GC 去回收,那么是有可能会引发 OOM 问题的。

    因此,如果要使用全局变量来作为数据传递方法,那么就一定要注意维护好这些全局变量的状态。

    3、通过 SharedPreferences 传递

    SharedPreferences 是 Android 提供的一种实现数据存储的方式,它可以将数据以 xml 格式存储在机器中,通常用来存储 APP 的设置信息,我们也可以用它来实现 Activity 间的数据传递。

    但是,SharedPreferences 因其特殊的工作方式,只提供了对部分基本类型和 String 的操作,对其它既有复杂类型和自定义类型是不支持的。它所支持的类型只有:

    boolean
    float
    int
    long
    String
    Set<String>
    

    仍旧拿前面的两个 Activity 煮栗子,要实现它们之间的数据传递,只需要现在 Activity1 中,将数据放入 SharedPreferences,如下:

    SharedPreferences sp = getSharedPreferences("FILENAME", MODE_PRIVATE);
    SharedPreferences.Editor editor = sp.edit();
    editor.putBoolean(String key, boolean value);
    editor.putFloat(String key, float value);
    editor.putInt(String key, int value);
    editor.putLong(String key, long value);
    editor.putString(String key, String value);
    editor.putStringSet(String key, Set<String> values);
    //editor.commit();
    editor.apply();
    startActivity(...);
    

    然后在 Activity2 中通过 SharedPreferences 将数据取出来,如下:

    SharedPreferences sp = getSharedPreferences("FILENAME", MODE_PRIVATE);
    sp.getBoolean(String key, boolean defValue);
    sp.getFloat(String key, float defValue);
    sp.getInt(String key, int defValue);
    sp.getLong(String key, long defValue);
    sp.getString(String key, String defValue);
    sp.getStringSet(String key, Set<String> defValue);
    

    关于 SharedPreferences 有几点需要注意:

    **1、**getSharedPreferences(“FILENAME”, MODE_PRIVATE) 是通过 Context 调用的,发送和接收的 FILENAME、MODE_PRIVATE 都要一致。

    2、发送时,往 SharedPreferences 存入数据后,需要提交,提交的方式有两种:commit、apply,这两个的区别如下:

    **commit:**同步操作,立即将修改写到 Storage,有 boolean 类型返回值。

    **apply:**立即刷新 In-memory 中的数据,然后启动异步任务将修改写到 Storage,无返回值。

    当两个 apply 同时操作时,后调用 apply 的将会被保存到 Storage 中;当有 apply正在执行时,调用 commit,commit 将被阻塞,直到 apply 执行完。

    因 Android framework 已经做好所有的事情,所以当我们不需要关注提交操作的返回值时,可以将 commit 无条件替换 apply 使用,而且 AS 也会建议将 commit 替换成 apply。

    **3、**SharedPreferences 支持的数据类型都必须是支持序列化操作的,上面提到的 Set是一个 interface,我们并不能直接实例化,但我们可以使用它的直接或间接实现类,比如:HashSet、TreeSet、LinkedHashSet等等。

    我们查看这几个的实现,不难发现,它们也都是实现了 Serializable 接口,支持序列化操作的:

    public class HashSet<E>
     extends AbstractSet<E>
     implements Set<E>, Cloneable, java.io.Serializable
    public class TreeSet<E> extends AbstractSet<E>
     implements NavigableSet<E>, Cloneable, java.io.Serializable
    public class LinkedHashSet<E>
     extends HashSet<E>
     implements Set<E>, Cloneable, java.io.Serializable {
    

    4、通过 SystemProperties 传递

    这个类可以看做一个维护全局变量的类,只不过这里的全局变量是系统的,它们的值是 build.prop 文件里面的内容。我们先看一下它的定义:

    /**
     * Gives access to the system properties store. The system properties
     * store contains a list of string key-value pairs.
     *
     * {@hide}
     */
    public class SystemProperties
    

    没错,这玩意是个 hide 的类,那就意味着正常情况下 SDK 里面是没有的,AS 里面也是访问不到的。不过我们还是可以通过一些手段去访问到它,比如反射、将源码的库导出到 AS 使用、将 APP 放在源码中编译等等。

    这里我们就不关注用什么手段去访问它了,我们重点还是在利用它进行 Activity 之间的数据传递。

    假设我们是在源码中编译,还是用一开始的两个 Activity 来煮栗子,发送数据时可以这么操作:

    SystemProperties.set("NAME", "Shawn.XiaFei");
    startActivity(...);
    

    接收时就可以这么写:

    SystemProperties.get("NAME");
    //或者
    SystemProperties.get("NAME", "defValue");
    

    是不是很方便呢,不过别激动,我们看下 set 的实现:

    /**
     * Set the value for the given key.
     * @throws IllegalArgumentException if the key exceeds 32 characters
     * @throws IllegalArgumentException if the value exceeds 92 characters
     */
    public static void set(String key, String val) {
     if (key.length() > PROP_NAME_MAX) {
     throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
     }
     if (val != null && val.length() > PROP_VALUE_MAX) {
     throw new IllegalArgumentException("val.length > " +
     PROP_VALUE_MAX);
     }
     native_set(key, val);
    }
    

    看注释,没错,key 和 val 都限制了长度的!!!当然,32和92字符,在一般情况下也还是够用的。但是下面就要说一般 APP 开发可能无法完成的事了。

    前面说了,这玩意是 SDK 不可见的,而且它维护的是系统的属性值,系统属性值 APP 可以读,但不能轻易修改。因此上面 set 的时候,如果权限不够就会报如下错误:

    Unable to set property "NAME" to "Shawn.XiaFei": connection failed; errno=13 (Permission denied)
    type=1400 audit(0.0:167): avc: denied { write } for name="property_service" dev="tmpfs" ino=10696 scontext=u:r:untrusted_app_25:s0:c512,c768 tcontext=u:object_r:property_socket:s0 tclass=sock_file permissive=0
    

    这个错误在 Rom 开发中比较常见,解决办法就是配置相应的 avc 权限,这一操作是一般 APP 开发者无法进行的。有兴趣的可以自己去查资料,这里不做介绍。

    5、通过 SettingsProvider 传递

    爱折腾的人可能注意到了 Android 设备上一般都会有这么一个应用,它的作用是通过数据库去维护一些系统配置信息。在 Rom 开发中,通常借助它设置首次开机的默认行为。

    通过它传递数据的关键在 android.provider.Settings 类,这个类里面有 3 个常用的静态内部类,分别是:Global、System、Secure,它们分别对应不同的权限等级。

    煮栗子了:

    发送时,这么写就可以了:

    /*Settings.System.putInt(ContentResolver cr, String name, int value);
    Settings.System.putString(ContentResolver cr, String name, String value);
    Settings.System.putFloat(ContentResolver cr, String name, float value);
    Settings.System.putLong(ContentResolver cr, String name, long value);*/
    Settings.Global.putString(getContentResolver(), "NAME", "Shawn.XiaFei");
    startActivity(...);
    

    接收时,就这么写:

    String name = Settings.Global.getString(getContentResolver(), "NAME");
    

    使用起来也是很简单滴!不过,使用起来虽然简单,但也并不是那么容易的。它也是要权限的!!!

    如果权限不够,运行的时候就会报如下错误:

     java.lang.RuntimeException: Unable to start activity ComponentInfo{xxx.xxx/xxx.xxx.Activity1}: java.lang.SecurityException: Permission denial: writing to settings requires:android.permission.WRITE_SECURE_SETTINGS
     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2805)
     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2883)
     at android.app.ActivityThread.-wrap11(Unknown Source:0)
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1613)
     at android.os.Handler.dispatchMessage(Handler.java:106)
     at android.os.Looper.loop(Looper.java:164)
     at android.app.ActivityThread.main(ActivityThread.java:6523)
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:857)
    

    意思很明了,得给它 WRITE_SECURE_SETTINGS 的权限,我们试着在 Manifest 里面添加一下,结果 AS 标红了,提示如下:

    Permissions with the protection level signature or signatureOrSystem are only granted to system apps. If an app is a regular non-system app, it will never be able to use these permissions.

    意思就是说,这个权限只有系统 APP 才能获得,三方 APP 没戏。

    6、通过数据库传递

    其实上面介绍的 SettingsProvider 方法,也是通过数据库实现的,只不过它对数据库的操作做了封装,我们感觉不到而已。既然如此,我们也可以在自己 APP 中创建数据库,然后通过数据库来实现 Activity 之间的数据传递。

    栗子煮太多,吃不动,不煮了,有兴趣的可以自己去查一下数据库的知识。

    PS:实话实说吧,个人用的不多,忘了怎么玩了……

    7、通过文件传递

    前面提到的 SharedPreferences 也是基于文件实现的,只不过 SharedPreferences 是固定成 xml 格式的文件。我们也可以通过自定义文件操作方式去实现数据的存取,进而实现 Activity 之间的数据传递。

    说了栗子不煮了,有兴趣自己去查一下吧。

    PS:原因同上一条……

    总结

    其实 Activity 之间数据传递的方法还是很多的,也各有优缺点,但最最最最最常用的还是第一种—— Intent,其他方法都是理论可行,实际使用起来都会有点鸡肋,或者得不偿失。

    因此要想掌握好 Activity 之间数据传递的技巧,个人觉得只需要掌握 Intent 的用法,能熟练使用,灵活处理就 OK 了。至于其它方法,能说得出来原理就可以了。

    最后

    针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

    • Android前沿技术大纲

    • 全套体系化高级架构视频

    资料领取方式: 加群免费获取 Android架构设计大群(185873940)

    最后送福利了,现在关注我并且加入群聊可以获取包含源码解析,自定义View,动画实现,架构分享等。
    内容难度适中,篇幅精炼,每天只需花上十几分钟阅读即可。
    大家可以跟我一起探讨,欢迎加群探讨,有flutter—底层开发—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿

    点击GitHub领取
    录播视频图.png

    自定义View,动画实现,架构分享等。
    内容难度适中,篇幅精炼,每天只需花上十几分钟阅读即可。
    大家可以跟我一起探讨,欢迎加群探讨,有flutter—底层开发—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿**
    点击GitHub领取
    [外链图片转存中…(img-1ZVXg49m-1623503402786)]

    展开全文
  • 1 基于消息的通信机制 Intent--------boudle,extra用这种简单的形式,一般而言传递一些简单的类型是比较容易的,如int、string等...----------路上带些什么,区分性数据和内容性数据简单数据传递:Intent intent = ...

    1  基于消息的通信机制 Intent--------boudle,extra用这种简单的形式,一般而言传递一些简单的类型是比较容易的,如int、string等

    详细介绍下Intent机制

    Intent包含两部分:1 目的【action】-------要去到哪里去

    2 内容【category、data】----------路上带些什么,区分性数据和内容性数据简单数据传递:

    Intent intent = new Intent(LoginActivity.this, MainActivity.class);

    intent.putExtra("flag", flag);

    startActivity(intent);

    /

    String flag = "   ";

    Intent intent1 = this.getIntent();

    flag = intent1.getStringExtra("flag");

    /

    数据类型有限,遇到不可序列化的数据Bitmap,Inputstream,或者是LinkList链表等数据类型就不太好用了

    2 利用static静态数据,public static成员变量我们千万不要以为Davlik虚拟机的垃圾回收器会帮助我们回收不需要的内存垃圾。事实上,回收器并不可靠,

    尤其是手机上,是更加的不可靠。 因此,除非我们要使自己的程序变得越来越糟糕,否则尽量远离static。

    注:如果经常使用static的Bitmap、Drawable等变量。可能就会抛出一个在Android系统中非常著名的异常(

    以前budget这个单词一直记不住什么意思,自从经常抛出这个异常后,这个单词终于烂熟于心了,)

    ERROR/AndroidRuntime(4958): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget

    注:如果经常使用static的Bitmap、Drawable等变量。可能就会抛出一个在Android系统中非常著名的异常(

    以前budget这个单词一直记不住什么意思,自从经常抛出这个异常后,这个单词终于烂熟于心了,)3 基于外部存储的传输 ,File/Preference/Sqlite,如果要针对第三方应用需要Content provider

    作为一个完成的应用程序,数据存储操作是必不可少的。因此,Android系统一共提供了四种数据存储方式。分别是:SharePreference、SQLite、Content Provider和File。由于Android系统中,数据基本都是私有的的

    ,都是存放于“data/data/程序包名”目录下,所以要实现数据共享,正确方式是使用Content Provider。

    SQLite: SQLite是一个轻量级的数据库,支持基本SQL语法,是常被采用的一种数据存储方式。Android

    为此数据库提供了一个名为SQLiteDatabase的类,封装了一些操作数据库的API。

    SharedPreference: 除SQLite数据库外,另一种常用的数据存储方式,其本质就是一个xml文件,常用于

    存储较简单的参数设置。

    File: 即常说的文件(I/O)存储方法,常用语存储大数量的数据,但是缺点是更新数据将是一件困难的

    事情。

    ContentProvider: ContentProvider是安卓平台中,在不同应用程序之间实现数据共享的一种机制。一个

    应用程序如果需要让别的程序可以操作自己的数据,即可采用这种机制。并且此种方式忽略了底层的数据存储

    实现,ContentProvider提供了一种统一的通过Uri实现数据操作的方式。

    详细介绍使用过程File 通过文件内容的读取传递数据

    Preference: SharedPreferences也是一种轻型的数据存储方式,它的本质是基于XML文件存储key-value键值

    对数据,通常用来存储一些简单的配置信息

    SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象实现。实现

    SharedPreferences存储的步骤如下:一、根据Context获取SharedPreferences对象

    二、利用edit()方法获取Editor对象。

    三、通过Editor对象存储key-value键值对数据。

    四、通过commit()方法提交数据。

    SharedPreferences sp=getSharedPreferences("login",0);//login存储文件名

    SharedPreferences.Editor se=sp.edit();;

    se.putString("server", logEdit.getText().toString());

    se.putString("port", portEdit.getText().toString());

    se.commit();

    /

    SharedPreferences ps=getSharedPreferences("login",0);//login是存储文件

    server=ps.getString("server", "");

    port=ps.getString("port", "");

    logEdit.setText(server);

    portEdit.setText(port);

    /

    ContentProvider

    其步骤为:1. 在当前应用程序中定义一个ContentProvider。

    2. 在当前应用程序的AndroidManifest.xml中注册此ContentProvider

    3. 其他应用程序通过ContentResolver和Uri来获取此ContentProvider的数据。

    在程序A中,继承ContProvider类,并重写其中的方法

    public class MyProvider extends ContentProvider{

    @Override

    public int delete(Uri uri, String selection, String[] selectionArgs) {

    // TODO Auto-generated method stub

    return 0;

    }

    @Override

    public String getType(Uri uri) {

    // TODO Auto-generated method stub

    return null;

    }

    @Override

    public Uri insert(Uri uri, ContentValues values) {

    return null;

    }

    //在Create中初始化一个数据库

    @Override

    public boolean onCreate() {

    SQLiteDatabase db = this.getContext().openOrCreateDatabase("test_db.db3",

    Context.MODE_PRIVATE, null);

    db.execSQL("create table tab(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT

    NULL)");

    ContentValues values = new ContentValues();

    values.put("name", "test");

    db.insert("tab", "_id", values);

    db.close();

    return true;

    }

    //实现query方法

    @Override

    public Cursor query(Uri uri, String[] projection, String selection,

    String[] selectionArgs, String sortOrder) {

    SQLiteDatabase db = this.getContext().openOrCreateDatabase("test_db.db3",

    Context.MODE_PRIVATE, null);

    Cursor c = db.query("tab", null, null, null, null, null,null);

    return c;

    }

    @Override

    public int update(Uri uri, ContentValues values, String selection,

    String[] selectionArgs) {

    // TODO Auto-generated method stub

    return 0;

    }

    }

    在其AndroidManifest.xml中声明此ContentProvider,其中authorities属性定义了此ContentProvider的Uri

    标识。

    在应用程序B中,通过ContentResolver获取程序A的ContentProvider中的数据。

    public class MainActivity extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    //获取上下文

    Context ctx = MainActivity.this;

    //获取ContentResolver对象

    ContentResolver resolver = ctx.getContentResolver();

    //获取Uri对象

    Uri uri = Uri.parse("content://com.test.MyProvider");

    //获取数据

    Cursor c = resolver.query(uri, null, null, null, null);

    c.moveToFirst();

    for(int i=0; i

    int index = c.getColumnIndexOrThrow("name");

    String src = c.getString(index);

    Log.d("", src);

    c.moveToNext();

    }

    }

    }

    再观察两个应用程序的结构,A的程序结构,可以清楚看到其有一个名为“test_db.db3”的数据库,B的程序结构,其并没有任何数据库用于存储数据。由此图,可以确定应用程序B中查询出来的数据结果是来自于应用程序A。

    以上就是ContentProvider的使用方式,这种存储方式相比SQLite和SharedPreferences,其复杂性是显而易见的,但是在处处可见“云”的今天,程序间的数据交互需求令ContentProvider存储机制变成必不可少的一部分。

    4 基于Ipc的通信机制context与service之间的传输,如Activity与Service之间的通信

    5 基于Application  Context在一个activity初始化一个ArrayList>对象,然后经过一个tableactivity,在传递到另

    外一个activity,一开始直接考虑用putExtra,测试发现数据只能传递一次,就考虑用Application传递

    Java里面通常是用一个static的变量(例如singleton之类的)来同步activity之间(程序里面类之间)的状态。在android里面比较靠谱的做法是用application context来关联这些状态。

    每个activity都是context,里面包含了运行时的状态。同样application也有一个context,android会保证这个context是唯一的实例。

    package net.blogjava.mobile1;

    import android.app.Application;

    import android.graphics.Bitmap;

    public class MyApp extends Application

    {

    private Bitmap mBitmap;

    public Bitmap getBitmap()

    {

    return mBitmap;

    }

    public void setBitmap(Bitmap bitmap)

    {

    this.mBitmap = bitmap;

    }

    }

    获得Bitmap对象的代码:

    ImageView imageview = (ImageView)findViewById(R.id.ivImageView);

    MyApp myApp = (MyApp)getApplication();

    imageview.setImageBitmap(myApp.getBitmap());

    上面两段代码可以在任何的Service、Activity中使用。全局的

    展开全文
  • 1. 概述在我们开发项目的过程中,一定会有两个 Activity之间需要进行数据传递的,这个想都不用想,是一定会有的。如果数据比较少,我们可以单个传递字段,如果数据比较多我们可以直接传递一个对象,当然也可以直接...
  • 弱引用方式保存数据,防止内存泄漏 public class DataHolder { private Map<String, WeakReference> data = new HashMap<String, WeakReference>(); private static DataHolder instance; public static...
  • 一、通过startActivity来进行Activity的传值在Android中,如果我们要通过一个Activity来启动另一个Activity,可以使用 startActivity(Intent intent)方法来传入一个Intent对象,这个Intent对象我们可以精确的指定...
  • 下面通过一个例子来详细说明先上代码,再细细分析MainActivitypublic class MainActivity extends Activity{private Button mainBtn=null;private final static int REQUEST_CODE=1;/** Called when the activity is...
  • 一个Android程序可以由多个Activity和Servier组成,在这些程序组件之间传递数据的方法有以下几种,每种方法都有其特定的使用途径。1、原始数据类型:在Activity/Servier之间传递临时性的原始数据,可以使用Intent的...
  • 使用Bundle在Activity之间传递数据Bundle类是一个key-value对,是一个final类两个Activity之间通信可以用Bundle类实现步骤:新建一个Bundle类Bundle bundle=new Bundle();bundle类中加入数据(key-value的形式)bundle...
  • Activity之间数据时,为了避免麻烦,往往会将一些值封装成对象,然后将整个对象传递过去。传对象的时候有两种情况,一种是实现Parcelable接口,一种是实现Serializable接口。0、解释两种接口:1)实现Serializable...
  • Android 中Activity 之间传递参数1.传递简单数据在A Activity中findViewById(R.id.startBActicityBtn).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent i = new ...
  • 从一个Activity传递数据到另一个Activity中,有如下几个方法:IntentBundleSerializableParcelable首先设置一个Button,按下即可跳转到下一个Activity;方法1.intent.putExtra传递一些简单的数据:String s = ...
  • 安卓应用在不同的Activity之间传递数据 首先新建一个Activity 这里使用的是Android Studio,新建一个Activity有两种方法 第一种:src\main\java\com.example.myapplication下右击com.example.myapplication点击New就...
  • 1、向目标Activity【Main2Activity传递数据:Intentintent=newIntent(this,Main2Activity.class);//可传递多种类型的数据intent.putExtra("name","张三");intent.putExtra("age",12);startActivity(intent);2、在...
  • Activity之间传递数据一般通过以下几种方式实现: 1. 通过intent传递数据 2. 通过Application 3. 使用单例 4. 静态成员变量。(可以考虑WeakReferences) 5. 持久化(sqlite、share preference、file等) 一...
  • 里面传两个参数(intent 和 请求码),并在A界面重写onActivityRusult()方法,接收从B界面改变集合后的数据,建议先看B界面的代码 B界面: public class OrderingActivity extends Activity { public final ...
  • 作者 / Yacine Rezgui无论您是在应用中请求某项权限,从文件管理系统中选择某个文件,还是期望从第三方应用中获取到某些数据,都会涉及到在 Activity 之间传递数据,而这也正...
  • 前面照着android系统的裁剪图片的...先上个图(界面依旧没优化,难看就难看吧):起始activity,打开图片选择窗口,随便选择一张图片下面是跳转到裁剪界面按下crop按钮,退出activity,回到原来界面,并显示裁剪后的...
  • Bundle常用于在Activity传递数据 ,当bundle传递的是对象或对象数组时,必须实现Serializable或Parcelable接口.。 intent.putExtra(键值对,具体要传递的值) @Override public void onClick(View v) { Intent ...
  • 一、向下一个活动传递数据 ...前面我们在介绍Intent的时候有说过,我们可以利用Intent在不同组件之间传递数据,接下来这篇文章就是记录如何利用Intent在不同Activity之间传递简单数据传递数据包、传递值对...
  • ViewModel中的第一个应该永远不应包含一个View,例如EditText,从ViewModelpage中...其次,ViewModel不应该用于处理数据,它只是数据的容器.处理应在后台执行,结果应存储在ViewModel中,以便潜在的侦听器可以对数据更改...
  • 一个activity就好比一个网页,此文章讲解怎样创建一个activity并且实现跳转!一、学习创建Activity1、新建一个java类,右击src目录,选择new-->class,新的activity需要继承Activity类2、需要复写onCreate()例子...
  • 1.如何把图片从Activity传递给另一个Activity Intent intent=new Intent(MainActivity.this,OtherActivity.class); intent.putExtra("bitmap", bitmap); startActivity(intent); bitmap是在oncreate方法中获得的...
  • [ 在Android中的不同Activity之间传递对象,我们可以考虑采用Bundle.putSerializable(Key,Object);也可以考虑采用Bundle.putParcelable(Key, Object);其中前面博客时间:2012-11-12 08:49 在两个activity之间传递...
  • Android开发中在Activity之间传递map和普通对象的几种方法​在android学习中,我们经常遇到从一个activity传参到另一个activity的问题(即界面传参),如果我们要传递基本类型的参数,只要利用意图Intent对象intent....
  • 以后我们在要传递大数据时,则可以用DataHolder.setData(name, value)进行传递,然后在目标Activity中使用DataHolder.getData(name)进行获取。 我们自定义了一个静态类DataHolder,并且设置setData和getData
  • Android activity之间值的传递activity之间值的传递需要用到Intent对象,然后将值绑定到Intent对象中进行传递简单的值传递比如就传一个值,可以直接将值放入到Intent对象中,比如在mainActivity中有一个button,点击...
  • 1.使用Intent进行传输//发送数据Activityclass button implements OnClickListener{@Overridepublic void onClick(View v) {// TODO Auto-generated method stubString ET_1String = ET_1.getText().toString();...
  • 目录1、按钮点击跳转页面2、数据传递 1、按钮点击跳转页面 mBtn3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //显式跳转1——首选 Intent intent1 = new ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 62,759
精华内容 25,103
关键字:

activity之间的数据传递

友情链接: ar7_wdt.zip