在我們學習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;
}
}
Intent傳遞基礎型別的資料相信你已經比較熟悉了,可是如果我們想要用Intent傳遞一個物件的話那該怎樣處理呢?本節我們就來學習一下使用Intent傳遞物件。
使用步驟:
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();
}
}
使用步驟:
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();
}
}
現在讓我們設想一個場景,你正在編寫一個比較龐大的專案,期間為了方便偵錯,在程式碼的很多地方都列印了大量的紀錄檔。最近專案已經基本完成了,但是卻有一個非常令人頭痛的問題,之前用於偵錯的那些紀錄檔,在專案正式上線之後仍然會照常列印,這樣不僅會降低程式的執行效率,還有可能將一些機密性的資料洩露出去。那可能會有人說我把列印紀錄檔的程式碼一行一行全部刪掉就行了,這顯然不是什麼好點子,不僅費事費力,而且以後你繼續維護這個專案時可能還會需要這些紀錄檔。本節我們就來學習該如何優雅的解決這個問題。
解決方法:
事實上這個問題的解決方法非常簡單,我們只需要定義一個自己的紀錄檔工具,並在裡面對列印紀錄檔條件加上限制條件即可。
範例:
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);
}
}
}
Android中的定時任務一般有兩種實現方式,一種是java API裡提供的Timer類,一種是使用Android的Alarm機制。而兩者的區別在於:Android手機會在長時間不操作的情況下自動讓CPU進入到睡眠狀態,這就有可能導致Timer中的定時任務無法正常執行,而Alarm則具有喚醒CPU的功能。(這裡要注意喚醒CPU和喚醒螢幕完全是兩個概念)
使用步驟:
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()方法即可。
Doze模式是Android6.0系統新加入的一種省電模式。該模式下系統會對CPU,網路,Alarm等活動進行限制,從而延長電池的使用壽命。因此這種模式也就極大的影響了我們Alarm任務的執行時間。不過倘若你真的有非常特殊的需求,要求在Doze模式下Alarm任務也要必須正常執行,Android還是提供瞭解決方案的。我們只需呼叫AlarmManger的setAndAllowWhileIdle()或setExactAndAllowWhileIdle()方法即可讓你的Alarm任務在Doze模式下也能正常執行了。
多視窗模式也就是我們現在經常說的分屏模式了。
當一個活動進入多視窗模式或橫豎屏切換時,該活動會重新建立。多視窗模式下正在與使用者互動的活動處於onResume狀態,另一個則處於onPause狀態。
另外,針對於進入多視窗模式時活動就會被重現建立,如果你想改變這一預設行為,只需在AndoridManifest.xml檔案中進行如下設定即可:
<activity android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize|screenLayout">
加入了這行設定之後,不管是進入多視窗模式,還是橫豎屏切換,活動都不會被重新建立,而是會將螢幕發生改變的事件通知到Activity的onConfigurationChanged()方法當中。
禁用多視窗模式的方法非常簡單,只需在AndroidManifest.xml的< application >或< activity >標籤下加入如下屬性即可:
android:resizeableActivity=["true"|"false"]
其中,true表示應用支援多視窗模式,false表示應用不支援多視窗模式,該屬性預設為true。
不過上面的方法只能在targetSdkVersion為24以上時才會有用,否則這個屬性是無效的。不過Android規定,當targetSdkVersion為24以下,並且活動不允許橫豎屏切換,那麼該應用也將不支援多視窗模式。設定方法如下:
android:screenOrientation=["portrait"|"landscap"]
其中,portrait表示活動只支援豎屏,landscap表示活動只支援橫屏。