Android第一行代码——14章继续进阶-你还应该掌握的高级技巧
文章目录
- 全局获取Context的技巧
- 使用Intent传递对象
-
- Serializable
- Parcelable
- 定制自己的日志工具
- 创建定时任务
-
- Alarm机制
- Doze模式
- 多窗口模式
-
- 禁用多窗口模式
- Lambda表达式
全局获取Context的技巧
Android提供了一个Application类,每当应用程序启动的时候,系统就会自动把这个类进行初始化。我们可定制一个自己的Application类,用于获取全局Context
示例:
1.创建Application的子类对象,提供获取content的方法
import android.app.Application;import android.content.Context;public class MyApplication extends Application { private static Context context; @Override public void onCreate() { super.onCreate(); context = getApplicationContext(); } //提供getContext()方法 public static Context getContext(){ return context; }}
2.在AndroidManifest.xml文件的application标签下指定,告知系统启动的是MyApplication,而不是默认的Application
<application android:name=".MyApplication" ...... </application>
问题:为了让LitePal正常工作,必须要配置
<application android:name="org.litepal.LitePalApplication" ...... </application>
这样配置之后,LitePal就可在内部自动获取到Context了。但是这样既无法配置MyApplication了,因为一个项目只能配置一个Application
解决办法:在我们自己的Application中调用LitePal的初始化方法就行
public class MyApplication extends Application { private static Context context; @Override public void onCreate() { super.onCreate(); context = getApplicationContext(); LitePal.initialize(context); } //提供getContext()方法 public static Context getContext(){ return context; }}
使用Intent传递对象
平时我们在用Intent传递数据时都用的putExtra()方法,但是当我们要传递的数据是自定义对象时,无法传递。实现方法如下:
Serializable
序列化的意思,表示吧一个对象转换成可储存或可传输的状态,序列化后的对象可以在网络上传输,也可储存到本地
是一个接口,用时直接实现接口就可
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; } }
发送:
Person person = new Person(); person.setAge(12); person.setName("dag"); Intent intent = new Intent(MainActivity.this,MainActivity2.class); intent.putExtra("person_data",person); startActivity(intent);
接收:(注意:与原来的接收不同)
Intent intent = getIntent(); Person person = (Person)intent.getSerializableExtra("person_data");
Parcelable
它的实现原理是将一个完整的对象进行分解,分解后的每一部分都是Intent所支持的数据类型
class people implements Parcelable{ 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; }//直接返回0 @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { //调用Parcel的writeXXX方法,吧类中的字段一一写出 dest.writeString(name); dest.writeInt(age); } public static final Parcelable.Creator<people> CREATOR = new Parcelable.Creator<people>(){ @Override public people createFromParcel(Parcel source) { //读取刚才写出的name和age字段,读取顺序一定要和写入的完全相同 people people1 = new people(); people1.name = source.readString(); people1.age = source.readInt(); return people1; } @Override public people[] newArray(int size) { return new people[size]; } };}
发送:
people people1 = new people(); people1.setAge(12); people1.setName("134455"); Intent intent1 = new Intent(MainActivity.this,MainActivity2.class); intent.putExtra("people_data",person); startActivity(intent);
接收:(注意:与原来的接收不同)
Intent intent = getIntent();people people1 = (people) intent.getParcelableExtra("people_data");
定制自己的日志工具
目的:自由的控制日志的打印
示例:
class LogUtil{ public static final int VERBOSE = 1; public static final int DEBUG = 2; public static final int INFO = 3; public static final int ERROR = 5; public static final int WARN = 4; 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); }}
之后只需要修改level变量,就可控制打印情况
创建定时任务
Android中的定时任务一般有两种实现方式,一种是Java API里的Timer类,一种是Android的Alarm机制
Timer并不太实用于那些需要长期在后台运行的定时任务,当长时间时,CPU进入到睡眠状态,可能导致Timer的定时任务无法正常运行
Alarm机制
可以保证大多数情况下需要执行定时任务时CPU都能正常工作
如下是一个长时间在后台定时运行的服务
public class LongRuningService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; } /* 一旦启动LongRuningService就会在onStartCommand中执行一个定时任务, 这样一个小时后将在此启动LongRuningService,形成循环 */ @Override public int onStartCommand(Intent intent, int flags, int startId) { new Thread(new Runnable() { @Override public void run() { //执行具体的操作逻辑 } }).start(); //获取AlarmManager对象 AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE); int anHour = 60*60*1000; Long l = System.currentTimeMillis(); //SystemClock.elapsedRealtime()获取开机至今的毫秒数 //System.currentTimeMillis() 获取1970年 一月一日0点至今所经历的毫秒数 Long triggerAtTime = SystemClock.elapsedRealtime()+anHour; Intent intent1 = new Intent(this,LongRuningService.class); PendingIntent pendingIntent = PendingIntent.getService(this,0,intent1,0); //设置定时任务 manager.set(AlarmManager.RTC_WAKEUP,triggerAtTime,pendingIntent); /*三个参数: 第一个是整型参数用于指定AlarmManager的工作类型 第二个:触发时间 第三个是 PendingIntent */ return super.onStartCommand(intent,flags,startId); }}
AlarmManager的工作类型 | 说明 |
---|---|
ELAPSED_REALTIME | 让定时任务从系统开机开始算起,但不会唤醒CPU |
ELAPSED_REALTIME_WAKEUP | 让定时任务从系统开机开始算起,唤醒CPU |
RTC | 让系统任务从1970年一月一日0点开始算起,但不会唤醒CPU |
RTC_WAKEUP | 让系统任务从1970年一月一日0点开始算起,唤醒CPU |
注:对于不同的工作类型,要选择不同的时间
如果你要求Alarm任务的执行时间必须准确无误,应用setExact()方法替换set()方法
Doze模式
当用户设备是Android 6.0 或以上系统时,如果未插接电源,且屏幕关闭了一段时间之后就会进入到Doze模式
在该模式下,系统会对CPU,网络,Alarm等活动进行限制,从而延长电池的使用寿命
当然,它不会一直处于该模式,而是会间隙性的退出Doze模式一小段时间,在这段时间中去完成同步操作,Alarm任务
注:Doze模式下,Alarm任务就会变的不准时,解决方案
吧set()方法换成setExactAndAllowWhileIdle()或setAndAllowWhileIdle()方法就可让定时任务在Doze模式下也可正常执行
多窗口模式
即我们常见的分屏操作,在该模式下活动会有一个重新创建的过程,如果操作一个程序,另一个程序会进入暂停状态(onPause)
如果你想改变进入多窗口模式活动被重新创建,可添加如下配置
<activity android:name=".MainActivity" android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"> ..... </activity>
禁用多窗口模式
<application.... android:resizeableActivity="false"> ..... </application>
true表示支持,false表示不支持,默认是支持
Lambda表达式
android studio 中的配置
1.app的build文件下配置好
jackOptions{ enabled true }compileOptions{ sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } retrolambda { //指定将源码编译的级别,使用下列代码,会将代码编译到兼容1.6的字节码格式 javaVersion JavaVersion.VERSION_1_6 }
2.项目build文件下也要加上配置
apply plugin: 'me.tatarka.retrolambda'//lambdadependencies { classpath 'com.android.tools.build:gradle:3.1.3' classpath 'me.tatarka:gradle-retrolambda:3.7.0' //lambda // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }
剩下的使用和java使用方法一样
Lambda表达式
更多相关文章
- 浅谈Java中Collections.sort对List排序的两种方法
- Python list sort方法的具体使用
- python list.sort()根据多个关键字排序的方法实现
- 解析底层原理!月薪20k+的Android面试都问些什么?深夜思考
- Android中的消息机制
- android auto 能微信_5分钟搞定Flutter与Android(安卓)的交互(内
- 【Android(安卓)UI设计与开发】第06期:底部菜单栏(一)使用TabActivi
- Unity3D研究院之与Android相互传递消息(十九)
- 在Android中监控来电和去电