Android自我提升之一 從架構(gòu)的角度看接口,萬(wàn)能接口的實(shí)現(xiàn)原理

目的

在Android開(kāi)發(fā)階段侮措,組件之間的通信是不可避免的懈叹,組件之間的通信方式也會(huì)有很多,它們各有優(yōu)劣分扎,今天我們主要了解的是澄成,一種萬(wàn)能接口的方式來(lái)實(shí)現(xiàn),一個(gè)簡(jiǎn)單而優(yōu)雅的通訊方式,用少量的代碼墨状,來(lái)完成組件間的通信解耦卫漫。

常用的組件間的通訊方式

常用的組件間的通訊方式

其中最常用就前三種,其中:

  1. Intent 只能界面逐級(jí)傳輸
  2. Handler 存在內(nèi)存泄漏肾砂, 在activity被銷毀時(shí)列赎,由于隊(duì)列還有消息,Handler還存在镐确,造成存在泄漏粥谬。
  3. interface 書寫反鎖,耦合性強(qiáng)辫塌,并且不能切換線程

當(dāng)然也有一些常用的三方的框架,如EventBus,XBus等等派哲,但是一個(gè)優(yōu)秀的第三方框架百分之八十的功能我們都不會(huì)使用臼氨,所以當(dāng)這些都沒(méi)有的時(shí)候,我們?nèi)绾胃觾?yōu)雅的實(shí)現(xiàn)大量組件間的通信了芭届?

“數(shù)據(jù)源” -- 思路

“數(shù)據(jù)源” -- 思路

核心思想

  1. 通過(guò)數(shù)據(jù)源或方法棧中轉(zhuǎn)储矩,組件只管接受或發(fā)送
  2. 將方法進(jìn)行封裝
  3. 將方法提取出來(lái)進(jìn)行管理

具體實(shí)踐

1.方法的封裝

四種類型:

方法封裝的四種類型

方法封裝的父類

package com.fly.newstart.neinterface;

/**
 * <pre>
 *           .----.
 *        _.'__    `.
 *    .--(Q)(OK)---/$\
 *  .' @          /$$$\
 *  :         ,   $$$$$
 *   `-..__.-' _.-\$/
 *         `;_:    `"'
 *       .'"""""`.
 *      /,  FLY  ,\
 *     //         \\
 *     `-._______.-'
 *     ___`. | .'___
 *    (______|______)
 * </pre>
 * 包    名 : com.fly.newstart.neinterface
 * 作    者 : FLY
 * 創(chuàng)建時(shí)間 : 2019/4/23
 * 描述: 方法封裝管理的父類
 */
public class Function {

    //方法名稱
    public String functionName;

    public Function(String functionName) {
        this.functionName = functionName;
    }
}

無(wú)參數(shù)無(wú)返回值類型方法

package com.fly.newstart.neinterface;

/**
 * <pre>
 *           .----.
 *        _.'__    `.
 *    .--(Q)(OK)---/$\
 *  .' @          /$$$\
 *  :         ,   $$$$$
 *   `-..__.-' _.-\$/
 *         `;_:    `"'
 *       .'"""""`.
 *      /,  FLY  ,\
 *     //         \\
 *     `-._______.-'
 *     ___`. | .'___
 *    (______|______)
 * </pre>
 * 包    名 : com.fly.newstart.neinterface
 * 作    者 : FLY
 * 創(chuàng)建時(shí)間 : 2019/4/23
 * 描述: 無(wú)參數(shù) 無(wú)返回 類型 方法
 */
public abstract class FunctionNoParamNoResult extends Function{

    public FunctionNoParamNoResult(String functionName) {
        super(functionName);
    }

     public abstract void function();
}

無(wú)參數(shù)有返回值類型方法

package com.fly.newstart.neinterface;

/**
 * <pre>
 *           .----.
 *        _.'__    `.
 *    .--(Q)(OK)---/$\
 *  .' @          /$$$\
 *  :         ,   $$$$$
 *   `-..__.-' _.-\$/
 *         `;_:    `"'
 *       .'"""""`.
 *      /,  FLY  ,\
 *     //         \\
 *     `-._______.-'
 *     ___`. | .'___
 *    (______|______)
 * </pre>
 * 包    名 : com.fly.newstart.neinterface
 * 作    者 : FLY
 * 創(chuàng)建時(shí)間 : 2019/4/23
 * 描述: 無(wú)參數(shù) 有返回值 類型 方法
 */
