1.全局獲取Context
Android提供了一個Application類,每當(dāng)應(yīng)用啟動的,系統(tǒng)就會自動將這個類進(jìn)行初始化,而我們可以定制一個自己的Application類,以便于管理程序內(nèi)一些全局的狀態(tài)信息,比如全局的Context。
1.自定義Application類
>public class MyApplication extends Application {
private static Context context;
@Override
public void onCreate() {
//重寫onCreate()方法,獲得context對象
context = getApplicationContext();
}
public static Context getContext() {
//外界調(diào)用,獲得context
return context;
}
}
2.在AndroidManifest.xml文件中指定加載MyApplication
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
3.外界調(diào)用的時候
Toast.makeText(MyApplication.getContext(), "點(diǎn)擊了頭像", Toast.LENGTH_SHORT).show();
2.使用Intent傳遞對象
Intent使用putExtra()方法傳遞數(shù)據(jù)時,所支持的類型是有限的,當(dāng)需要傳遞一些自定義對象時,就需要使用Serializable或者Parcelablc的方式來實(shí)現(xiàn)了。
一、Serializable方式
Serializable是序列化的意思,表示將一個對象轉(zhuǎn)換成可存儲或可傳輸?shù)臓顟B(tài),序列化后的對象可以在網(wǎng)絡(luò)上進(jìn)行傳輸,也可以存儲到本地,至于序列化的方法也很簡單,只需要讓一個類去實(shí)現(xiàn)Serializable這個接口就可以了。
1.1比如一個Person類,其中包含了name和age兩個字段,想要將它序列化就可以這樣寫:
//整個類中跟定義一個實(shí)體類大致相同,最最重要的是在第一行,讓Person類去實(shí)現(xiàn)Serializable接口。
public class Person implements Serializable {
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
1.2然后需要傳遞對象的activity中:
Intent intent = new Intent(mContext, FruitActivity.class);
Person person = new Person();
person.setAge(20);
person.setName("Tom");
intent.putExtra("person_data", person); MyApplication.getContext().startActivity(intent);
1.3在需要獲取對象的acidity中:
Person person = (Person) getIntent().getSerializableExtra("person_data");
二、Parcelabele方式
使用Parcelable同樣可以達(dá)到跟Serializable相同的效果,不同的是,Parcelabel方式的實(shí)現(xiàn)原理是將一個完整的對象進(jìn)行分解,而分解后的每一部分都是Intent所支持的數(shù)據(jù)類型。這樣也就實(shí)現(xiàn)傳遞對象的功能了。
2.1和Serializable一樣,需要使Person實(shí)現(xiàn)Parcelable接口。然后重寫describeContents()和writeToParcel()這兩個方法。其中describeContents()方法中直接返回0就可以了。而writeToParcel()需要調(diào)用writeXxx()方法,將Person類中的字段一一寫出。然后還要提供一個名為CREATOR的常量。
public class Person implements Parcelable {
private String name;
private int age;
public int getAge() {
return age;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
//重寫describeContents()方法
@Override
public int describeContents() {
return 0;
}
//重寫writeToParcel()方法
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);//寫出name
dest.writeInt(age);//寫出age
}
//定義CREATOR常量
public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
@Override
public Person createFromParcel(Parcel source) {
Person person = new Person();
person.setName(source.readString());//讀取name
person.setAge(source.readInt());//讀取age
return person;
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
}
2.2在需要傳遞對象的activity中,這跟Serializable是一樣
Intent intent = new Intent(mContext, FruitActivity.class);
Person person = new Person();
person.setAge(20);
person.setName("Tom");
intent.putExtra("person_data", person); MyApplication.getContext().startActivity(intent);
2.3在需要獲取對象的activity中
Person person = (Person) getIntent().getParcelableExtra("person_data");
3.定制自己的日志工具
定制日志工具,可以讓程序處于開發(fā)階段的時候就打印日志,處于上線階段的時候就不打印日志,便于后期維護(hù),也防止了私密信息的泄漏。
1.1如下,創(chuàng)建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 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);
}
}
}
1.2外界調(diào)用的時候直接通過LogUtil打印信息即可。并且當(dāng)我們設(shè)置LogUtil中的level等于VERBOSE就可以把所有日志都打印出來,等于WARN就可以只打印WARN以上級的日志,在發(fā)布之后,將level設(shè)置成NOTHING就可以把所有日志都屏蔽掉了。
LogUtil.d("TAG", "Debug log");
4. 創(chuàng)建定時任務(wù)
Android中的定時任務(wù)一般有兩種實(shí)現(xiàn)方式,一種是使用JavaAPI提供的Timer類,一種是Android的Alarm機(jī)制。兩種方式都能實(shí)現(xiàn)相同的效果,但是Timer有可能在手機(jī)休眠的狀態(tài)下無法正常運(yùn)行,而Alarm則具有喚醒CPU的功能,因此在手機(jī)休眠的狀態(tài)下也能保證定時任務(wù)的正常執(zhí)行。
一、Alarm機(jī)制
Alarm機(jī)制的用法,主要是借助AlarmManager類來實(shí)現(xiàn),這個類和NotificationManager有點(diǎn)類似,都是通過調(diào)用Context的getSystemService()方法傳入?yún)?shù)Context.ALARM_SERVICE來獲取實(shí)例。
1.1獲取AlarmManager實(shí)例
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
1.2調(diào)用AlarmManager的set()方法就可以設(shè)置一個定時任務(wù)了。比如設(shè)定一個任務(wù)在10秒后執(zhí)行
set()方法接收3個參數(shù):
第一個:一個整型參數(shù),用于指定AlarmManager的工作類型,有4種值可選:>>1. RTC_WAKEUP : 表示讓定時任務(wù)的觸發(fā)時間從1970年1月1日0時開始算起,但會喚醒CPU
- RTC : 表示讓定時任務(wù)的觸發(fā)時間從1970年1月1日0時開始算起,但不會喚醒CPU
- ELAPSED_REALTIME_WAKEUP : 表示讓定時任務(wù)的觸發(fā)時間從系統(tǒng)開機(jī)算起,但會喚醒CPU。
- ELAPSED_REALTIME : 表示讓定時任務(wù)的處罰時間從系統(tǒng)開機(jī)算起,但不會喚醒CPU>
第二個參數(shù):定時任務(wù)出發(fā)的時間,加上第一個參數(shù)設(shè)定值。
第三個參數(shù):PendingIntent對象。這里一般會調(diào)用getService()方法或者getBroadcast()方法來獲取一個能夠執(zhí)行服務(wù)或廣播接收器的onReceive()方法就可以得到執(zhí)行。
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
long triggerArTime = SystemClock.elapsedRealtime() + 10*1000;
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerArTime, pendingIntent);
1.3 如果需要實(shí)現(xiàn)一個長時間在后臺定時運(yùn)行的服務(wù),如下代碼,每個一小時就會啟用一次服務(wù)。
public class LongRunningService extends Service {
public LongRunningService() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
//這里執(zhí)行具體的操作邏輯
}
});
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int anHour = 60 * 60 * 1000; //一小時的毫秒數(shù)
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);
}
}
1.4 最后只需要在需要啟動服務(wù)的時候調(diào)用
Intent intent = new Intent(context, LongRunningService.class);
context.startService(intent);
注:從Android4.4開始,因?yàn)橄到y(tǒng)在好點(diǎn)性方面的調(diào)整,Alarm使用set()觸發(fā)任務(wù)的時間會變得不準(zhǔn)確,如果需要讓執(zhí)行時間變得準(zhǔn)確無誤,需使用setExact()方法來代替set()方法。
5.多窗口模式的一些設(shè)置
1.當(dāng)應(yīng)用進(jìn)入多窗口模式的時候,活動默認(rèn)會被重新創(chuàng)建,修改這一行為,可以在AndroidManifest.xml中對活動進(jìn)行如下設(shè)置
<activity
android:name=".FruitActivity"
android:theme="@style/FruitActivityTheme"
android:configChanges="orientation|keyboardHidden|screenSize|screenLayout">
</activity>
2.禁用多窗口模式
設(shè)置程序禁用多窗口模式,只需在application中把a(bǔ)ndroid:resizeableActivity設(shè)置為false即可。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.anwser_mac.materialtest">
<application
android:resizeableActivity="false"
注:android:resizeableActivity,是在targetSdkVersion大于24才有用的,如果對于一些沒有指定到24的項(xiàng)目,想要禁用多窗口模式,需要設(shè)置活動不允許橫豎屏切換,因?yàn)锳ndroid規(guī)定targetSdkVersion小于24并且活動不允許橫豎屏切換的應(yīng)用也不將不支持多窗口模式。
<activity
android:screenOrientation="portrait"http://landscape只支持橫屏,portrait為只支持豎屏。