1.獲取全局Context
通過Context, 可以啟動服務(wù), Activity, 通知, 創(chuàng)建操控內(nèi)容提供器(ContentProvider)的對象SQLiteOpenHelper等. 在Activity中可以很容易獲取Context, 但是在自己封裝的工具類中, 就不能像Activity中使用繼承至父類方法getContext來獲取. 通用的方法是獲取Application的Context.
首先新建繼承自Application的類MyApplication.
public class MyApplication extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public static Context getContext() {
return context;
}
}
然后再AndroidManifest中使用新建的MyApplication.
<application
android:name=".MyApplication"
...
</application>
這樣在封裝的工具類中就可以使用MyApplication的getContext方法, 輕易獲取全局Context.
public class HttpUtil {
public static void sendHttpRequest(final String address, final HttpCallbackListener listener){
if (!isNetworkAvailable()){
Toast.makeText(MyApplication.getContext(), "noNet", Toast.LENGTH_SHORT).show();
return;
}
new Thread(
new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
try {
URL url = new URL(address);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
connection.setDoInput(true);
connection.setDoOutput(true);
InputStream in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null){
response.append(line);
}
if (listener != null){
listener.onFinish(response.toString());
}
}catch (Exception e){
if (listener != null){
listener.onError(e);
}
}finally {
if (connection != null){
connection.disconnect();
}
}
}
}
).start();
}
private static boolean isNetworkAvailable(){
return true;
}
}
2.實現(xiàn)自己的Log日志工具類
開發(fā)過程中, 我們常常借助打印出的詳細(xì)日志來調(diào)試程序, 可以幫助自己理順開發(fā)邏輯思路. 但是, 如果發(fā)布之后就沒有必要再次打印, 不然會在后臺消耗大量的手機資源, 給用戶造成App是耗電大戶的假象. 解決方式是可以自定義日志工具類, 通過參數(shù)控制日志是否打印.
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 final 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);
}
}
}
調(diào)試狀態(tài)下, 把level設(shè)置成VERBOSE的級別, 打印出所有日志; 發(fā)布時, 將level設(shè)置成NOTHING級別, 不打印日志.
3.后臺定時執(zhí)行
很多時候, 作為前端的App需要和服務(wù)端定時通信, 比如行情數(shù)據(jù)的刷新、報價的定時提醒等. Android中通過AlarmManager可以實現(xiàn).
public class LongRunningService extends Service {
@Nullable
@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() {
Log.d("LongRunningService", "run: ");
}
}).start();
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int dur = 5 * 1000;
long triggerAtTime = SystemClock.elapsedRealtime() + dur;
Intent intent1 = new Intent(this, LongRunningService.class);
PendingIntent pi = PendingIntent.getService(this, 0, intent1, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
return super.onStartCommand(intent, flags, startId);
}
}
通過SystemClock.elapsedRealtime()可以獲取自從Android開機累計的時間. 通過System.currentTimeMillis()可以獲取自從1970年1月1日0點( UNIX和C語言誕生)開始累計的時間. manager的set方法接受3個參數(shù), 第一個參數(shù)表示啟用的時間起點: ELAPSED_REALTIME_WAKEUP表示使用開機累計的時間, RTC表示1970年累計的時間. 第二個參數(shù)表示觸發(fā)的時間點. 第三個參數(shù)表示要啟動的PendingIntent.
通過以上設(shè)置, 就能在啟用LongRunningService后, 每隔5s執(zhí)行Thread中的run方法.
4.Doze模式
為了限制Android后臺服務(wù)過多造成的耗電過快問題, Android6.0推出了Doze模式. 在Doze模式下, 系統(tǒng)會對CPU、網(wǎng)絡(luò)、Alarm活動等進行限制.

從圖上可以看出, 手機退出Doze模式間隔的時間逐漸延長, 因為這時可以認(rèn)為用戶與手機交互的需要逐漸降低. 如果在Doze模式下要求Alarm強制執(zhí)行, 可以使用AlarmManager的setAndAllowWhileIdle或者setExactAndAllowWhileIdle方法.
5.0 使用Intent傳遞對象
我們知道通過Intent可以傳遞String, int等基本數(shù)據(jù)類型, 但是如果是class對象, 該如何傳遞呢? 有Serializable和Parcelable兩種方式.
<1>Serializable
public 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;
}
}
然后就可以用Intent來傳遞:
Person person = new Person();
person.setAge(18);
person.setName("xiaoming");
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("person", person);
startActivity(intent);
在SecondActivity中的獲取方式:
Person person = (Person) intent.getSerializableExtra("person");
Log.d(TAG, "onCreate: " + person.getName() + ", " + person.getAge());
<2>Parcelable
Android推出Parcelable是為了解決使用Serializable存取對象效率過慢的問題, 將存取對象的地方從硬盤中提升到內(nèi)存中進行. 它也通過接口的方式來實現(xiàn).
public class Person 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;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);
parcel.writeInt(age);
}
public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
@Override
public Person createFromParcel(Parcel parcel) {
Person person = new Person();
person.name = parcel.readString();
person.age = parcel.readInt();
return person;
}
@Override
public Person[] newArray(int i) {
Log.d(TAG, "newArray11111: " + i);
return new Person[i];
}
};
}
傳遞方式和Serializable方式一樣, 獲取方式有所區(qū)別.
Person person = (Person) intent.getParcelableExtra("person");
Log.d(TAG, "onCreate: " + person.getName() + ", " + person.getAge());
6. 多窗口模式
在Android7.0下, 長按底部控制欄最右邊的OverView按鈕, 就會自動進入多窗口模式.

在項目MaterialTest3的MainActivity中, 我們在頁面的生命周期中添加打印消息, 來觀察多窗口模式下頁面的生命周期.
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MaterialTest3";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: ");
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG, "onStart: ");
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume: ");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause: ");
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop: ");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, "onRestart: ");
}
}
觀察打印日志:
D/MaterialTest3: onPause:
D/MaterialTest3: onStop:
D/MaterialTest3: onDestroy:
D/MaterialTest3: onCreate:
D/MaterialTest3: onStart:
D/MaterialTest3: onResume:
D/MaterialTest3: onPause:
可以看到界面實際上是重新銷毀, 二次創(chuàng)建的過程.
通過設(shè)置MainActivity的屬性來禁用多窗口模式:
<activity android:name=".MainActivity"
android:resizeableActivity="false"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
7.Lambda表達式
Android是基于Java的語言, Java 8.0的發(fā)布也給Android的開發(fā)帶來了便利. Java8.0支持Lamda表達式、streamAPI、接口默認(rèn)實現(xiàn)等. streamAPI和接口默認(rèn)實現(xiàn)只支持Android 7.0以上的系統(tǒng), 而Lamda表達式最低支持Android 2.3, 值得學(xué)習(xí)一下.
首先需要在app的build.gradle文件中添加Java8的支持.
defaultConfig {
jackOptions.enabled = true
...
}
compileOptions{
sourceCompatibility org.gradle.api.JavaVersion.VERSION_1_8
targetCompatibility org.gradle.api.JavaVersion.VERSION_1_8
}
然后我們可以很方便的實現(xiàn)只有一個方法的接口. 首先定義接口:
public interface MyInterface_Lambda {
public String speak(String a, String b);
}
然后可以如下實現(xiàn)和調(diào)用接口:
MyInterface_Lambda myInter = (a, b) -> {
return a + b;
};
myInter.speak("Hello ", "world!");
其中Lambda表達式可以自動推導(dǎo)出參數(shù)a, b 為String類型. 是不是很方便?
喜歡和關(guān)注都是對我的鼓勵和支持~