第一行代碼(十三)

第十三章主要講了一些日常開發(fā)中常用的技巧

一洛勉、全局獲取 Context 的技巧

??截止到目前,我們還沒有碰見過為得不到 Context 而發(fā)愁的情況纵穿,因?yàn)槲覀兒芏嗟牟僮鞫际窃诨顒?dòng)中進(jìn)行的下隧,而活動(dòng)本身就是一個(gè) Context 對(duì)象,但是谓媒,當(dāng)應(yīng)用程序的架構(gòu)逐漸復(fù)雜起來的時(shí)候淆院,很多邏輯代碼都將脫離 Activity 類,但此時(shí)你又恰恰需要使用 Context句惯,這就傷腦筋了土辩。
??舉個(gè)例子,你寫了一個(gè) Util 類抢野,該類的某個(gè)方法需要用到 Context拷淘,怎么辦?也許你會(huì)想到通過方法傳遞進(jìn)來指孤,還是用代碼來說明吧启涯。

public class Util {

    public static void needContext(){
        //下面的邏輯處理需要用到 Context 對(duì)象
    }
}

??大多數(shù)人的第一反應(yīng)就是通過方法的參數(shù)傳遞進(jìn)來

public class Util {

    public static void needContext(Context context){
        //下面的邏輯處理需要用到 Context 對(duì)象
    }
}

??是的,沒問題恃轩,可以這樣寫结洼,但是如果調(diào)用方也獲取不到 Context 怎么辦?我們可以使用另一種更好的方法來解決這個(gè)問題叉跛。

Android 提供了一個(gè) Application 類松忍,每當(dāng)應(yīng)用程序啟動(dòng)的時(shí)候,系統(tǒng)就會(huì)自動(dòng)將這個(gè)類進(jìn)行初始化昧互。我們也可以定制一個(gè)自己的 Application 類挽铁,以便于管理程序內(nèi)一些全局的狀態(tài)信息伟桅,比如全局的 Context.

??首先你需要新建一個(gè)類敞掘,繼承自 Application

/**
 * 自定義 Application
 */

public class MyApplication extends Application {

    private static Context mContext;

    /**
     * 通過靜態(tài)方法獲取 Context
     */
    public static Context getContext(){
        return mContext;
    }

    /**
     * 重寫 onCreate() 方法
     */
    @Override
    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
    }
}

??接下來我們需要告知系統(tǒng),當(dāng)程序啟動(dòng)的時(shí)候應(yīng)該初始化 MyApplication 類楣铁,而不是默認(rèn)的 Application 類玖雁。

    <!-- 這里注意,一定是全包名盖腕,或者前面有個(gè)" . "赫冬,否則系統(tǒng)找不到這個(gè)類 -->
    <application
        android:name=".MyApplication"
        ...>

        ...
    </application>

??接下來,我們就可以在 Util 類里面這樣獲取 Context 了溃列。

public class Util {

    public static void needContext(){
        //下面的邏輯處理需要用到 Context 對(duì)象
        Context context = MyApplication.getContext();
    }
}

二劲厌、使用 Intent 傳遞對(duì)象

??我們可以借助 Intent 的 putExtra() 方法來傳遞數(shù)據(jù),里面可以傳遞boolean听隐、byte补鼻、short、int、long风范、float咨跌、double、char硼婿、String锌半,以及前面這些數(shù)據(jù)類型所對(duì)應(yīng)的數(shù)組形式的數(shù)據(jù)類型,那么傳遞對(duì)象呢寇漫?
??putExtra() 方法還有兩個(gè)數(shù)據(jù)類型:Serializable 和 Parcelable

    1. Serializable 方式:
      ??Serializable 是序列化的意思刊殉,表示將一個(gè)對(duì)象轉(zhuǎn)換成可存儲(chǔ)或可傳輸?shù)臓顟B(tài)。序列化后的對(duì)象可以在網(wǎng)絡(luò)上進(jìn)行傳輸州胳,也可以存儲(chǔ)到本地冗澈。至于序列化的方法也很簡(jiǎn)單,只需要讓類實(shí)現(xiàn) Serializable 接口即可陋葡。
/**
 * 實(shí)體類
 */

public class Fruit implements Serializable{

    ...
}

