今天我要把前幾天所學的功能實作成一個簡單的接收API專案,這邊以FakeAPI的資料來接取。
大致上的功能是判斷輸入的帳號是否正確接著拿取到資料,並且是以MVP架構下去撰寫。
<androidx.constraintlayout.widget.Guideline
android:id="@+id/GLPersent01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.1"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/GLPersentvertcal01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.1"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/GLPersentvertcal09"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.9"/>
<TextView
android:id="@+id/Account"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="帳號:"
android:textAlignment="center"
android:textSize="25dp"
app:layout_constraintTop_toTopOf="@+id/GLPersent01"
app:layout_constraintStart_toStartOf="@id/GLPersentvertcal01"/>
<EditText
android:id="@+id/ETaccount"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="請輸入帳號"
app:layout_constraintTop_toTopOf="@id/GLPersent01"
app:layout_constraintStart_toEndOf="@id/Account"
app:layout_constraintEnd_toEndOf="@id/GLPersentvertcal09"/>
<TextView
android:id="@+id/password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="密碼:"
android:textAlignment="center"
android:textSize="25dp"
app:layout_constraintTop_toBottomOf="@id/Account"
app:layout_constraintStart_toStartOf="@id/GLPersentvertcal01"/>
<EditText
android:id="@+id/ETpassword"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="請輸入密碼"
app:layout_constraintTop_toBottomOf="@id/Account"
app:layout_constraintStart_toEndOf="@id/password"
app:layout_constraintEnd_toEndOf="@id/GLPersentvertcal09"/>
<Button
android:id="@+id/EnterButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="確定"
app:layout_constraintTop_toBottomOf="@id/password"
app:layout_constraintStart_toStartOf="@id/GLPersentvertcal01"
app:layout_constraintEnd_toEndOf="@id/GLPersentvertcal09"
android:layout_marginTop="10dp"
tools:ignore="MissingConstraints" />
<TextView
android:id="@+id/showStatus"
android:layout_width="0dp"
android:layout_height="0dp"
android:hint="結果顯示區"
android:textAlignment="center"
android:textSize="18dp"
android:background="@color/teal_200"
app:layout_constraintTop_toBottomOf="@id/EnterButton"
app:layout_constraintStart_toStartOf="@id/GLPersentvertcal01"
app:layout_constraintEnd_toEndOf="@id/GLPersentvertcal09"
app:layout_constraintBottom_toBottomOf="parent"/>
//Retrofit2
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation("com.squareup.okhttp3:okhttp:4.10.0")
// 以Singleton模式建立
private static SiteManager mInstance = new SiteManager ();
private APIService myAPIService;
private SiteManager () {
// 設置baseUrl即要連的網站,addConverterFactory用Gson作為資料處理Converter
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://jsonplaceholder.typicode.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
myAPIService = retrofit.create(APIService.class);
}
public static SiteManager getInstance() {
return mInstance;
}
public APIService getAPI() {
return myAPIService;
}
@GET("posts")
Call<List<APIResponse>> response();
private int userId;
private int id;
private String title;
private String body;
@Override
public String toString() {
return "APIResponse{" +
"userId=" + userId +
", id=" + id +
", title='" + title + '\'' +
", body='" + body + '\'' +
'}';
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
interface View{
void setString(String string);
}
interface Presenter{
void onButtonClick(String Password,String Account);
}
interface Model{
interface FinishListener {
void OnFinished(String string);
}
void OnNext(Contract.Model.FinishListener OnFinished);
}
三個對應的Class
MainActivity(View)
public class MainActivity extends AppCompatActivity implements Contract.View{
private TextView showText;
private Button button;
private EditText account,password;
private Contract.Presenter presenter;
private static String TAG = "View";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.EnterButton);
showText = findViewById(R.id.showStatus);
account = findViewById(R.id.ETaccount);
password = findViewById(R.id.ETpassword);
presenter = new Presenter(this,new Model());
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.e(TAG, "onClick: ");
presenter.onButtonClick(account.getText().toString(),password.getText().toString());
}
});
}
@Override
public void setString(String string) {
Log.e(TAG, "setString: ");
showText.setText(string);
}
}
public class Presenter implements Contract.Presenter,Contract.Model.FinishListener{
private Contract.View mainView;
private Contract.Model model;
private static String TAG = "Presenter";
private String password,account;
public Presenter(Contract.View mainView, Contract.Model model) {
this.mainView = mainView;
this.model = model;
}
@Override
public void OnFinished(String string) {
if(mainView != null){
Log.e(TAG, "OnFinished: ");
mainView.setString(string);
}
}
@Override
public void onButtonClick(String Password,String Account) {
Log.e(TAG, "onButtonClick: ");
account = Account;
password = Password;
Log.e(TAG, "onButtonClick: "+password+" "+account );
if(account.equals("jay") && password.equals("jay")){
Log.e(TAG, "Account is Correct: ");
model.OnNext(this);
}else{
Log.e(TAG, "Account is Error: ");
}
}
}
public class Model implements Contract.Model{
private static String TAG = "Model";
private APIService apiService = SiteManager.getInstance().getAPI();
@Override
public void OnNext(Contract.Model.FinishListener OnFinished) {
GetFakeAPI(OnFinished);
}
public void GetFakeAPI(Contract.Model.FinishListener OnFinished){
Call<List<APIResponse>> call = apiService.response ();
call.enqueue (new Callback<List<APIResponse>>() {
@Override
public void onResponse (Call<List<APIResponse>> call, Response<List<APIResponse>> response) {
// for (int i = 0;i<response.body ().size ();i++){
// Log.e (TAG, "userid: "+response.body ().get (i).getUserId ());
// Log.e (TAG, "ID: "+response.body ().get (i).getId ());
// Log.e (TAG, "title: "+response.body ().get (i).getTitle ());
// Log.e (TAG, "body: "+response.body ().get (i).getBody ());
// }
// Log.e (TAG, "ToString Size = "+response.body().toString());
OnFinished.OnFinished(response.body().toString());
}
@Override
public void onFailure (Call<List<APIResponse>> call, Throwable t) {
Log.e (TAG, "onFailure: " );
}
});
}
}
這邊的Model
撰寫方式與上面的GetFakeAPI一樣是寫在副程式並套入到OnNext中。
public void GetObservableResponse(Contract.Model.FinishListener OnFinished){
apiService.observableResponse()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableObserver<Response<List<APIResponse>>>() {
@Override
public void onNext(@NonNull Response<List<APIResponse>> listResponse) {
// for(int i = 0;i<listResponse.body().size();i++){
// Log.e(TAG, "onNextId: "+listResponse.body().get(i).getId() );
// Log.e(TAG, "onNextUserId: "+listResponse.body().get(i).getUserId() );
// Log.e(TAG, "onNextTitle: "+listResponse.body().get(i).getTitle() );
// Log.e(TAG, "onNextBody: "+listResponse.body().get(i).getBody() );
// }
Log.e(TAG, "onNext_Observable: ");
OnFinished.OnFinished(listResponse.body().toString());
}
@Override
public void onError(@NonNull Throwable e) {
Log.e(TAG, "onError: "+e );
}
@Override
public void onComplete() {
Log.e(TAG, "已完成資料接收 ");
}
});
}