文章目录
- 1.全局获得Context的技巧
- 2.使用Intent传递对象
- 2.1Serializable方式
- 2.2Parcelable方式
- 3.定制自己的日志工具
- 4.创建定时任务
- 4.1Alarm机制
- 4.2Doze模式
- 5.多窗口模式编程
- 5.1多窗口模式下的生命周期
- 5.2禁用多窗口模式
1.全局获得Context的技巧
在我们学习Android基础知识的时候,你会发现在很多地方我们都会使用到Context,弹出Toast的时候需要,启动活动的时候需要,发送广播的时候需要,操作数据库的时候需要,使用通知的时候需要,等等等等。所以有时候在需要使用Context时,却不知道该怎么获得Context将会是一件非常伤脑筋的事情。本节我们就来介绍一个全局获得Context的技巧。
使用步骤:
1.新建类继承Application类,在其中获取Context并定义一个用于外部获取Context的方法。
2.给AndroidManifest.xml设置android:name属性。也就是告知系统,当程序启动时应该初始化MyApplication类,而不是默认的Application类。
示例:
//步骤一
public class MyApplication extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context=getApplicationContext();
}
public static Context getContext(){
return context;
}
}
//步骤二
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.temp">
<application
android:name=".MyApplication"//告知系统当程序启动时初始化MyApplication类
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
这里还有个小问题:在我们学习LitePal时我们也需要设置AndroidManifest.xml中的android:name属性,那当你两者都想要使用时该怎样处理呢?其实解决方法也很简单,我们只需在我们自己的Application中调用LitePal的初始化方法即可。
示例:
public class MyApplication extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context=getApplicationContext();
LitePal.initialize(context);
}
public static Context getContext(){
return context;
}
}
2.使用Intent传递对象
Intent传递基础类型的数据相信你已经比较熟悉了,可是如果我们想要用Intent传递一个对象的话那该怎样处理呢?本节我们就来学习一下使用Intent传递对象。
2.1Serializable方式
使用步骤:
1.定义一个你想要传递的类,并让该类继承Serializable接口。
2.调用putExtra()方法向Intent中存储对象,调用getSerializableExtra()方法从Intent中获取对象。
Serializable详解:Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。
示例:
//步骤一
public class Student implements Serializable {
String name;
int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
}
//步骤二
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button=(Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(MainActivity.this,MainActivity2.class);
Student student=new Student("Tom",18);
intent.putExtra("Student",student);//向Intent中存储对象
startActivity(intent);
}
});
}
}
public class MainActivity2 extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Intent intent=getIntent();
Student student= (Student) intent.getSerializableExtra("Student");//从Intent中获取对象
Toast.makeText(MainActivity2.this,student.name,Toast.LENGTH_SHORT).show();
}
}
2.2Parcelable方式
使用步骤:
1.定义一个你想要传递的类,让其继承Parcelable接口并实现接口中的一些方法。
2.调用putExtra()方法向Intent中存储对象,调用getParcelableExtra()方法从Intent中获取对象。
Parcelable详解:Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了。
示例:
//步骤一
public class Student implements Parcelable {
String name;
int age;
public Student(){
}
public Student(String name,int age){
this.name=name;
this.age=age;
}
public static final Creator<Student> CREATOR = new Creator<Student>() {
@Override
public Student createFromParcel(Parcel in) {
Student student=new Student();
student.name=in.readString();//读取name(注意这里的读取顺序要和写入顺序完全相同)
student.age=in.readInt();//读取int
return student;
}
@Override
public Student[] newArray(int size) {
return new Student[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);//写出name
parcel.writeInt(age);//写出age
}
}
//步骤二
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button=(Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(MainActivity.this,MainActivity2.class);
Student student=new Student("Tom",18);
intent.putExtra("Student",student);//向Intent中存储对象
startActivity(intent);
}
});
}
}
public class MainActivity2 extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Intent intent=getIntent();
Student student= (Student) intent.getParcelableExtra("Student");//从Intent中获取对象
Toast.makeText(MainActivity2.this,student.name,Toast.LENGTH_SHORT).show();
}
}
3.定制自己的日志工具
现在让我们设想一个场景,你正在编写一个比较庞大的项目,期间为了方便调试,在代码的很多地方都打印了大量的日志。最近项目已经基本完成了,但是却有一个非常令人头痛的问题,之前用于调试的那些日志,在项目正式上线之后仍然会照常打印,这样不仅会降低程序的运行效率,还有可能将一些机密性的数据泄露出去。那可能会有人说我把打印日志的代码一行一行全部删掉就行了,这显然不是什么好点子,不仅费事费力,而且以后你继续维护这个项目时可能还会需要这些日志。本节我们就来学习该如何优雅的解决这个问题。
解决方法:
事实上这个问题的解决方法非常简单,我们只需要定义一个自己的日志工具,并在里面对打印日志条件加上限制条件即可。
示例:
public class LogUtil {
private static final int VERBOSE=1;
private static final int DEBUG=2;
private static final int INFO=3;
private static final int WARN=4;
private static final int ERROR=5;
private static final int NOTHING=6;
private static int level=VERBOSE;//我们只需要更改level的值即可对不同等级的打印语句进行限制,而当我们不想打印任何日志时,我们只需将level的值设置为NOTHING即可。
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.创建定时任务
Android中的定时任务一般有两种实现方式,一种是java API里提供的Timer类,一种是使用Android的Alarm机制。而两者的区别在于:Android手机会在长时间不操作的情况下自动让CPU进入到睡眠状态,这就有可能导致Timer中的定时任务无法正常运行,而Alarm则具有唤醒CPU的功能。(这里要注意唤醒CPU和唤醒屏幕完全是两个概念)
4.1Alarm机制
使用步骤:
1.获取AlarmManager实例。
2.调用manager.set()方法创建定时任务。
示例:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button=(Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(MainActivity.this,MainActivity2.class);
PendingIntent pendingIntent=PendingIntent.getActivity(MainActivity.this,0,intent,0);
AlarmManager alarmManager= (AlarmManager) getSystemService(ALARM_SERVICE);//步骤一
long time= SystemClock.elapsedRealtime()+1000;
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,time,pendingIntent);//步骤二
}
});
}
}
manager.set()方法详解:第一个参数同于设置工作类型,ELAPSED_REALTIME型:表示定时任务的触发时间从系统开机开始算起,但不会唤醒CPU;ELAPSED_REALTIME_WAKEUP类型:表示定时任务的触发时间从系统开机开始算起,且会唤醒CPU;RTC类型:表示定时任务的触发时间从1970年1月1日0点开始算起,但不会唤醒CPU;RTC_WAKEUP类型:表示定时任务的触发时间从1970年1月1日0点开始算起,且会唤醒CPU。第二个参数就是定时任务的触发时间,以毫秒为单位(注意要与第一个参数相匹配)。第三个参数就是定时调度任务要执行的具体事件了。
注意:从Android4.4系统开始,Alarm任务的触发事件会变得不准确,有可能会延迟一段时间后才会执行,当然这可不是Bug,这只是为了能让手机更好的节省电量。但倘若你要求Alarm任务的执行时间必须准确无误,那么你只需将set()方法更改为setExact()方法即可。
4.2Doze模式
Doze模式是Android6.0系统新加入的一种省电模式。该模式下系统会对CPU,网络,Alarm等活动进行限制,从而延长电池的使用寿命。因此这种模式也就极大的影响了我们Alarm任务的执行时间。不过倘若你真的有非常特殊的需求,要求在Doze模式下Alarm任务也要必须正常执行,Android还是提供了解决方案的。我们只需调用AlarmManger的setAndAllowWhileIdle()或setExactAndAllowWhileIdle()方法即可让你的Alarm任务在Doze模式下也能正常执行了。
5.多窗口模式编程
多窗口模式也就是我们现在经常说的分屏模式了。
5.1多窗口模式下的生命周期
当一个活动进入多窗口模式或横竖屏切换时,该活动会重新创建。多窗口模式下正在与用户交互的活动处于onResume状态,另一个则处于onPause状态。
另外,针对于进入多窗口模式时活动就会被重现创建,如果你想改变这一默认行为,只需在AndoridManifest.xml文件中进行如下配置即可:
<activity android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize|screenLayout">
加入了这行配置之后,不管是进入多窗口模式,还是横竖屏切换,活动都不会被重新创建,而是会将屏幕发生改变的事件通知到Activity的onConfigurationChanged()方法当中。
5.2禁用多窗口模式
禁用多窗口模式的方法非常简单,只需在AndroidManifest.xml的< application >或< activity >标签下加入如下属性即可:
android:resizeableActivity=["true"|"false"]
其中,true表示应用支持多窗口模式,false表示应用不支持多窗口模式,该属性默认为true。
不过上面的方法只能在targetSdkVersion为24以上时才会有用,否则这个属性是无效的。不过Android规定,当targetSdkVersion为24以下,并且活动不允许横竖屏切换,那么该应用也将不支持多窗口模式。配置方法如下:
android:screenOrientation=["portrait"|"landscap"]
其中,portrait表示活动只支持竖屏,landscap表示活动只支持横屏。