??使用 Intent 傳遞對(duì)象

        //發(fā)送方
        Fruit fruit = new Fruit();
        fruit.setName("蘋果");
        Intent intent = new Intent(this,MainActivity.class);
        intent.putExtra("fruit_data",fruit);
        startActivity(intent);
        //接收方
        /*
            通過 getSerializable() 方法獲取序列化對(duì)象亚亲,再向下轉(zhuǎn)型成 Fruit 對(duì)象即可
         */
        Fruit fruit_data = (Fruit) getIntent().getSerializableExtra("fruit_data");
    1. Parcelable 方式:
      ??不同于 Serializable ,Parcelable 方式的實(shí)現(xiàn)原理是將一個(gè)完整的對(duì)象進(jìn)行分解腐缤,而分解后的每一部分都是 Intent 所支持的數(shù)據(jù)類型捌归,這樣就實(shí)現(xiàn)傳遞對(duì)象的功能了。
      ??實(shí)現(xiàn) Parcelable 的方式首先也是讓一個(gè)類去實(shí)現(xiàn) Parcelable 接口岭粤。
/**
 * 實(shí)體類
 */

public class Fruit implements Parcelable {

    private String name;//水果的名字
    private int imageId;//水果對(duì)應(yīng)資源的圖片id

    public Fruit() {

    }

    public Fruit(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }

    protected Fruit(Parcel in) {
        /*
           這里注意惜索,讀取的順序一定要和剛才寫入的順序一致。
        */
        name = in.readString();
        imageId = in.readInt();
    }

    /**
     * 必須重寫的方法
     */
    @Override
    public int describeContents() {
        //這里直接返回 0 就可以了
        return 0;
    }

    /**
     * 必須重寫的方法
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        /*
            將字段一一寫出
            字符串調(diào)用 writeString()剃浇,整數(shù)調(diào)用 writeInt() 依此類對(duì)
         */
        dest.writeString(name);
        dest.writeInt(imageId);
    }

    /**
     * 定義一個(gè)常量巾兆,創(chuàng)建 Parcelable.Creator 接口的實(shí)現(xiàn),并且指定泛型為當(dāng)前類虎囚,
     */
    public static final Creator<Fruit> CREATOR = new Creator<Fruit>() {
        @Override
        public Fruit createFromParcel(Parcel in) {
            return new Fruit(in);
        }

        @Override
        public Fruit[] newArray(int size) {
            return new Fruit[size];
        }
    };

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getImageId() {
        return imageId;
    }

    public void setImageId(int imageId) {
        this.imageId = imageId;
    }

    @Override
    public String toString() {
        return "Fruit{" +
                "name='" + name + '\'' +
                ", imageId=" + imageId +
                '}';
    }
}

??具體的使用方法和 Serializable 類似角塑,只是在獲取的時(shí)候,只需要把 getSerializableExtra() 方法換成 getParcelableExtra() 方法即可淘讥。

注意:Serializable 的方式較為簡(jiǎn)單圃伶,但由于會(huì)把整個(gè)對(duì)象進(jìn)行序列化,因此效率會(huì)比 Parcelable 方式低一些蒲列,所以在通常情況下還是更加推薦使用 Parcelable 的方式來實(shí)現(xiàn) Intent 傳遞對(duì)象的功能窒朋。

三、定制自己的日志工具

??理想狀態(tài)下蝗岖,我們的日志打印是可以控制的侥猩,當(dāng)程序處于開發(fā)階段時(shí)就讓日志打印出來,當(dāng)程序上線了之后就把日志屏蔽掉抵赢。

/**
 * 日志工具類
 */

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;
    /*
        這里通過改變 level 的值來控制打印日志的行為欺劳,比如:
        讓 level 等于 VERBOSE 就是打印所有日志洛退,讓 level 等于
        WARN 就是只打印警告以上級(jí)別的日志,讓 level 等于
        NOTHING 就是把所有日志都屏蔽掉杰标。
     */
    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.v(tag, msg);
        }
    }

    public static void i(String tag, String msg) {
        if (level <= INFO) {
            Log.v(tag, msg);
        }
    }

    public static void w(String tag, String msg) {
        if (level <= WARN) {
            Log.v(tag, msg);
        }
    }

    public static void e(String tag, String msg) {
        if (level <= ERROR) {
            Log.v(tag, msg);
        }
    }
}

