Android——你应该掌握的高级技巧

1、全局获取Context的技巧

回想一下我们在项目中你会发现有很多地方都需要Context,比如:弹出Toast的时候需要,启动活动的时候需要,发送广播的时候需要,操作数据库的时候需要,使用通知的时候需要,等等等等。

或许目前你还没有为得不到Context而发愁过,因为我们很多的操作都是在活动中进行的,而活动本身就是一个Context对象。但是当应用程序的架构逐渐开始复杂起来的时候,很多的逻辑代码都将脱离Activity类,但此时你又恰恰需要使用Context,也许这个时候你就会感到有些伤脑筋了。

由以上可以看出,在某些情况下,获取Context并非那么容易的一件事,有时候还是挺伤脑筋的,不过别担心,下面我们来学习一种技巧,让你在项目的任何地方都能轻松获取到Context。

Android提供了一个Application类,每当应用程序启动的时候,系统就会自动将这个类进行初始化。而我们可以定制一个自己的Application类,以便于管理程序内一些全局的状态信息,比如说全局Context。

定制一个自己的Application其实并不复杂,首先我们需要创建一个MyApplication类继承自Application,代码如下示例:

public class MyApplication extends Application {

    private static Context context;

    @Override

    public void onCreate(){

        context = getApplicationContext();

    }

    public static Context getContext(){

        return context;

    }

}

接下来我们需要告知系统,当程序启动的时候应该初始化MyApplication类,而不是默认的Application类。这一步也很简单,在AndroidManifest.xml文件的<application>标签下进行指定就可以了,如下所示:

<application

    android:name="MyApplication全限定名"

   ...>

        ...

</application>

2、使用Intent传递对象

Intent的用法相信你已经比较熟悉了,我们可以借助它来启动活动、发送广播、启动服务等。在进行上述操作的时候,我们还可以在 Intent 中添加一些附加数据,以达到传值的效果,比如在 FirstActivity 中添加如下代码:

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);

intent.putExtra("string_data", "hello");

intent.putExtra("int_data", 100);

startActivity(intent);

这里调用了 Intent的 putExtra()方法来添加要传递的数据,之后在 SecondActivity 中就可以得到这些值了,代码如下所示:

getIntent().getStringExtra("string_data");

getIntent().getIntExtra("int_data", 0);

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

2.1、Serializable 方式

使用 Intent 来传递对象通常有两种实现方式,Serializable 和 Parcelable,本小节中我们先来学习一下第一种的实现方式。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");

这里调用了 getSerializableExtra()方法来获取通过参数传递过来的序列化对象,接着再将它向下转型成 Person 对象,这样我们就成功实现了使用 Intent 来传递对象的功能了。

2.2、Parcelable 方式

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

public class Person implements Parcelable {

    private String name;

    private int age;

    ……

    @Override

    public int describeContents() {

        return 0;

    }

    @Override

    public void writeToParcel(Parcel dest, int flags) {

        dest.writeString(name); //  写出name

        dest.writeInt(age); //  写出age

    }

    public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {

        @Override

        public Person createFromParcel(Parcel source) {

            Person person = new Person();

            person.name = source.readString(); //  读取name

            person.age = source.readInt(); //  读取age

            return person;

    }

    @Override

    public Person[] newArray(int size) {

        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 方式低一些,所以在通常情况下还是更加推荐使用 Parcelable 的方式来实现 Intent 传递对象的功能。

3、定制自己的日志工具

虽然 Android 中自带的日志工具功能非常强大,但也不能说是完全没有缺点,例如在打印日志的控制方面就做得不够好。打个比方,你正在编写一个比较庞大的项目,期间为了方便调试,在代码的很多地方都打印了大量的日志。最近项目已经基本完成了,但是却有一个非常让人头疼的问题,之前用于调试的那些日志,在项目正式上线之后仍然会照常打印,这样不仅会降低程序的运行效率,还有可能将一些机密性的数据泄露出去。那该怎么办呢,难道要一行一行把所有打印日志的代码都删掉?显然这不是什么好点子,不仅费时费力,而且以后你继续维护这个项目的时候可能还会需要这些日志。因此,最理想的情况是能够自由地控制日志的打印,当程序处于开发阶段就让日志打印出来,当程序上线了之后就把日志屏蔽掉。看起来好像是挺高级的一个功能,其实并不复杂,我们只需要定制一个自己的日志工具就可以轻松完成了。比如新建一个 LogUtil 类,代码如下所示:

public class LogUtil {

    public static final int VERBOSE = 1;

    public static final int DEBUG = 2;

    public static final int INFO = 3;

    public static final int WARN = 4;

    public static final int ERROR = 5;

    public static final int NOTHING = 6;

    public static final int LEVEL = VERBOSE;

    public static void v(String tag, String msg) {

        if (LEVEL <= VERBOSE) {

            Log.v(tag, msg);

        }

    }

    public static void d(String tag, String msg) {

        if (LEVEL <= DEBUG) {

            Log.d(tag, msg);

        }

    }

    public static void i(String tag, String msg) {

        if (LEVEL <= INFO) {

            Log.i(tag, msg);

        }

    }

    public static void w(String tag, String msg) {

        if (LEVEL <= WARN) {

            Log.w(tag, msg);

        }

    }

    public static void e(String tag, String msg) {

        if (LEVEL <= ERROR) {

            Log.e(tag, msg);

        }

    }

}

可以看到,我们在 LogUtil 中先是定义了 VERBOSE、DEBUG、INFO、WARN、ERROR、NOTHING 这六个整型常量,并且它们对应的值都是递增的。然后又定义了一个 LEVEL 常量,可以将它的值指定为上面六个常量中的任意一个。接下来我们提供了 v()、d()、i()、w()、e()这五个自定义的日志方法,在其内部分别调用了 Log.v()、Log.d()、Log.i()、Log.w()、Log.e()这五个方法来打印日志,只不过在这些自定义的方法中我们都加入了一个 if 判断,只有当 LEVEL 常量的值小于或等于对应日志级别值的时候,才会将日志打印出来。这样就把一个自定义的日志工具创建好了,之后在项目里我们可以像使用普通的日志工具一样使用 LogUtil,比如打印一行 DEBUG 级别的日志就可以这样写:

LogUtil.d("TAG", "debug log");

打印一行 WARN 级别的日志就可以这样写:

LogUtil.w("TAG", "warn log");

然后我们只需要修改 LEVEL 常量的值,就可以自由地控制日志的打印行为了。比如让LEVEL 等于 VERBOSE 就可以把所有的日志都打印出来,让 LEVEL 等于 WARN 就可以只打印警告以上级别的日志,让 LEVEL 等于 NOTHING 就可以把所有日志都屏蔽掉。使用了这种方法之后,刚才所说的那个问题就不复存在了,你只需要在开发阶段将LEVEL 指定成 VERBOSE,当项目正式上线的时候将 LEVEL 指定成 NOTHING 就可以了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值