Android MVVM Demo實戰(zhàn)解析

參考:

http://www.reibang.com/p/996d76b2317f
http://www.reibang.com/p/fed20fc304b7
文章名稱都懶得改恩商,照搬過來了。

效果圖

image.png

代碼結(jié)構(gòu)

image.png

整體架構(gòu)MVVM,網(wǎng)絡(luò)請求用的retrofit2 + rxjava2研叫,數(shù)據(jù)綁定使用的 databinding嚷炉。
1.View層就是展示數(shù)據(jù)的申屹,以及接收到用戶的操作傳遞給viewModel層哗讥,通過dataBinding實現(xiàn)數(shù)據(jù)與view的單向綁定或雙向綁定
2.Model層最重要的作用就是獲取數(shù)據(jù)了胞枕,當(dāng)然不止于此决乎,model層將結(jié)果通過接口的形式傳遞給viewModel層
3.ViewModel 層通過調(diào)用model層獲取數(shù)據(jù)派桩,以及業(yè)務(wù)邏輯的處理铆惑。

1.LoginActivity 的布局

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

    </data>

    <LinearLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/rover_color_background"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dp"
            android:layout_gravity="center_horizontal"
            android:background="@mipmap/login_title" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp"
            android:background="@drawable/background_white_shape"
            android:layout_marginTop="30dp"
            android:orientation="vertical">

            <RelativeLayout
                android:id="@+id/relay1"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:layout_marginTop="20dp"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:background="@drawable/background_grey_shape_stroke">

                <ImageView
                    android:id="@+id/img1"
                    android:layout_width="22dp"
                    android:layout_height="22dp"
                    android:layout_centerVertical="true"
                    android:layout_marginEnd="10dp"
                    android:layout_marginLeft="10dp"
                    android:layout_marginRight="10dp"
                    android:layout_marginStart="10dp"
                    android:src="@mipmap/login_user" />

                <View
                    android:layout_width="0.5dp"
                    android:layout_height="match_parent"
                    android:layout_toEndOf="@+id/img1"
                    android:layout_toRightOf="@+id/img1"
                    android:layout_marginTop="5dp"
                    android:layout_marginBottom="5dp"
                    android:background="@color/ranger_color_blue"
                    android:id="@+id/view1" />

                <EditText
                    android:id="@+id/name_edit"
                    style="@style/Ranger_MSize_GColor"
                    android:layout_width="match_parent"
                    android:layout_height="40dp"
                    android:layout_centerVertical="true"
                    android:layout_gravity="center_vertical"
                    android:layout_marginEnd="10dp"
                    android:layout_marginRight="10dp"
                    android:layout_toEndOf="@+id/view1"
                    android:layout_toRightOf="@+id/view1"
                    android:background="@drawable/rover_white_shape"
                    android:gravity="center_vertical"
                    android:hint="請輸入手機號"
                    android:maxLength="11" />

                <ImageView
                    android:id="@+id/delete1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentRight="true"
                    android:layout_centerVertical="true"
                    android:layout_marginEnd="18dp"
                    android:layout_marginRight="18dp"
                    android:background="@mipmap/input_close"
                    android:padding="10dp"
                    android:visibility="gone" />
            </RelativeLayout>

            <RelativeLayout
                android:id="@+id/relay2"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:layout_marginTop="20dp"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="20dp"
                android:background="@drawable/background_grey_shape_stroke">

                <ImageView
                    android:id="@+id/img2"
                    android:layout_width="22dp"
                    android:layout_height="22dp"
                    android:layout_centerVertical="true"
                    android:layout_marginEnd="10dp"
                    android:layout_marginLeft="10dp"
                    android:layout_marginRight="10dp"
                    android:layout_marginStart="10dp"
                    android:src="@mipmap/login_pwd" />

                <View
                    android:layout_width="0.5dp"
                    android:layout_height="match_parent"
                    android:layout_toEndOf="@+id/img2"
                    android:layout_toRightOf="@+id/img2"
                    android:layout_marginTop="5dp"
                    android:layout_marginBottom="5dp"
                    android:background="@color/ranger_color_blue"
                    android:id="@+id/view2" />

                <EditText
                    android:id="@+id/pass_edit"
                    style="@style/Ranger_MSize_GColor"
                    android:layout_width="match_parent"
                    android:layout_height="40dp"
                    android:layout_centerVertical="true"
                    android:layout_gravity="center_vertical"
                    android:layout_marginEnd="10dp"
                    android:layout_marginRight="10dp"
                    android:layout_toEndOf="@+id/view2"
                    android:layout_toRightOf="@+id/view2"
                    android:background="@drawable/rover_white_shape"
                    android:gravity="center_vertical"
                    android:hint="請輸入密碼"
                    android:inputType="textPassword" />

                <ImageView
                    android:id="@+id/delete2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentRight="true"
                    android:layout_centerVertical="true"
                    android:layout_marginEnd="18dp"
                    android:layout_marginRight="18dp"
                    android:background="@mipmap/input_close"
                    android:padding="10dp"
                    android:visibility="gone" />
            </RelativeLayout>
        </LinearLayout>

        <Button
            android:id="@+id/login_button"
            style="@style/Ranger_BSize_WColor"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp"
            android:layout_marginTop="35dp"
            android:background="@drawable/background_blue_shape"
            android:text="登錄" />

    </LinearLayout>