四兵怯、創(chuàng)建定時(shí)任務(wù)

??Android 中定時(shí)任務(wù)一般有兩種實(shí)現(xiàn)方式,一種是使用 Java API 里提供的 Timer 類腔剂,一種是使用 Android 的 Alarm 機(jī)制媒区。在大多數(shù)情況下,這兩種方式都能實(shí)現(xiàn)類似的效果掸犬,但是 Timer 有一個(gè)明顯的短板袜漩,它并不太適用于那么些需要長(zhǎng)期在后臺(tái)運(yùn)行的定時(shí)任務(wù),為了讓電池更加耐用湾碎,每種手機(jī)都會(huì)有自己的休眠策略宙攻,Android 手機(jī)會(huì)在長(zhǎng)時(shí)間不操作的情況下自動(dòng)讓 CPU 進(jìn)入休眠功狀態(tài),這就可能導(dǎo)致 Timer 中的定時(shí)任務(wù)無法正常運(yùn)行介褥。而 Alarm 則具有喚醒 CPU 的功能座掘,它可以保證在大多數(shù)情況下需要執(zhí)行定時(shí)任務(wù)的時(shí)候 CPU 都能正常工作,需要注意柔滔,這里喚醒 CPU 喚醒屏幕完全不是一個(gè)概念溢陪。

Alarm機(jī)制

??主要是借助了 AlarmManager 類來實(shí)現(xiàn),這個(gè)類 NotificationManager 有點(diǎn)類似睛廊。

        /*
            SystemClock.elapsedRealtime() 方法可以獲取到系統(tǒng)開機(jī)至今所經(jīng)歷時(shí)間的毫秒數(shù)
            System.currentTimeMillis() 方法獲取到的是1970年1月1日0點(diǎn)至今所經(jīng)時(shí)間的毫秒數(shù)
         */
        long triggerAtTime = SystemClock.elapsedRealtime() + 10 * 1000;
        AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        /*
            參1:用于指定AlarmManager的工作類型形真,有四種值可選:
                1.ELAPSED_REALTIME          :表示讓定時(shí)任務(wù)的觸發(fā)時(shí)間從系統(tǒng)開機(jī)開始算起,但不會(huì)喚醒CPU
                2.ELAPSED_REALTIME_WAKEUP   :表示讓定時(shí)任務(wù)的觸發(fā)時(shí)間從系統(tǒng)開機(jī)開始算起超全,但會(huì)喚醒CPU
                3.RTC                       :表示讓定時(shí)任務(wù)的觸發(fā)時(shí)間從1970年1月1日0時(shí)開始算起咆霜,但不會(huì)喚醒CPU
                4.RTC_WAKEUP                :表示讓定時(shí)任務(wù)的觸發(fā)時(shí)間從1970年1月1日0時(shí)開始算起,但會(huì)喚醒CPU
         */
        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pendingIntent);

??如果我們需要實(shí)現(xiàn)一個(gè)長(zhǎng)時(shí)間在后臺(tái)定時(shí)運(yùn)行的服務(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() {
                //處理具體的邏輯
            }
        }).start();
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        int anHour = 60 * 60 * 1000;//一小時(shí)的毫秒數(shù)
        //設(shè)置時(shí)間為一小時(shí)后執(zhí)行
        long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
        Intent i = new Intent(this,LongRunningService.class);
        PendingIntent pendingIntent = PendingIntent.getService(this,0,i,0);
        //執(zhí)行定時(shí)任務(wù)蛾坯,這樣會(huì)使得 LongRunningService 的onStartCommand() 方法每隔一小時(shí)就執(zhí)行一次
        alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pendingIntent);
        return super.onStartCommand(intent, flags, startId);
    }
}