public abstract class FunctionNoParamHasResult<T> extends Function{

    public FunctionNoParamHasResult(String functionName) {
        super(functionName);
    }

     public abstract T function();
}

有參數(shù)無(wú)返回值類型方法

package com.fly.newstart.neinterface;

/**
 * <pre>
 *           .----.
 *        _.'__    `.
 *    .--(Q)(OK)---/$\
 *  .' @          /$$$\
 *  :         ,   $$$$$
 *   `-..__.-' _.-\$/
 *         `;_:    `"'
 *       .'"""""`.
 *      /,  FLY  ,\
 *     //         \\
 *     `-._______.-'
 *     ___`. | .'___
 *    (______|______)
 * </pre>
 * 包    名 : com.fly.newstart.neinterface
 * 作    者 : FLY
 * 創(chuàng)建時(shí)間 : 2019/4/23
 * 描述: 有參數(shù) 無(wú)返回值 類型 方法
 */
public abstract class FunctionHasParamNoResult<P> extends Function{

    public FunctionHasParamNoResult(String functionName) {
        super(functionName);
    }

     public abstract void function(P p);
}


有參數(shù)有返回值類型方法

package com.fly.newstart.neinterface;

/**
 * <pre>
 *           .----.
 *        _.'__    `.
 *    .--(Q)(OK)---/$\
 *  .' @          /$$$\
 *  :         ,   $$$$$
 *   `-..__.-' _.-\$/
 *         `;_:    `"'
 *       .'"""""`.
 *      /,  FLY  ,\
 *     //         \\
 *     `-._______.-'
 *     ___`. | .'___
 *    (______|______)
 * </pre>
 * 包    名 : com.fly.newstart.neinterface
 * 作    者 : FLY
 * 創(chuàng)建時(shí)間 : 2019/4/23
 * 描述: 有參數(shù) 有返回值 類型 方法
 */
public abstract class FunctionHasParamHasResult<T,P> extends Function{

    public FunctionHasParamHasResult(String functionName) {
        super(functionName);
    }

     public abstract T function(P p);
}

2.方法管理類構(gòu)建

方法管理類

package com.fly.newstart.neinterface;

import android.text.TextUtils;

import com.fly.newstart.utils.LogUtil;

import java.util.HashMap;
import java.util.Map;

/**
 * <pre>
 *           .----.
 *        _.'__    `.
 *    .--(Q)(OK)---/$\
 *  .' @          /$$$\
 *  :         ,   $$$$$
 *   `-..__.-' _.-\$/
 *         `;_:    `"'
 *       .'"""""`.
 *      /,  FLY  ,\
 *     //         \\
 *     `-._______.-'
 *     ___`. | .'___
 *    (______|______)
 * </pre>
 * 包    名 : com.fly.newstart.neinterface
 * 作    者 : FLY
 * 創(chuàng)建時(shí)間 : 2019/4/23
 * 描述: 方法管理類
 */
public class FunctionManager {

    private static FunctionManager instance;
    private Map<String, FunctionNoParamNoResult> mFunctionNoParamNoResultMap;
    private Map<String, FunctionNoParamHasResult> mFunctionNoParamHasResultMap;
    private Map<String, FunctionHasParamNoResult> mFunctionHasParamNoResultMap;
    private Map<String, FunctionHasParamHasResult> mFunctionHasParamHasResultMap;

    public FunctionManager() {
        mFunctionNoParamNoResultMap = new HashMap<>();
        mFunctionNoParamHasResultMap = new HashMap<>();
        mFunctionHasParamNoResultMap = new HashMap<>();
        mFunctionHasParamHasResultMap = new HashMap<>();
    }

    public static FunctionManager getInstance() {
        if (instance == null) {
            instance = new FunctionManager();
        }
        return instance;
    }

    /**
     * 添加無(wú)參數(shù)無(wú)返回值方法
     *
     * @param function
     */
    public void addFunction(FunctionNoParamNoResult function) {
        if (function != null) {
            this.mFunctionNoParamNoResultMap.put(function.functionName, function);
        } else LogUtil.print("FunctionNoParamNoResult is Null");
    }