</layout>

2.LoginActivity

public class LoginActivity extends AppCompatActivity {

    LoginActivityBinding binding;
    LoginViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = DataBindingUtil.setContentView(this,R.layout.login_activity);
        viewModel = new LoginViewModel();

        binding.loginButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                login();
            }
        });

    }

    private void login() {

        if (TextUtils.isEmpty(binding.nameEdit.getEditableText().toString())) {
            Toast.makeText(getApplication(), "請輸入賬號脑慧!", Toast.LENGTH_SHORT).show();
            return;
        }

        if (TextUtils.isEmpty(binding.passEdit.getEditableText().toString())) {
            Toast.makeText(getApplication(), "請輸入密碼闷袒!", Toast.LENGTH_SHORT).show();
            return;
        }

        viewModel.login(binding.nameEdit.getEditableText().toString(),binding.passEdit.getEditableText().toString());
    }

3.LoginViewModel

public class LoginViewModel extends ViewModel {

    private static final String TAG = "LoginViewModel";
    private LoginModel model;
    public LoginViewModel() {
        model = new LoginModel();
    }

    public void login(String name, String pass) {
        model.appLogin(name, pass, new INetWorkCallback<LoginResult>() {
            @Override
            public void onCallApiSuccess(LoginResult loginResult) {

                android.util.Log.e(TAG,"---onCallApiSuccess---");
            }

            @Override
            public void onCallApiFailure(Throwable throwable) {
                android.util.Log.e(TAG,"---onCallApiFailure---");
            }

            @Override
            public void onCompleted() {
                android.util.Log.e(TAG,"---onCompleted---");
            }
        });
    }
}

4.RetrofitService api地址

public interface RetrofitService {

    /**
     * 地址是測試地址囊骤,外網(wǎng)ping不通
     */
    String HOST = "http://10.6.152.9:8091/";

    /**
     * 登錄</p>
     * 作者:Bob</p>
     * 日期:2020-03-07</p>
     *
     * @param body {"loginName":"111","loginPass":"123456"}
     * @return 是否登錄成功
     */
    @Headers({"Content-Type: application/json", "Accept: application/json"})
    @POST("user/login")
    Observable<LoginResult> appLogin(@Body RequestBody body);

}

5.LoginModel

public class LoginModel {

    public void appLogin(final String loginName, final String pass, final INetWorkCallback<LoginResult> callback) {

        final RequestBodyEntity.Login loginRequest = new RequestBodyEntity.Login();
        loginRequest.loginName = loginName;
        loginRequest.loginPass = pass;
        final Gson gson = new Gson();
        String gsonStr = gson.toJson(loginRequest);
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), gsonStr);

        RetrofitUtil.getInstance().getRetrofitService()
                .appLogin(body)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new DisposableObserver<LoginResult>() {
                    @Override
                    public void onNext(LoginResult loginResult) {
                        callback.onCallApiSuccess(loginResult);
                    }

                    @Override
                    public void onError(Throwable e) {
                        callback.onCallApiFailure(e);
                    }

                    @Override
                    public void onComplete() {
                        callback.onCompleted();
                    }
                });
    }
}

GitHub地址

https://github.com/Ityang/mvvm-demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末滑蚯,一起剝皮案震驚了整個濱河市抵栈,隨后出現(xiàn)的幾起案子古劲,更是在濱河造成了極大的恐慌产艾,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骚露,死亡現(xiàn)場離奇詭異棘幸,居然都是意外死亡误续,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門育瓜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來躏仇,“玉大人腺办,你說我怎么就攤上這事∈槠蓿” “怎么了躲履?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長聊闯。 經(jīng)常有香客問我崇呵,道長,這世上最難降的妖魔是什么馅袁? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮荒辕,結(jié)果婚禮上汗销,老公的妹妹穿的比我還像新娘。我一直安慰自己抵窒,他們只是感情好弛针,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著李皇,像睡著了一般削茁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掉房,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天瘾杭,我揣著相機與錄音贤笆,去河邊找鬼。 笑死钝吮,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的巧鸭。 我是一名探鬼主播纲仍,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼乡革,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了视粮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤坚踩,失蹤者是張志新(化名)和其女友劉穎卧晓,沒想到半個月后郁稍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年俊性,在試婚紗的時候發(fā)現(xiàn)自己被綠了定页。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片典徊。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖屎飘,靈堂內(nèi)的尸體忽然破棺而出褂萧,到底是詐尸還是另有隱情唱凯,我是刑警寧澤卷雕,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布浸间,位于F島的核電站,受9級特大地震影響梅惯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜葫哗,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧擎浴,春花似錦仿吞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春桂肌,著一層夾襖步出監(jiān)牢的瞬間谭跨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留苗缩,地道東北人彼乌。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓稚铣,卻偏偏與公主長得像抬伺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355