注意:從Android 4.4 系統(tǒng)開始, Alarm 任務(wù)的觸發(fā)時(shí)間將變得不準(zhǔn)確见咒,有可能會(huì)延遲一段時(shí)間后任務(wù)才能得到執(zhí)行偿衰。這不是 bug挂疆,而是系統(tǒng)在耗電性方面進(jìn)行的優(yōu)化改览。系統(tǒng)會(huì)自動(dòng)檢測(cè)目前有多少 Alarm 任務(wù)存在,然后將觸發(fā)時(shí)間相近的幾個(gè)任務(wù)放在一起執(zhí)行缤言,這樣可以大幅度減少 CPU 被喚醒的次數(shù)宝当,從而有效延長(zhǎng)電池的使用時(shí)間。
??如果你要求 Alarm 任務(wù)的執(zhí)行事件必須準(zhǔn)確無誤胆萧,就要使用 AlarmManager 的 setExact() 方法代替 set() 方法庆揩。

Doze 模式

??Doze模式是Android6.0系統(tǒng)中新加入的模式俐东,從而可以極大幅度地延長(zhǎng)電池的使用壽命。
??Doze模式就是當(dāng)設(shè)備是 Android 6.0 及以上系統(tǒng)時(shí)订晌,如果該設(shè)備未插接電源虏辫,處于靜止?fàn)顟B(tài)(Android 7.0 中刪除了這一條件),且屏幕關(guān)閉了一段時(shí)間后锈拨,就會(huì)進(jìn)入到 Doze 模式砌庄,在 Doze 模式下,系統(tǒng)會(huì)對(duì) CPU奕枢、網(wǎng)絡(luò)娄昆、Alarm 等活動(dòng)進(jìn)行限制,從而延長(zhǎng)電池的使用壽命缝彬。
??當(dāng)然萌焰,系統(tǒng)并不會(huì)一直處于 Doze 模式,而是會(huì)間歇性地退出 Doze 模式一小段時(shí)間谷浅,在這段時(shí)間中扒俯,應(yīng)用就可以去完成他們的同步操作、Alarm任務(wù)

注意:隨著設(shè)備進(jìn)入 Doze 模式的時(shí)間越長(zhǎng)一疯,間歇性地退出 Doze 模式的時(shí)間間隔也會(huì)越長(zhǎng)陵珍,因?yàn)槿绻O(shè)備長(zhǎng)時(shí)間不使用的話,是沒有必要頻繁退出 Doze 模式來執(zhí)行同步等操作的违施。其中 Doze 模式下會(huì)受到限制的功能:
1.網(wǎng)絡(luò)訪問被禁止
2.系統(tǒng)忽略喚醒CPU或屏幕操作
3.系統(tǒng)不在執(zhí)行WIFI掃描
4.系統(tǒng)不再執(zhí)行同步服務(wù)
5.Alarm任務(wù)將會(huì)在下次退出Doze模式的時(shí)候執(zhí)行
??注意最后一條互纯,如果在 Doze 模式下,我們的任務(wù)將會(huì)變得不準(zhǔn)時(shí)

??如果你要求Alarm任務(wù)即使在Doze模式下也必須正常執(zhí)行磕蒲,Android還提供了解決方案留潦。調(diào)用 AlarmManager 的setAndAllowWhileIdle() 或者 setExactAndAllowWhileIdle() 方法就能讓定時(shí)任務(wù)即使在 Doze 模式下也能正常執(zhí)行了,這兩個(gè)方法的區(qū)別和 set()與setEsact()方法之間的區(qū)別是一樣的辣往。

五兔院、多窗口模式編程

??Android 7.0 系統(tǒng)中引入的特色功能,允許我們?cè)谕粋€(gè)屏幕中同時(shí)打開兩個(gè)應(yīng)用程序站削。
??如何進(jìn)入多窗口模式坊萝?一般手機(jī)底部按鍵有三個(gè),左邊的是返回鍵许起,右邊的是HOME鍵十偶,右邊的是Overview鍵,點(diǎn)一下Overview鍵园细,會(huì)打開一個(gè)最近訪問過的活動(dòng)或任務(wù)的列表界面惦积。


image.png

??那么我們可以通過兩種方式進(jìn)入多窗口模式:

  • 1.在 Overview 列表界面長(zhǎng)按任意一個(gè)活動(dòng)的標(biāo)題,將該活動(dòng)拖動(dòng)到屏幕突出顯示的區(qū)域猛频,則可以進(jìn)入多窗口模式狮崩。
  • 2.打開任意一個(gè)程序蛛勉,長(zhǎng)按 Overview 按鈕,也可以進(jìn)入多窗口模式(沒有試出來)


    image.png

    ??另外睦柴,我們還可以旋轉(zhuǎn)诽凌,使上下分屏變成左右分屏


    image.png

    ??如果想要退出多窗口模式,只要將屏幕中央的分割線向屏幕任意方向拖動(dòng)到底即可坦敌。

