網(wǎng)絡(luò)請(qǐng)求中代碼執(zhí)行順序

1 問(wèn)題的提出秆撮,最常見(jiàn)在網(wǎng)絡(luò)請(qǐng)求等耗時(shí)操作

  • 當(dāng)我們初學(xué)接觸網(wǎng)絡(luò)大千世界收壕,可能會(huì)遇到這樣的問(wèn)題歼捐,感覺(jué)java代碼的執(zhí)行順序似乎是亂的氓拼,某的代碼并沒(méi)有執(zhí)行而直接跳到下一步你画。下面通過(guò)Android Demo說(shuō)明問(wèn)題:
  • 布局很簡(jiǎn)單,就放了一個(gè)Button:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

   <Button
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="點(diǎn)我執(zhí)行"
       android:id="@+id/bt_click_execute"
       />
</LinearLayout>
  • 活動(dòng)MainActivity.java:
public class MainActivity extends AppCompatActivity {
    private String toastStr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.bt_click_execute)
                .setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        execute();
                    }
                });
    }
    private void execute() {
        toastStr = "execute開(kāi)始";
        toastStr = getWebData();/*模擬獲取網(wǎng)絡(luò)數(shù)據(jù)等耗時(shí)操作*/
        Toast.makeText(this, toastStr, Toast.LENGTH_LONG).show();
    }
    private String getWebData() {
       new Thread(new Runnable() {
           @Override
           public void run() {
               try {
                   Thread.sleep(1000*2);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               toastStr="模擬網(wǎng)絡(luò)返回的數(shù)據(jù)";
           }
       }).start();
       return toastStr;
    }
}
  • 簡(jiǎn)單說(shuō)一下活動(dòng)中的邏輯:
  1. 找到布局文件中的Button桃漾,并給它設(shè)置一個(gè)監(jiān)聽(tīng)坏匪,點(diǎn)擊Button,執(zhí)行execute()
  2. execute中有三個(gè)主要部分
    2.1 將字符串toastStr初始化為“execute開(kāi)始”;
    2.2 將方法getWebData返回的字符串賦值給toastStr;
    2.3 將toastStr字符串顯示出來(lái)撬统。
  3. getWebData方法中:
    3.1 開(kāi)啟一個(gè)新線程
    3.2 讓線程睡眠兩秒(模擬耗時(shí)操作)
    3.2 將"模擬網(wǎng)絡(luò)返回的數(shù)據(jù)" 賦值給toastStr
    3.3 返回toastStr
  • 那么在上面邏輯下面适滓,我們的顯示的字符串會(huì)是什么呢?看結(jié)果:


    1.png
  • 沒(méi)有看錯(cuò)恋追,這就是Toast顯示的字符串凭迹,是不是有些驚喜:不對(duì)啊罚屋,我們明明在getWebData中將字符串的值改成了模擬網(wǎng)絡(luò)返回的數(shù)據(jù)
  • 為了跟蹤toastStr的變化,我們?cè)倜恳淮蝨oasStr的值可能變化的地方蕊苗,添加Log沿后,看看問(wèn)題出在什么地方,修改代碼如下:
public class MainActivity extends AppCompatActivity {
    private String toastStr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.bt_click_execute)
                .setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        execute();
                    }
                });
    }

    private void execute() {
        toastStr = "execute開(kāi)始";
        Log.d("20180621", "在execute方法中第一步時(shí)候,toastStr: " + toastStr);
        toastStr = getWebData();/*模擬獲取網(wǎng)絡(luò)數(shù)據(jù)等耗時(shí)操作*/
        Log.d("20180621", "在execute方法中第二步時(shí)候,toastStr: " + toastStr);
        Toast.makeText(this, toastStr, Toast.LENGTH_LONG).show();
    }

    private String getWebData() {
        Log.d("20180621", "在getWebData方法中開(kāi)始時(shí),toastStr: " + toastStr);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000 * 2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                toastStr = "模擬網(wǎng)絡(luò)返回的數(shù)據(jù)";
                Log.d("20180621", "在getWebData方法中修改數(shù)據(jù)后,toastStr: " + toastStr);
            }
        }).start();
        Log.d("20180621", "在getWebData方法中返回前,toastStr: " + toastStr);
        return toastStr;
    }
}
  • Log打印結(jié)果:
    2.png
  • 特別注意劃線地方朽砰,我們注意到尖滚,從getWebData返回時(shí),toastStr的值還是原來(lái)的值瞧柔,這也就是為什么最后顯示的漆弄,就是該字符串。
  • 同時(shí)造锅,你也能發(fā)現(xiàn)撼唾,最后一條Log信息顯示,我們確實(shí)在某一個(gè)時(shí)候哥蔚,將字符串的值改成了"模擬網(wǎng)絡(luò)返回的數(shù)據(jù)"
  • 這里順帶提一下倒谷,Log打印的順序不一定就是代碼執(zhí)行的順序,所以要想依據(jù)Log打印的順序來(lái)推斷代碼執(zhí)行的順序是不可取的糙箍,除非你沒(méi)執(zhí)行一條Log打印一下系統(tǒng)當(dāng)前時(shí)間渤愁,或者你給每一條Log信息增加一個(gè)整形的標(biāo)識(shí),每打印一條深夯,讓它自增一下抖格。最佳方案嘛,就是給條Log添加說(shuō)明咕晋,像上面我做的那樣雹拄,(^-^)V,畢竟這樣清楚明了(然而這還是不能通過(guò)Log推斷執(zhí)行順序掌呜,當(dāng)然滓玖,其實(shí)絕大多數(shù)時(shí)間,兩者的順序是相同的_)质蕉。
  • 想要了解執(zhí)行順序呢撞,Debug(小蟲(chóng)子圖標(biāo))調(diào)試一下就OK了。
  • 通過(guò)log信息我們得到以下信息:
  1. getWebData方法返回時(shí)饰剥,并沒(méi)有修改字符串
  2. 也就是說(shuō)在方法getWebData中殊霞,代碼塊
