Android 进阶的小技巧整理(整理自第一行代码)

目录

一 获取全局Context

二 使用Intent传递对象

2.1 Serializable方式

2.2 Parcelable方式

三 日志工具

四 创建定时任务

4.1 Alarm 机制

4.2 Doze模式

五 多窗口模式编程

5.1 进入多窗口模式

5.2 多窗口模式下的生命周期

5.3 禁用多窗口模式

六  Lambda 表达式


一 获取全局Context

       活动本身就是一个 Context 对象。但当应用程序的架构逐渐开始复杂起来的时候,很多的逻辑代码都将脱离 Activity 类,但Android 提供了一个 Application 类,每当应用程序启动的时候,系统就会自动将这个类进行初始化。而我们可以定制一个自己的 Application 类,以便管理程序内一些全局的状态信息,比如说全局 Context。

public class MyApplication extends Application {
    private static Context context;

    @Override
    public void onCreate() {
        super.onCreate();
        context =getApplicationContext();
    }

    public static Context getContext() {
        return context;
    }
}

二 使用Intent传递对象

2.1 Serializable方式

Serializable 是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可存储到本地。至于序列化的方法也很简单,只需要让一个类去实现 Serizable 这个接口就可以了。

public class Festival implements Serializable {
    private String name;
    private String data;
    
    public Festival(String name,String data){
        this.name = name;
        this.data = data;
    }

    public String getName() {
        return name;
    }

    public String getData() {
        return data;
    }
}

传数据:

Festival festival = new Festival("元旦节","1月1日");
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("festival_object",festival);
startActivity(intent);

取数据:

 Festival festival = (Festival)getIntent().getSerializableExtra("festival_object");

2.2 Parcelable方式

 Parcelable 方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是 Intent 所支持的数据类型,这样也就实现传递对象的功能了。

public class Person implements Parcelable {
    
    private String name;
    private int age;
    
    //省略set和get方法

    protected Person(Parcel in) {
        name = in.readString();//读取name
        age = in.readInt();//读取age
    }

    public static final Creator<Person> CREATOR = new Creator<Person>() {
        @Override
        public Person createFromParcel(Parcel in) {
            return new Person(in);
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);//写出name
        dest.writeInt(age);//写入age
    }
}

首先让 Person 类实现 Parcelable 接口,这样就必须重写 describeContents( )和 writeToParcel( )这两个方法。其中describeContents( )方法直接返回 0 就可以了,而 writeToParcel( )方法中需要调用 Parcel 的 writeXxx( )方法将 Person 类中的字段一一写出。

除此之外,还必须在 Person 类中提供一个名为 CREATOR 的常量,这里创建了 Parcelable.Creator 接口的一个实现,并将泛型指定为 Person。

接着需要重写 createFromParcel( )和 newArray( )这两个方法,在 createFromParcel( )方法中去读取刚才写出的 name 和 age 字段,并创建一个 Person 对象进行返回,其中 name和age都是调用 Parcel 的 readXxx( )方法读取到的,注意这里的读取顺序一定要和写出顺序完全相同。而newArray()方法中只需要new出一个Person数组,并使用方法中传入的 size 作为数组大小就可以了。

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

三 日志工具

public class LogUtils {
 
    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 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);
        }
    }
}

四 创建定时任务

4.1 Alarm 机制

Alarm 机制的用法不复杂,主要是借助 AlarmManager 类来实现的。比如想要设定一个任务在 10 秒钟后执行,可写成:

// 获取 AlarmManager 的实例
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        
// 设置触发时间
// SystemClock.elapsedRealtime() 获取系统开机至今所经历时间的毫秒数
// SystemClock.currentTimeMillis() 获取1970年1月1日0点至今所经历时间的毫秒数
long triggerAtTime = SystemClock.elapsedRealtime() + 10 * 1000;
        
// 3个参数:指定 AlarmManager 的工作类型、定时任务的触发时间、PendingIntent
// 其中AlarmManager 的工作类型有四种:
// ELAPSED_REALTIME 定时任务的触发时间从系统开机开始时算起,不会唤醒 CPU
// ELAPSED_REALTIME_WAKEUP 系统开机开始时算起,会唤醒 CPU
// RTC 从1970年1月1日0点开始算起,不会唤醒 CPU
// RTC_WAKEUP 从1970年1月1日0点开始算起,会唤醒 CPU
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pandingIntent);