多窗口模式下的生命周期

??多窗口模式不會(huì)改變活動(dòng)原有的生命周期皿淋,只會(huì)將正和用戶交互的那個(gè)活動(dòng)設(shè)置為運(yùn)行狀態(tài),將另一個(gè)活動(dòng)設(shè)置為暫停狀態(tài)恬试。
??我們新建兩個(gè)項(xiàng)目窝趣,并且將這兩個(gè)項(xiàng)目的啟動(dòng) Activity 的生命周期都進(jìn)行打印。
??先運(yùn)行第一個(gè)項(xiàng)目


image.png

??在運(yùn)行第二個(gè)項(xiàng)目


image.png

??接下來我們進(jìn)入到多窗口模式
image.png

??可以看到训柴,第一個(gè)項(xiàng)目先銷毀然后重新創(chuàng)建哑舒,因?yàn)檫M(jìn)入多窗口模式后活動(dòng)的大小發(fā)生了比較大的變化,默認(rèn)是會(huì)重新創(chuàng)建活動(dòng)的幻馁。由于我進(jìn)入多窗口模式后又讓該項(xiàng)目獲取了焦點(diǎn)洗鸵,所以多執(zhí)行了一個(gè)onResume(),接下來將第二個(gè)項(xiàng)目從 Overview 列表中選中仗嗦。
image.png

??這時(shí)候只要我們點(diǎn)擊任意一個(gè)項(xiàng)目膘滨,就會(huì)切換這兩個(gè)項(xiàng)目的暫停還是活動(dòng)的狀態(tài)。


image.png

??一個(gè)onPause稀拐,另一個(gè)onResume

注意:在多窗口模式下我們需要考慮一些關(guān)鍵性的點(diǎn)火邓,比如說,在多窗口模式下德撬,用戶仍然可以看到處于暫停狀態(tài)的應(yīng)用铲咨,如果是播放器之類的應(yīng)用,此時(shí)就應(yīng)該能繼續(xù)播放視頻才對(duì)蜓洪。因此纤勒,我們最好不要在活動(dòng)的 onPause() 方法中去處理視頻播放器的暫停邏輯,應(yīng)該在 onStop() 方法中處理隆檀,并且在 onStart() 方法中恢復(fù)視頻播放摇天。

注意:如果想改變進(jìn)入多窗口模式時(shí)活動(dòng)會(huì)被重新創(chuàng)建這一默認(rèn)行為,可以在清單文件中進(jìn)行如下配置恐仑,加入了如下配置后泉坐,不管是進(jìn)入多窗口模式,還是橫豎屏切換菊霜,活動(dòng)都不會(huì)被重新創(chuàng)建坚冀,而是會(huì)將屏幕發(fā)生變化的事件通知到 Activity 的 onConfigurationChanged() 方法當(dāng)中

        <activity android:name=".MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize|screenLayout">
            
        </activity>

禁用多窗口模式

??如果你不希望應(yīng)用能夠在多窗口模式下運(yùn)行,就可以將這個(gè)功能關(guān)閉掉鉴逞,禁用多窗口模式的方法很簡(jiǎn)單记某,只需要在清單文件中的 <application> 或 <activity> 標(biāo)簽中加入如下屬性即可:
android:resizeableActivity="false",其中如果傳 true 表示支持多窗口模式构捡,也是默認(rèn)的情況液南,如果傳入 false 表示不支持多窗口模式。

注意:雖然說 android:resizeableActivity 屬性的用法很簡(jiǎn)單勾徽,但是他有一個(gè)很嚴(yán)重的問題滑凉,就是這個(gè)屬性只有當(dāng)項(xiàng)目的 targetSdkVersion 指定成 24 或更高的時(shí)候才會(huì)有用,否則這個(gè)屬性是無效的喘帚。
??解決方案:Android 規(guī)定畅姊,如果項(xiàng)目指定 targetSdkVersion 低于 24,并且活動(dòng)是不允許橫豎屏切換的吹由,那么該應(yīng)用也將不支持多窗口模式若未。
??那么讓應(yīng)用不允許橫豎屏切換,只需要在清單文件的 <activity> 標(biāo)簽中加入如下配置即可:android:screenOrientation="portrait" 或 android:screenOrientation="landscape"倾鲫,其中 portrait 表示活動(dòng)只支持豎屏粗合,landscape 表示活動(dòng)只支持橫屏。

