1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

インターフェースとDataBindingを使ってログインする

Posted at

はじめに

前回作成した 【Android】DataBindingを使ってログインするのコードを振り返ってみて、
handlersではなくインターフェースを使った実装もあるとわかったので記録しておく。

やりたいこと

  • handlersを使わずに実装したい
  • OnClickListenerは使いたくない(ActivityではなるべくViewを表示させる処理だけに留めたいため)

    →ボタンクリック後の処理(画面遷移させる処理)をViewModelで実行したい
該当箇所(抜粋)
public class LoginActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    // (省略)
        // xmlのhandlersにLoginActivityのonLoginClick()を紐付ける
        binding.setHandlers(this);
    }

    // buttonをクリックしたときのイベント処理
    @Override
    public void onLoginClick(View view) {
        if (viewModel.isValidInputValue()) {
            Intent intent = new Intent(LoginActivity.this, MainActivity.class);
            startActivity(intent);
            finish();
        } else {
            binding.clickText.setText("6文字以上入力してください");
        }
    }
}

【悩んだこと】
ViewModel内でActivityを呼び出すのはMVVMに反してしまう。
どうやってViewModelで画面遷移させる処理を呼び出せば良いんだろう?

【導き出したこと】
インターフェースを挟み、あえて曖昧にしたviewを使う。

抜粋コード

インターフェースを定義

LoginView.java
public interface LoginView {
    void moveToMainView();
}

ViewModelで遷移する処理を実行

インターフェースを介してViewModel内で擬似的にviewをセットする

public class UserViewModel extends BaseObservable {

  private LoginView view

  // (省略)

  // Activityのviewを紐付けさせるために使う
  public void setView(LoginView view) {
    this.view = view
  }

  public void validateLogin() {
    if (バリデーション) {
      view.moveToMainView();
    } else {
      // エラー処理  
    }
  }
}

インターフェースを実装

LoginActivity.java
public class LoginActivity extends AppCompatActivity implements LoginView {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // (省略)

        UserViewModel viewModel = new UserViewModel();
        // ここでViewModelにActivityのView(this)を渡す
        viewModel.setView(this);
    }

    // LoginViewのメソッドをオーバーライド
    @Override
    public void moveToMainView() {
        Intent intent = new Intent(LoginActivity.this, MainActivity.class);
        startActivity(intent);
        finish();
    }
}

ボタンクリック後に呼び出す処理を指定する

レイアウト内にて指定

<Button
  android:onClick="@{(v) -> viewModel.validateLogin()}" />        

全文コード

Interface

LoginView.java
public interface LoginView {
    void moveToMainView();
}

ViewModel

UserViewModel.java
public class UserViewModel extends BaseObservable {
    private String email;
    private String password;
    private String clickText = "";
    private LoginView view;

    @Bindable public String getEmail() {
        return email;
    }

    @Bindable public String getPassword() { return password; }
    
    @Bindable public String getClickText() {
        return clickText;
    }

    public void setEmail(String email) {
        this.email = email;
        notifyPropertyChanged(BR.buttonEnable);
    }

    public void setPassword(String password) {
        this.password = password;
        notifyPropertyChanged(BR.buttonEnable);
    }

    public void setView(LoginView view) {
        this.view = view;
    }
    
    @Bindable public boolean isButtonEnable() {
        return !TextUtils.isEmpty(email) && !TextUtils.isEmpty(password);
    }

    public void validateLogin() {
        if (email.length() >= 6 && password.length() >= 6) {
            view.moveToMainView();
        } else {
            clickText = "6文字以上入力してください";
            notifyPropertyChanged(BR.clickText);
        }
    }
}

Activity

LoginActivity.java
public class LoginActivity extends AppCompatActivity implements LoginView {

    ActivityLoginBinding binding;

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

        binding = DataBindingUtil.setContentView(this, R.layout.activity_login);

        UserViewModel viewModel = new UserViewModel();
        // ここでViewModelにActivityのView(this)を渡す
        viewModel.setView(this);
        binding.setViewModel(viewModel);
    }

    @Override
    public void moveToMainView() {
        Intent intent = new Intent(LoginActivity.this, MainActivity.class);
        startActivity(intent);
        finish();
    }
}

レイアウト

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

    <data>
        <variable
            name="viewModel"
            type="com.example.loginapp.UserViewModel" />
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/clickText"
            android:layout_width="320dp"
            android:layout_height="wrap_content"
            android:text="@{viewModel.clickText}" />


        <EditText
            android:id="@+id/mail_form"
            android:layout_width="320dp"
            android:layout_height="wrap_content"
            android:imeOptions="actionDone"
            android:inputType="textEmailAddress"
            android:text="@={viewModel.email}"
         />

        <EditText
            android:id="@+id/pass_form"
            android:layout_width="320dp"
            android:layout_height="wrap_content"
            android:imeOptions="actionDone"
            android:inputType="textPassword"
            android:text="@={viewModel.password}"
           />

        <Button
            android:id="@+id/login"
            android:layout_width="320dp"
            android:layout_height="wrap_content"
            android:text="ログイン"
            android:enabled="@{viewModel.buttonEnable}"
            android:onClick="@{(v) -> viewModel.validateLogin()}" />

    </LinearLayout>
</layout>

最後に

「ViewModelからLiveData、RxにてActivityへ通知」までが完成形っぽいので早くできるようになりたい。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?