new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000 * 2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                toastStr = "模擬網(wǎng)絡(luò)返回的數(shù)據(jù)";
                Log.d("20180621", "在getWebData方法中修改數(shù)據(jù)后,toastStr: " + toastStr);
            }
        }).start();

在方法返回后才執(zhí)行的(通過(guò)最后字符串變?yōu)椤澳M網(wǎng)絡(luò)返回的數(shù)據(jù)”推斷,其實(shí)只能推斷賦值語(yǔ)句在方法返回后才執(zhí)行汰蓉。我這么寫(xiě)是因?yàn)檎J(rèn)識(shí)了解了線程嘛绷蹲,還是那句話,想看看執(zhí)行順序,請(qǐng)Debug)祝钢,那么代碼執(zhí)行順序“有問(wèn)題”比规,是因?yàn)樾戮€程的原因咯,正是如此拦英!

2 多線程蜒什、異步任務(wù)給我們?cè)斐闪舜a執(zhí)行順序不對(duì)的假象

  • 對(duì)主線程,其他線程疤估,異步任務(wù)打個(gè)比方灾常。
  • 我們把每天上班比作主線程,那么某甲今天要出差去做某事情就叫子線程铃拇。本來(lái)他是應(yīng)該和我們一起上班解決事情的钞瀑,現(xiàn)在他出差去做其他事情了,他出差去做某事情我們就可以說(shuō)成是慷荔,他開(kāi)啟一個(gè)新線程去干某事情了雕什。因?yàn)樗霾铍x開(kāi)了,和我們上著班的不能及時(shí)溝通處理問(wèn)題显晶,他與我們的拍子和不在一起了贷岸,所以他做的事情也叫作異步任務(wù)。
  • 如果結(jié)合上面實(shí)例磷雇,我們大家上班解決問(wèn)題為主線程凰盔,稱(chēng)之為團(tuán)隊(duì)工作,甲出差去做某事情為子線程倦春,稱(chēng)之為私人工作。主線程要求子線程把網(wǎng)絡(luò)數(shù)據(jù)取回來(lái)(團(tuán)隊(duì)要求甲出差成果展現(xiàn)出來(lái))落剪,甲說(shuō)睁本,沒(méi)問(wèn)題,我出差回來(lái)就提交成果忠怖。問(wèn)題來(lái)了呢堰,出差是需要時(shí)間的,而這段時(shí)間之內(nèi)凡泣,團(tuán)隊(duì)莫不是就停擺等著甲返回的成果枉疼,當(dāng)然不是!
  • 團(tuán)隊(duì)不可能停擺等著甲的成果鞋拟,同樣骂维,主線程也不可能等著子線程的“成果”,這就是問(wèn)題的所在贺纲。結(jié)合上面實(shí)例航闺,主線程(Android中也稱(chēng)作UI線程)通過(guò)方法getWebData取得網(wǎng)絡(luò)數(shù)據(jù)(模擬),但是子線程執(zhí)行是需要時(shí)間的,主線程在這期間不能一直等著,所以它便繼續(xù)執(zhí)行潦刃,注意:代碼塊
private String getWebData() {
        Log.d("20180621", "在getWebData方法中開(kāi)始時(shí),toastStr: " + toastStr);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000 * 2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                toastStr = "模擬網(wǎng)絡(luò)返回的數(shù)據(jù)";
                Log.d("20180621", "在getWebData方法中修改數(shù)據(jù)后,toastStr: " + toastStr);
            }
        }).start();
        Log.d("20180621", "在getWebData方法中返回前,toastStr: " + toastStr);
        return toastStr;
    }