六乌昔、Lambda表達(dá)式

??Java 8 中引入了一些非常有特色的功能隙疚,如 Lambda 表達(dá)式、stream API磕道、接口默認(rèn)實(shí)現(xiàn)等等供屉。其中,stream API 和接口默認(rèn)實(shí)現(xiàn)等特性都只支持 Android 7.0 及以上的系統(tǒng)溺蕉,而 Lambda 表達(dá)式最低兼容到 Android 2.3 系統(tǒng)贯卦,所以我們來學(xué)習(xí)一下 Lambda 表達(dá)式。

Lambda 表達(dá)式本質(zhì)上是一個(gè)匿名方法焙贷,它既沒有方法名撵割,也沒有訪問修飾符和返回值類型,使用它來編寫代碼將會(huì)更加簡(jiǎn)潔辙芍,更加易讀啡彬。

??如果要在 Android 項(xiàng)目中使用 Labmda 表達(dá)式或者 Java 8中的其他新特性,需要在 app/build.gradle 中添加如下配置:

android {
    ...
    defaultConfig {
        ...
        jackOptions.enabled = true;
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

注意:如果你的項(xiàng)目中有 Android Library 模塊故硅,那么上述方式是不能引用成功的庶灿,我們首先要在最外層的 project build.gradle 中加入這句話classpath 'me.tatarka:gradle-retrolambda:3.2.0'
然后在要使用 lambda 表達(dá)式的 Module 的 build.gradle 中加入如下代碼

apply plugin: 'me.tatarka.retrolambda'
android {
    ...

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

??寫個(gè)簡(jiǎn)單的例子:

        //開啟線程傳統(tǒng)寫法
        new Thread(new Runnable() {
            @Override
            public void run() {
                //具體處理邏輯
            }
        }).start();

        //開啟線程 Lambda 表達(dá)式
        new Thread(() -> {
            //具體處理偶偶機(jī)
        }).start();

??能這樣寫是因?yàn)?Thread 類的構(gòu)造函數(shù)接收的參數(shù)是一個(gè) Runnable 接口,并且改接口中只有一個(gè)待實(shí)現(xiàn)的方法吃衅。

注意:凡是這種只有一個(gè)待實(shí)現(xiàn)方法的接口往踢,都可以使用 Lambda 表達(dá)式的寫法

        //傳統(tǒng)寫法
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                //具體處理邏輯
            }
        };

        //Lambda 寫法
        Runnable runnable1 = () -> {
            //具體處理邏輯
        };

??接下來,我們自定義一個(gè)接口徘层,再使用 Lambda 表達(dá)式的方式進(jìn)行實(shí)現(xiàn)峻呕。

/**
 * 定義一個(gè)接口
 */
public interface MyListener {
    //注意利职,該方法有返回值,有參數(shù)
    String doSomething(String a,int b);
}
        //Lambda 表達(dá)式寫法
        MyListener myListneer2 = (String a,int b) -> {
            return a + b;
        };

         /*
            還可以精簡(jiǎn)成這樣
            這里瘦癌,Java 會(huì)自動(dòng)判斷出 a 和 b 的數(shù)據(jù)類型
         */
        MyListener myListener2 = (a, b) -> {
            return a + b;
        };

??假如有一個(gè)方法猪贪,需要傳入 MyListener 接口

    public void hello(MyListener mListener) {
        String a = "Hello Lambda";
        int b = 1024;
        String result = mListener.doSomething(a, b);
        Log.d(TAG, "hello: " + result);
    }
        //傳統(tǒng)寫法
        hello(new MyListener() {
            @Override
            public String doSomething(String a, int b) {
                return a + b;
            }
        });

        //Lambda 表達(dá)式
        hello((a, b) -> {
            return a + b;
        });

