Android開發(fā)入門小知識

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模式

從圖上可以看出, 手機退出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)注都是對我的鼓勵和支持~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容