new ....start():之外的代碼都是在主線程中執(zhí)行的(在兩者之間的就是子線程)侮措,所以當(dāng)我們?cè)谥骶€程調(diào)用getWebData方法,想以此獲取網(wǎng)絡(luò)數(shù)據(jù)時(shí)乖杠,因?yàn)橹骶€程不可能等待子線程分扎,所以其實(shí)執(zhí)行的是在子線程之外的、屬于主線程的代碼胧洒,所以其實(shí)執(zhí)行的操作就是:return toastStr,而toasStr在之前賦值為"execute開(kāi)始",那么

 toastStr = getWebData();

其實(shí)就相當(dāng)于把他它自身賦值給自己畏吓,所以值還是"execute開(kāi)始",這樣略荡,Toast顯示出這個(gè)字符串也就理所當(dāng)然了庵佣。

  • 疑惑倒是解開(kāi)了,那么莫非我們就不能取到網(wǎng)絡(luò)數(shù)據(jù)了汛兜,這自然不可能巴粪。

3 將一個(gè)子線程寫(xiě)在一個(gè)帶返回值方法里,想獲取子線程處理的數(shù)據(jù)在邏輯上就是錯(cuò)的

  • 比如我們前面粥谬,將獲取網(wǎng)絡(luò)數(shù)據(jù)(模擬)的子線程寫(xiě)在方法getWebData中肛根,以期獲取網(wǎng)絡(luò)數(shù)據(jù),進(jìn)而返回與網(wǎng)絡(luò)數(shù)據(jù)相關(guān)的字符串漏策,這是存在邏輯錯(cuò)誤的:因?yàn)榍懊嫖覀冋f(shuō)過(guò)派哲,主線程是不會(huì)等待子線程的,而之所以開(kāi)辟子線程掺喻,就是需要其去做某事情芭届,做事情是需要花費(fèi)時(shí)間的,這個(gè)時(shí)間主線程不會(huì)等感耙。所以如果非要把子線程寫(xiě)在帶返回值的方法里褂乍,是達(dá)不到預(yù)期目的的(等子線程處理好數(shù)據(jù),方法早就返回了即硼,而返回值是沒(méi)有經(jīng)過(guò)子線程處理的(很可能是空之類(lèi)的……))逃片。

4 如何取回子線程中處理的數(shù)據(jù)

  • 通過(guò)前面的分析我們知道,將子線程寫(xiě)在帶返回值的方法里只酥,想返回子線程處理的數(shù)據(jù)不可行褥实,那么可行的方案是:其實(shí)也簡(jiǎn)單當(dāng)子線程處理完數(shù)據(jù),告訴主線程一聲裂允,我這邊OK了损离,你那邊拿去用吧
  • 那么如何告訴主線程子線程O(píng)K了,這個(gè)可以用Handler绝编,Broadcast草冈,EventBus等等,下面我們用Handler做一下簡(jiǎn)單的示例。
public class MainActivity extends AppCompatActivity {
    private String toastStr;

    private MyHandler handler = new MyHandler(this);

    /**
     * Instances of static inner classes do not hold an implicit
     * reference to their outer class.
     */
    private static class MyHandler extends Handler {
        private final WeakReference<MainActivity> mActivity;

        private MyHandler(MainActivity activity) {
            mActivity = new WeakReference<MainActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = mActivity.get();
            if (activity != null) {
                if (msg.what == 1) {
                    Toast.makeText(activity, (String) msg.obj, Toast.LENGTH_LONG).show();
                }
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.bt_click_execute)
                .setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        execute();
                    }
                });
    }

    private void execute() {
        toastStr = "execute開(kāi)始";
        Log.d("20180621", "在execute方法中第一步時(shí)候,toastStr: " + toastStr);
        requestWebData();/*模擬獲取網(wǎng)絡(luò)數(shù)據(jù)等耗時(shí)操作*/
        Log.d("20180621", "在execute方法中第二步時(shí)候,toastStr: " + toastStr);

    }

    private void requestWebData() {
        Log.d("20180621", "在getWebData方法中開(kāi)始時(shí),toastStr: " + toastStr);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000 * 2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                toastStr = "模擬網(wǎng)絡(luò)返回的數(shù)據(jù)";
                Message message = Message.obtain();
                message.what = 1;
                message.obj = toastStr;
                handler.sendMessage(message);

                Log.d("20180621", "在getWebData方法中修改數(shù)據(jù)后,toastStr: " + toastStr);
            }
        }).start();
        Log.d("20180621", "在getWebData方法中返回前,toastStr: " + toastStr);
    }
}
  • 慚愧怎棱,原來(lái)的Handler寫(xiě)法好像有警告哩俭,又度娘了一下它的寫(xiě)法(@^_^@)
  • 簡(jiǎn)單說(shuō)下邏輯:
  1. 與之前相比拳恋,定義了一個(gè)Handler來(lái)處理子線程傳過(guò)來(lái)的數(shù)據(jù)
  2. 在子線程處理好數(shù)據(jù)后凡资,將消息發(fā)給主線程,并將數(shù)據(jù)發(fā)送給主線程
  3. 既然getWedData沒(méi)有實(shí)際用處谬运,那么將返回值改成void類(lèi)型隙赁,并改方法名為:requestWebData,意在請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)(至于怎么拿到梆暖,我不關(guān)心伞访,我只是告訴子線程,去給我拿數(shù)據(jù)(子線程處理好數(shù)據(jù)轰驳,發(fā)送消息給主線程厚掷,那么也就拿到數(shù)據(jù)了))