??Lambda表達(dá)式的基本用法已經(jīng)掌握了,接下來看一看在 Android 中有哪些常用的功能是可以使用 Lambda 表達(dá)式替換的讯私。
??其實(shí)热押,只要符合接口中只有一個(gè)待實(shí)現(xiàn)方法這個(gè)規(guī)則的功能,都是可以使用 Lambda 表達(dá)式來編寫的斤寇,除了開啟子線程之外桶癣,還有點(diǎn)擊事件之類的功能。

        //傳統(tǒng)寫法
        findViewById(R.id.tv).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //處理點(diǎn)擊事件
            }
        });

        //Lambda 表達(dá)式
        findViewById(R.id.tv).setOnClickListener((v) -> {
            //處理點(diǎn)擊事件
        });

注意:另外娘锁,當(dāng)接口的待實(shí)現(xiàn)方法有且只有一個(gè)參數(shù)的時(shí)候牙寞,我們還可以進(jìn)一步簡(jiǎn)化,將參數(shù)外面的括號(hào)去掉

        //Lambda 表達(dá)式進(jìn)一步簡(jiǎn)化
        findViewById(R.id.tv).setOnClickListener(v -> {
            //處理點(diǎn)擊事件
        });

下一篇文章:http://www.reibang.com/p/3487e4dd8db4

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末致盟,一起剝皮案震驚了整個(gè)濱河市碎税,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌馏锡,老刑警劉巖雷蹂,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異杯道,居然都是意外死亡匪煌,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門党巾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萎庭,“玉大人,你說我怎么就攤上這事齿拂〔倒妫” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵署海,是天一觀的道長(zhǎng)吗购。 經(jīng)常有香客問我,道長(zhǎng)砸狞,這世上最難降的妖魔是什么捻勉? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮刀森,結(jié)果婚禮上踱启,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好埠偿,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布透罢。 她就那樣靜靜地躺著,像睡著了一般胚想。 火紅的嫁衣襯著肌膚如雪琐凭。 梳的紋絲不亂的頭發(fā)上芽隆,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天浊服,我揣著相機(jī)與錄音,去河邊找鬼胚吁。 笑死牙躺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的腕扶。 我是一名探鬼主播孽拷,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼半抱!你這毒婦竟也來了脓恕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤窿侈,失蹤者是張志新(化名)和其女友劉穎炼幔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體史简,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乃秀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了圆兵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跺讯。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖殉农,靈堂內(nèi)的尸體忽然破棺而出刀脏,到底是詐尸還是另有隱情,我是刑警寧澤超凳,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布愈污,位于F島的核電站,受9級(jí)特大地震影響聪建,放射性物質(zhì)發(fā)生泄漏钙畔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一金麸、第九天 我趴在偏房一處隱蔽的房頂上張望擎析。 院中可真熱鬧,春花似錦、人聲如沸揍魂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽现斋。三九已至喜最,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間庄蹋,已是汗流浹背瞬内。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留限书,地道東北人虫蝶。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像倦西,于是被迫代替她去往敵國(guó)和親能真。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,742評(píng)論 25 707
  • 服務(wù)是什么扰柠?Service是Android系統(tǒng)中的四大組件之一粉铐,主要有兩個(gè)應(yīng)用場(chǎng)景:后臺(tái)運(yùn)行和跨進(jìn)程訪問。Serv...
    飛行員suke閱讀 972評(píng)論 0 1
  • 本篇文章主要介紹以幾下個(gè)知識(shí)點(diǎn):獲取全局 Context使用 Intent 傳遞對(duì)象定制日志工具創(chuàng)建定時(shí)任務(wù)多窗口...
    開心wonderful閱讀 1,431評(píng)論 5 28
  • 獲取全局Context的技巧 我們首先看一下Context類的結(jié)構(gòu) 不難看出Context一共有三種類型卤档,分別是A...
    小徐andorid閱讀 1,029評(píng)論 1 0
  • 桃花 三生三世 傲然枝頭 粉墨點(diǎn)點(diǎn) 白凈晶瑩 風(fēng)兒吹過 我看見 你的裙擺輕動(dòng) 一陣陣地 攜起芬芳襲襲 梨花 一夜春...
    笑陽依舊閱讀 275評(píng)論 0 1