    /**
     * 調(diào)用無(wú)參數(shù)無(wú)返回值方法
     *
     * @param functionName
     */
    public void invokeFunction(String functionName) {
        if (TextUtils.isEmpty(functionName)) {
            return;
        }

        if (mFunctionNoParamNoResultMap != null) {
            FunctionNoParamNoResult function = mFunctionNoParamNoResultMap.get(functionName);
            if (function != null) {
                function.function();
            } else LogUtil.print("FunctionNoParamNoResult not created");
        }
    }

    /**
     * 添加無(wú)參數(shù)有返回值方法
     *
     * @param function
     */
    public void addFunction(FunctionNoParamHasResult function) {
        if (function != null) {
            this.mFunctionNoParamHasResultMap.put(function.functionName, function);
        } else LogUtil.print("FunctionNoParamNoResult is Null");
    }

    /**
     * 調(diào)用無(wú)參數(shù)有返回值方法
     *
     * @param functionName
     * @param t            返回泛型
     * @param <T>          返回泛型
     * @return
     */
    public <T> T invokeFunction(String functionName, Class<T> t) {
        if (!TextUtils.isEmpty(functionName)) {
            if (mFunctionNoParamHasResultMap != null) {
                FunctionNoParamHasResult function = mFunctionNoParamHasResultMap.get(functionName);
                if (function != null) {
                    if (t != null) {
                        return t.cast(function.function());
                    } else LogUtil.print("Class T is null");
                } else LogUtil.print("FunctionNoParamHasResult not created");
            }
        }
        return null;
    }


    /**
     * 添加有參數(shù)無(wú)返回值方法
     *
     * @param function
     */
    public void addFunction(FunctionHasParamNoResult function) {
        if (function != null) {
            this.mFunctionHasParamNoResultMap.put(function.functionName, function);
        } else LogUtil.print("FunctionNoParamNoResult is Null");
    }

    /**
     * 調(diào)用有參數(shù)無(wú)返回值方法
     *
     * @param functionName
     * @param param
     * @param <P>
     */
    public <P> void invokeFunction(String functionName, P param) {
        if (TextUtils.isEmpty(functionName)) {
            return;
        }
        if (mFunctionHasParamNoResultMap != null) {
            FunctionHasParamNoResult function = mFunctionHasParamNoResultMap.get(functionName);
            if (function != null) {
                function.function(param);
            } else LogUtil.print("FunctionNoParamHasResult not created");
        }
    }


    /**
     * 添加有參數(shù)有返回值方法
     *
     * @param function
     */
    public void addFunction(FunctionHasParamHasResult function) {
        if (function != null) {
            this.mFunctionHasParamHasResultMap.put(function.functionName, function);
        } else LogUtil.print("FunctionNoParamNoResult is Null");
    }

    /**
     * 調(diào)用有參數(shù)有返回值方法
     *
     * @param functionName
     * @param param
     * @param t
     * @param <T>
     * @param <P>
     * @return
     */
    public <T, P> T invokeFunction(String functionName, P param, Class<T> t) {
        if (!TextUtils.isEmpty(functionName)) {
            if (mFunctionHasParamHasResultMap != null) {
                FunctionHasParamHasResult function = mFunctionHasParamHasResultMap.get(functionName);
                if (function != null) {
                    if (t != null) {
                        return t.cast(function.function(param));
                    } else LogUtil.print("Class T is null");
                } else LogUtil.print("FunctionNoParamHasResult not created");
            }
        }
        return null;
    }


    public void removeFunctionNoParamNoResult(String functionName) {
        mFunctionNoParamNoResultMap.remove(functionName);
    }

    public void removeFunctionNoParamHasResult(String functionName) {
        mFunctionNoParamHasResultMap.remove(functionName);
    }

    public void removeFunctionHasParamNoResult(String functionName) {
        mFunctionHasParamNoResultMap.remove(functionName);
    }

    public void removeFunctionHasParamHasResult(String functionName) {
        mFunctionHasParamHasResultMap.remove(functionName);
    }

    public void removeAll(String functionName) {
        mFunctionNoParamNoResultMap.remove(functionName);
        mFunctionNoParamHasResultMap.remove(functionName);
        mFunctionHasParamNoResultMap.remove(functionName);
        mFunctionHasParamHasResultMap.remove(functionName);
    }

    public void removeAll() {
        mFunctionNoParamNoResultMap.clear();
        mFunctionNoParamHasResultMap.clear();
        mFunctionHasParamNoResultMap.clear();
        mFunctionHasParamHasResultMap.clear();
    }

}