5 異步任務(wù)請(qǐng)求數(shù)據(jù)的正確姿勢(shì)

  • 正確姿勢(shì)是什么我不大懂,不過(guò)最起碼级解,你應(yīng)該分為三步:
  1. 告訴子線程冒黑,“小子去干活了”,相當(dāng)于上述代碼的requestWebData,其核心就是開(kāi)啟子線程勤哗,執(zhí)行耗時(shí)操作
  2. 當(dāng)子線程活干完了抡爹,要報(bào)告:“老大,活干好了芒划,要看看成果不冬竟?”,上述代碼中的,即向主線程發(fā)送消息民逼,傳遞數(shù)據(jù)
                Message message = Message.obtain();
                message.what = 1;
                message.obj = toastStr;
                handler.sendMessage(message);
  1. 老大檢查工作成果泵殴,并做進(jìn)一步加工,也就是最后數(shù)據(jù)的使用
 public void handleMessage(Message msg) {
            MainActivity activity = mActivity.get();
            if (activity != null) {
                if (msg.what == 1) {
                    Toast.makeText(activity, (String) msg.obj, Toast.LENGTH_LONG).show();
                }
            }
        }
  • over
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缴挖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子焚辅,更是在濱河造成了極大的恐慌映屋,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件同蜻,死亡現(xiàn)場(chǎng)離奇詭異棚点,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)湾蔓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)瘫析,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事贬循∠贪” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵杖虾,是天一觀的道長(zhǎng)烂瘫。 經(jīng)常有香客問(wèn)我,道長(zhǎng)奇适,這世上最難降的妖魔是什么坟比? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮嚷往,結(jié)果婚禮上葛账,老公的妹妹穿的比我還像新娘。我一直安慰自己皮仁,他們只是感情好籍琳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著魂贬,像睡著了一般巩割。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上付燥,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天宣谈,我揣著相機(jī)與錄音,去河邊找鬼键科。 笑死闻丑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的勋颖。 我是一名探鬼主播嗦嗡,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼饭玲!你這毒婦竟也來(lái)了侥祭?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤茄厘,失蹤者是張志新(化名)和其女友劉穎矮冬,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體次哈,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胎署,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了窑滞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琼牧。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恢筝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巨坊,到底是詐尸還是另有隱情撬槽,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布抱究,位于F島的核電站恢氯,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鼓寺。R本人自食惡果不足惜勋拟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望妈候。 院中可真熱鬧敢靡,春花似錦、人聲如沸苦银。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)幔虏。三九已至纺念,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間想括,已是汗流浹背陷谱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瑟蜈,地道東北人烟逊。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像铺根,于是被迫代替她去往敵國(guó)和親宪躯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,373評(píng)論 8 265
  • 第2章 基本語(yǔ)法 2.1 概述 基本句法和變量 語(yǔ)句 JavaScript程序的執(zhí)行單位為行(line)位迂,也就是一...
    悟名先生閱讀 4,148評(píng)論 0 13
  • 生活從來(lái)不是一場(chǎng)苦情戲掂林。
    雪筱莜閱讀 182評(píng)論 0 0
  • 自評(píng):七夕節(jié)快到了驳庭!我應(yīng)應(yīng)景刑顺,之前一直秉承“少即是多”氯窍,盡量少寫(xiě)字的原則,這次忍不住把鵲橋仙寫(xiě)了下來(lái)蹲堂,平時(shí)我只知道...
    簡(jiǎn)單漫生活閱讀 285評(píng)論 0 3
  • 一首詩(shī) 一紙呈上的供狀 等待 何其不安 路人皆可審判 白晝里觀盡日和月 夜色也可以沐浴星光璀璨 我說(shuō)狼讨,天空是日月 ...
    一團(tuán)菌閱讀 237評(píng)論 11 5