举个例子,实现一个长时间在后台定时运行的服务,首先新建一个普通的服务 LongRunningService,将触发定时任务的代码写到 onStartCommand() 方法中,如下:

public class LongRunningService extends Service {
    public LongRunningService() {
    }
 
    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
 
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 在这里执行具体的逻辑操作
            }
        }).start();
        AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
        int anHour = 60 * 60 * 1000;//1小时的毫秒数
        long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
        Intent i = new Intent(this,LongRunningService.class);
        PendingIntent pi = PendingIntent.getService(this,0,i,0);
        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pi);
        return super.onStartCommand(intent, flags, startId);
    }
}

然后,要启动定时服务时调用如下代码即可:

Intent intent = new Intent(context,LongRunningService.class);
context.startService(intent);

值得注意的是,从 Android 4.4开始,由于系统在耗电方面的优化,Alarm 任务的触发时间变得不准确,可能会延迟一段时间后再执行。当然,使用 AlarmManager 的 setExact() 方法来替代 set() 方法,基本上可以保证任务准时执行。

4.2 Doze模式

        在 Android 6.0中,谷歌加入了一个全新的 Doze 模式,可以极大幅度地延长电池的使用寿命。在 6.0 及以上系统的设备上,若未插接电源,处于静止状态(7.0中删除了这一条件),且屏幕关闭了一段时间之后,就会进入到 Doze 模式。在 Doze 模式下,系统会对 CPU、网络、Alarm 等活动进行限制,从而延长电池的使用寿命。

  当然,系统不会一直处于 Doze 模式,而是会间歇性的退出一小段时间,在这段时间应用可以去完成它们的同步操作、Alarm 任务等,其工作过程如下:

Doze 模式的工作过程

  Doze 模式下受限的功能有:
 (1)网络访问被禁止
 (2)系统忽略唤醒CPU或屏幕操作
 (3)系统不再执行WIFI扫描
 (4)系统不再执行同步任务
 (5)Alarm 任务将会在下次退出 Doze 模式时执行

  特殊需求,要 Alarm 任务在 Doze 模式下也必须正常执行,则可以调用 AlarmManager 的 setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle() 方法。


五 多窗口模式编程

5.1 进入多窗口模式

      在 OverView 列表界面长按任意一个活动的标题,将该活动拖到屏幕突出显示的区域,则可以进入多窗口模式。打开任意一个程序,长按 OverView 按钮,也可以进入多窗口模式。

5.2 多窗口模式下的生命周期

        这一块是比较重要的。多窗口模式并不会改变活动原有的生命周期,只是会将用户最近交互过的那个活动设置为运行状态,而将多窗口模式下另外一个可见活动设置为暂停状态。若这时用户又去和暂停的活动进行交互,那么该活动就变成运行状态,之前处于运行状态的活动变成暂停状态。

      进入多窗口模式时活动会被重新创建,若要改变这一默认行为,可以在 AndroidManifest.xml 中对活动添加如下配置:

android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"

添加这行配置后,不管是进入多窗口模式还是横竖屏切换,活动都不会被重新创建,而是会将屏幕发生变化的事件通知到 Activity 的 onConfigurationChanged() 方法中。因此,若要在屏幕发生变化时进行相应的逻辑处理,那么在活动中重写 onConfigurationChanged() 方法即可。

5.3 禁用多窗口模式

在 AndroidManifest.xml 中,只要在Activity 或者 application中添加 android:resizeableActivity="false"  即可。


六  Lambda 表达式

Lambda表达式本质上是一种一名方法,它既没有方法名,也没有访问修饰符和返回值类型,使用它来编写代码将会更加简介,也更加易读。

Android Studio 2.1.1之前,需要自己导入插件

 dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.2.0'
  }

在 Module 的 build.gradle 中添加如下代码

// 应用插件
  apply plugin: 'me.tatarka.retrolambda'
 
  // 支持Java8
  android {
      compileOptions {
          sourceCompatibility JavaVersion.VERSION_1_8
          targetCompatibility JavaVersion.VERSION_1_8
      }
  }

Android Studio 2.1.1之后(支持lambda插件)

android {
      defaultConfig {
          jackOptions {
              // 打开jack编译器
              enabled true
          }
      }
 
      // 编译支持Java8
      compileOptions {
          sourceCompatibility JavaVersion.VERSION_1_8
          targetCompatibility JavaVersion.VERSION_1_8
      }
  }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

许进进

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值