3.組件通信測(cè)試

組件A

代碼

package com.fly.newstart.neinterface.text;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.fly.newstart.R;
import com.fly.newstart.common.base.BaseActivity;
import com.fly.newstart.neinterface.FunctionHasParamHasResult;
import com.fly.newstart.neinterface.FunctionHasParamNoResult;
import com.fly.newstart.neinterface.FunctionManager;
import com.fly.newstart.neinterface.FunctionNoParamHasResult;
import com.fly.newstart.neinterface.FunctionNoParamNoResult;

public class AActivity extends BaseActivity {

    public static final String FUNCTION_1 = "functon01";
    public static final String FUNCTION_2 = "functon02";
    public static final String FUNCTION_3 = "functon03";
    public static final String FUNCTION_4 = "functon04";

    private TextView mTvShow;
    private Button mBtnStartB;

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

        mTvShow = findViewById(R.id.tvShow);
        mBtnStartB = findViewById(R.id.btnStartB);

        mBtnStartB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AActivity.this.startActivity(new Intent(AActivity.this, BActivity.class));
            }
        });

        //注冊(cè)方法1-無(wú)參數(shù)無(wú)返回值類型方法

        FunctionManager.getInstance().addFunction(new FunctionNoParamNoResult(FUNCTION_1) {
            @Override
            public void function() {
                mTvShow.setText("調(diào)用了方法1,無(wú)參數(shù)無(wú)返回值類型方法");
            }
        });

        FunctionManager.getInstance().addFunction(new FunctionNoParamHasResult<String>(FUNCTION_2) {
            @Override
            public String function() {
                return "調(diào)用了方法2,無(wú)參數(shù)有返回值類型方法";
            }
        });

        FunctionManager.getInstance().addFunction(new FunctionHasParamNoResult<String>(FUNCTION_3) {
            @Override
            public void function(String s) {
                mTvShow.setText(s);
            }
        });

        FunctionManager.getInstance().addFunction(new FunctionHasParamHasResult<String, String>(FUNCTION_4) {
            @Override
            public String function(String s) {
                return s;
            }
        });

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        FunctionManager.getInstance().removeFunctionNoParamNoResult(FUNCTION_1);
        FunctionManager.getInstance().removeFunctionNoParamHasResult(FUNCTION_2);
        FunctionManager.getInstance().removeFunctionHasParamNoResult(FUNCTION_3);
        FunctionManager.getInstance().removeFunctionHasParamHasResult(FUNCTION_4);
    }
}

XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context="com.fly.newstart.neinterface.text.AActivity">

    <TextView
        android:id="@+id/tvShow"
        style="@style/WrapWrap"
        android:textSize="@dimen/dp_16" />

    <Button
        android:id="@+id/btnStartB"
        style="@style/WrapWrap"
        android:layout_marginTop="@dimen/dp_10"
        android:text="啟動(dòng)B組件"/>

</LinearLayout>

組件B

代碼

package com.fly.newstart.neinterface.text;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.fly.newstart.R;
import com.fly.newstart.common.base.BaseActivity;
import com.fly.newstart.neinterface.FunctionManager;

public class BActivity extends BaseActivity {

    private Button mBtnFuncton01;
    private Button mBtnFuncton02;
    private Button mBtnFuncton03;
    private Button mBtnFuncton04;
    private Button mBtnCloseB;
    private TextView mTvShow;

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


        mBtnFuncton01 = findViewById(R.id.btnFuncton01);
        mBtnFuncton02 = findViewById(R.id.btnFuncton02);
        mBtnFuncton03 = findViewById(R.id.btnFuncton03);
        mBtnFuncton04 = findViewById(R.id.btnFuncton04);
        mBtnCloseB = findViewById(R.id.btnCloseB);
        mTvShow = findViewById(R.id.tvShow);


        mBtnFuncton01.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FunctionManager.getInstance().invokeFunction(AActivity.FUNCTION_1);
            }
        });


        mBtnFuncton02.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mTvShow.setText(FunctionManager.getInstance().invokeFunction(AActivity.FUNCTION_2, String.class));
            }
        });

        mBtnFuncton03.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FunctionManager.getInstance().invokeFunction(AActivity.FUNCTION_3, "調(diào)用了方法3,有參數(shù)無(wú)返回值類型方法");
            }
        });

        mBtnFuncton04.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mTvShow.setText(FunctionManager.getInstance().invokeFunction(AActivity.FUNCTION_4, "調(diào)用了方法4,有參數(shù)有返回值類型方法", String.class));
            }
        });

        mBtnCloseB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });

    }
}

XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    style="@style/MatchMatch"
    android:gravity="center"
    android:orientation="vertical"
    tools:context="com.fly.newstart.neinterface.text.BActivity">

    <Button
        android:id="@+id/btnFuncton01"
        style="@style/WrapWrap"
        android:text="調(diào)用方法1" />

    <Button
        android:id="@+id/btnFuncton02"
        style="@style/WrapWrap"
        android:text="調(diào)用方法2" />

    <Button
        android:id="@+id/btnFuncton03"
        style="@style/WrapWrap"
        android:text="調(diào)用方法3" />


    <Button
        android:id="@+id/btnFuncton04"
        style="@style/WrapWrap"
        android:text="調(diào)用方法4" />

    <Button
        android:id="@+id/btnCloseB"
        style="@style/WrapWrap"
        android:text="關(guān)閉B" />

    <TextView
        android:id="@+id/tvShow"
        style="@style/WrapWrap" />

</LinearLayout>

小結(jié)

  1. 代碼簡(jiǎn)潔,主要是提供一個(gè)思路褂乍,還有很多可以完善的地方
  2. EventBus的核心與我們當(dāng)前一樣:將方法提取出來(lái)管理
  3. 只是EventBus運(yùn)用反射機(jī)制與更加完善的調(diào)用獲取方式
  4. 我們只要是去理解整個(gè)實(shí)現(xiàn)的過(guò)程和思維方式
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末持隧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子逃片,更是在濱河造成了極大的恐慌屡拨,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件褥实,死亡現(xiàn)場(chǎng)離奇詭異呀狼,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)损离,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門哥艇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人僻澎,你說(shuō)我怎么就攤上這事貌踏。” “怎么了窟勃?”我有些...
    開(kāi)封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵祖乳,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我拳恋,道長(zhǎng)凡资,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮隙赁,結(jié)果婚禮上垦藏,老公的妹妹穿的比我還像新娘。我一直安慰自己伞访,他們只是感情好掂骏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著厚掷,像睡著了一般弟灼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冒黑,一...
    開(kāi)封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天田绑,我揣著相機(jī)與錄音,去河邊找鬼抡爹。 笑死掩驱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的冬竟。 我是一名探鬼主播欧穴,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼泵殴!你這毒婦竟也來(lái)了涮帘?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤笑诅,失蹤者是張志新(化名)和其女友劉穎调缨,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體苟鸯,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡同蜻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了早处。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片湾蔓。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖砌梆,靈堂內(nèi)的尸體忽然破棺而出默责,到底是詐尸還是另有隱情,我是刑警寧澤咸包,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布桃序,位于F島的核電站,受9級(jí)特大地震影響烂瘫,放射性物質(zhì)發(fā)生泄漏媒熊。R本人自食惡果不足惜奇适,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芦鳍。 院中可真熱鬧嚷往,春花似錦、人聲如沸柠衅。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)菲宴。三九已至贷祈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間喝峦,已是汗流浹背势誊。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谣蠢,地道東北人键科。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像漩怎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嗦嗡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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

  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 10,993評(píng)論 6 13
  • 一勋锤、簡(jiǎn)歷準(zhǔn)備 1、個(gè)人技能 (1)自定義控件侥祭、UI設(shè)計(jì)叁执、常用動(dòng)畫特效 自定義控件 ①為什么要自定義控件? Andr...
    lucas777閱讀 5,213評(píng)論 2 54
  • 1. 文章摘要 【本文目標(biāo)】了解ETH生態(tài)下DAPP去中心化應(yīng)用程序的框架和交互流程矮冬,了解WEB3.JS的作用和接...
    筆名輝哥閱讀 6,044評(píng)論 0 49
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,105評(píng)論 1 32
  • 捧一盆綠意谈宛,聽(tīng)著杰倫的音樂(lè),回憶慢慢燃起胎署,那是十七八歲的盛夏吆录,毒烈的太陽(yáng)照耀著大地,我回家的路上琼牧,耳朵塞...
    LUDASEE1123閱讀 219評(píng)論 0 1