質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Q&A

解決済

1回答

1803閲覧

【Android】Recyclerviewに、Retrofit2で取得したデータをリアルタイムで反映させたい

nomabe

総合スコア1

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

0グッド

0クリップ

投稿2022/04/21 11:56

1.前提・実現したいこと

JavaでAndroidアプリ開発のMVVM設計を勉強中です。今は、郵便番号から町域名をリスト表示するサンプルプログラムを作っています。

以下の流れで実現させたいと考えています。

❶ Searchviewで7桁の郵便番号を入力
❷ ❶をもとにAPI通信(今回はZipcloudの郵便番号検索APIを使用)
❸ ❷で取得したデータをRecyclerviewに表示

因みに、ライブラリは以下を使用しています。

  • リストRetrofit2
  • リストViewmodel
  • リストLivedata
  • リストDatabinding

2.発生している問題

Searchview(onQueryTextChangeメソッドで実現)に、実際に存在する7桁の郵便番号を入力しても、一回でリアルタイムで反映されません。

7桁(1)▶︎6桁▶︎7桁(2)の順で入力すると、7桁(1)で入力した郵便番号に対応する住所がまず表示されてしまいます。

つまり、**1回分ずれてRecyclerviewにデータが反映されます。**今回はここを解決したいです。

3.該当のソースコード

<ViewModel箇所>

CityViewModel.java

1public class CityViewModel extends AndroidViewModel { 2 3 private MutableLiveData<List<Address>> address; 4 private CityRepository repository; 5 6 public CityViewModel(@NonNull Application application) { 7 super(application); 8 repository = new CityRepository(); 9 } 10 11 public LiveData<List<Address>> getAddress() { 12 13 if(address == null) { 14 15 address = new MutableLiveData<List<Address>>(); 16 } 17 return address; 18 } 19 20 //取得したデータを設定 21 public void searchAddress(String zipcode) { 22 23 //CityRepository.executorService.execute(() -> { 24 25 address.postValue(repository.getAddress(zipcode)); 26 //}); 27 } 28 29 public void clearAddress() { 30 31 //CityRepository.executorService.execute(() -> { 32 address.postValue(repository.clearAddress()); 33 //}); 34 } 35}

<Model箇所>

CityRepository.java

1public class CityRepository { 2 3 private ApiInterface service; 4 private List<Address> address; 5 private static final int NUMBER_OF_THREADS = 4; 6 public static final ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_THREADS); 7 8 public CityRepository() { 9 10 //APIインスタンスを生成 11 service = new Retrofit.Builder() 12 .baseUrl("https://zipcloud.ibsnet.co.jp/") 13 .addConverterFactory(GsonConverterFactory.create()) 14 .build() 15 .create(ApiInterface.class); 16 } 17 18 public List<Address> getAddress(String zipcode) { 19 20 //APIを呼び出し 21 service.getCity(zipcode).enqueue(new Callback() { 22 23 //リクエスト成功時 24 @Override 25 public void onResponse(Call call, Response response) { 26 27 Log.i("message2", "Successed to request"); 28 29 //通信結果を受け取る 30 City city = (City) response.body(); 31 address = city.getResults(); 32 } 33 34 @Override 35 public void onFailure(Call call, Throwable t) { 36 37 Log.i("message2", "error:" + t); 38 } 39 }); 40 41 return address; 42 } 43 44 public List<Address> clearAddress() { 45 46 return new ArrayList<Address>(); 47 } 48 49}

<View箇所>

MainFragment.java

1public class MainFragment extends Fragment { 2 3@Override 4 public View onCreateView(LayoutInflater inflater, ViewGroup container, 5 Bundle savedInstanceState) { 6 // Inflate the layout for this fragment 7 //return inflater.inflate(R.layout.fragment_main, container, false); 8 9 //DataBindingインスタンス生成 10 binding = DataBindingUtil.inflate(inflater,R.layout.fragment_main, container, false); 11 //DataBindingに紐付け 12 binding.setLifecycleOwner(getActivity()); 13 return binding.getRoot(); 14 } 15 16 @Override 17 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 18 super.onViewCreated(view, savedInstanceState); 19 20 //ViewModelインスタンス生成 21 viewModel = new ViewModelProvider(requireActivity()).get(CityViewModel.class); 22 23 //SearchViewにリスナ設定 24 binding.svZipcode.setOnQueryTextListener(new searchViewListener()); 25 26 //RecyclerViewの表示設定 27 binding.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); 28 binding.recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(),LinearLayoutManager.VERTICAL)); 29 adapter = new CityAdapter(new CityAdapter.CountryDiff(),getActivity()); 30 binding.recyclerView.setAdapter(adapter); 31 } 32 33 @Override 34 public void onActivityCreated(@Nullable Bundle savedInstanceState) { 35 super.onActivityCreated(savedInstanceState); 36 37 //LiveDataを監視 38 viewModel.getAddress().observe(getViewLifecycleOwner(),new Observer<List<Address>>() { 39 @Override 40 public void onChanged(List<Address> addresses) { 41 42 //変更があるたびに、差分データを更新 43 adapter.submitList(addresses); 44 } 45 }); 46 } 47 48 //SearchViewのリスナークラス 49 private class searchViewListener implements SearchView.OnQueryTextListener { 50 51 @Override 52 public boolean onQueryTextSubmit(String query) { 53 54 if(query.length() == 7) { 55 56 //検索処理 57 //viewModel.searchAddress(query); 58 } 59 return false; 60 } 61 62 @Override 63 public boolean onQueryTextChange(String newText) { 64 65 if(newText.length() == 7) { 66 //検索処理 67 viewModel.searchAddress(newText); 68 69 } else { 70 //空にする 71 viewModel.clearAddress(); 72 } 73 return false; 74 } 75 } 76}

CityAdapter.java

1public class CityAdapter extends ListAdapter<Address, RecyclerView.ViewHolder> { 2 3 private LifecycleOwner owner; 4 5 public CityAdapter(@NonNull DiffUtil.ItemCallback<Address> diffCallback,LifecycleOwner _owner) { 6 super(diffCallback); 7 owner = _owner; 8 } 9 10 //ビューホルダーオブジェクトを生成 11 @NonNull 12 @Override 13 public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 14 15 //DataBindingインスタンス生成 16 ListItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.list_item, parent, false); 17 18 //RootViewを取得 19 View rootView = binding.getRoot(); 20 21 //RootViewにbindingを設定 22 rootView.setTag(binding); 23 24 return new RecyclerView.ViewHolder (rootView) {}; 25 } 26 27 //データの割り当て 28 @Override 29 public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { 30 31 ListItemBinding binding = (ListItemBinding)holder.itemView.getTag(); 32 binding.setLifecycleOwner(owner); 33 binding.setAddress(getItem(position)); 34 binding.executePendingBindings(); 35 } 36 37 //変化を検知するインナークラス 38 public static class CountryDiff extends DiffUtil.ItemCallback<Address> { 39 40 //変化後、インスタンスが同じかどうかを判定 41 @Override 42 public boolean areItemsTheSame(@NonNull Address oldItem, @NonNull Address newItem) { 43 return oldItem == newItem; 44 } 45 46 //変化後、インスタンスの中身が同じかどうかを判定 47 @Override 48 public boolean areContentsTheSame(@NonNull Address oldItem, @NonNull Address newItem) { 49 return oldItem.getAddress3().equals(newItem.getAddress3()); 50 } 51 } 52}

fragment_main.xml

1<?xml version="1.0" encoding="utf-8"?> 2<layout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools"> 5 6 <androidx.constraintlayout.widget.ConstraintLayout 7 android:layout_width="match_parent" 8 android:layout_height="match_parent" 9 tools:context=".view.MainActivity"> 10 11 <androidx.appcompat.widget.SearchView 12 android:id="@+id/sv_zipcode" 13 android:layout_width="match_parent" 14 android:layout_height="wrap_content" 15 app:layout_constraintEnd_toEndOf="parent" 16 app:layout_constraintStart_toStartOf="parent" 17 app:layout_constraintTop_toTopOf="parent" 18 app:queryHint="郵便番号" 19 android:iconifiedByDefault="false" /> 20 21 <androidx.recyclerview.widget.RecyclerView 22 android:id="@+id/recyclerView" 23 android:layout_width="match_parent" 24 android:layout_height="0dp" 25 app:layout_constraintBottom_toBottomOf="parent" 26 app:layout_constraintEnd_toEndOf="parent" 27 app:layout_constraintHorizontal_bias="0.0" 28 app:layout_constraintStart_toStartOf="parent" 29 app:layout_constraintTop_toBottomOf="@id/sv_zipcode" 30 app:layout_constraintVertical_bias="0.0" /> 31 32 </androidx.constraintlayout.widget.ConstraintLayout> 33</layout>

list_item.xml

1<?xml version="1.0" encoding="utf-8"?> 2<layout xmlns:android="http://schemas.android.com/apk/res/android"> 3 4 <data> 5 <variable 6 name="address" 7 type="com.example.mvvmtrialapp2.model.Address" /> 8 9 </data> 10 11 <androidx.appcompat.widget.LinearLayoutCompat 12 android:layout_width="match_parent" 13 android:layout_height="wrap_content" 14 android:paddingLeft="10dp" 15 android:orientation="vertical"> 16 17 <TextView 18 android:id="@+id/tv_address1" 19 android:text="@{address.address1}" 20 android:layout_width="wrap_content" 21 android:layout_height="wrap_content" 22 android:textSize="25sp" /> 23 24 <TextView 25 android:id="@+id/tv_address2" 26 android:text="@{address.address2}" 27 android:layout_width="wrap_content" 28 android:layout_height="wrap_content" 29 android:textSize="25sp" /> 30 31 <TextView 32 android:id="@+id/tv_address3" 33 android:text="@{address.address3}" 34 android:layout_width="wrap_content" 35 android:layout_height="wrap_content" 36 android:textSize="25sp" /> 37 38 </androidx.appcompat.widget.LinearLayoutCompat> 39</layout>

4.自分で試したこと

  • リストログより、Zipcloudの郵便番号検索APIからデータの取得自体は出来ている。

▶︎Retrofit2周りが原因ではなさそう。

  • リスト【2.発生している問題】にもある通り、ユーザーのアクションから1回分ずれてRecyclerviewに表示される。

▶︎viewModel.searchAddress(Searchviewで入力された文字)でLivedataの値を変更する際に、反映の通知が遅れているためかなと考える。

5.補足情報

<開発環境>
Mac
Android Studio Bumblebee
Java 8

<エミュレータ>
Google Pixel 5(Android 12)
compileSdkVersion 31
minSdkVersion 16

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2022/04/22 11:29

CityRepository.getAddress メソッドの最後の return address の直前にも Log を入れて、 "Successed to request" とどちらが先に表示されるか試しては如何でしょう。
nomabe

2022/04/22 13:10

アドバイスありがとうございます。試します。
guest

回答1

0

ベストアンサー

Retrofit2 から戻った時の表示までの流れは出来ているでしょうか。
(Call.enqueue() は非同期で処理を行うメソッドです。)

MainFragment.java

java

1import android.os.Bundle; 2import android.view.View; 3import android.widget.*; 4 5import androidx.annotation.*; 6import androidx.appcompat.widget.SearchView; 7import androidx.fragment.app.Fragment; 8import androidx.lifecycle.ViewModelProvider; 9import androidx.recyclerview.widget.*; 10 11public class MainFragment extends Fragment { 12 MainFragment() { 13 super(R.layout.fragment_main); 14 } 15 @Override 16 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 17 super.onViewCreated(view, savedInstanceState); 18 19 ProgressBar progressBar = view.findViewById(R.id.progressBar); 20 SearchView searchView = view.findViewById(R.id.searchView); 21 TextView messageText = view.findViewById(R.id.messageText); 22 RecyclerView recyclerView = view.findViewById(R.id.recyclerView); 23 24 CityAdapter adapter = new CityAdapter(); 25 recyclerView.setAdapter(adapter); 26 27 CityViewModel viewModel = new ViewModelProvider(requireActivity()).get(CityViewModel.class); 28 29 viewModel.getAddressList().observe(getViewLifecycleOwner(), addressList -> { 30 adapter.setAddressList(addressList); 31 progressBar.setVisibility(View.INVISIBLE); 32 searchView.setEnabled(true); 33 }); 34 35 viewModel.getMessage().observe(getViewLifecycleOwner(), message -> { 36 if(message != null) { 37 messageText.setVisibility(View.VISIBLE); 38 messageText.setText(message); 39 } else { 40 messageText.setVisibility(View.GONE); 41 } 42 }); 43 44 searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 45 @Override 46 public boolean onQueryTextSubmit(String query) { 47 viewModel.searchAddress(query); 48 progressBar.setVisibility(View.VISIBLE); 49 searchView.setEnabled(false); 50 return true; 51 } 52 @Override 53 public boolean onQueryTextChange(String newText) { 54 return false; 55 } 56 }); 57 } 58}

res/layout/fragment_main.xml

xml

1<?xml version="1.0" encoding="utf-8"?> 2<androidx.constraintlayout.widget.ConstraintLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 xmlns:app="http://schemas.android.com/apk/res-auto" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent"> 7 <ProgressBar 8 android:id="@+id/progressBar" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:visibility="invisible" 12 app:layout_constraintBottom_toBottomOf="parent" 13 app:layout_constraintEnd_toEndOf="parent" 14 app:layout_constraintStart_toStartOf="parent" 15 app:layout_constraintTop_toTopOf="parent" /> 16 <androidx.appcompat.widget.SearchView 17 android:id="@+id/searchView" 18 android:layout_width="match_parent" 19 android:layout_height="wrap_content" 20 app:queryHint="郵便番号" 21 android:iconifiedByDefault="false" 22 app:layout_constraintEnd_toEndOf="parent" 23 app:layout_constraintStart_toStartOf="parent" 24 app:layout_constraintTop_toTopOf="parent" /> 25 <TextView 26 android:id="@+id/messageText" 27 android:layout_width="match_parent" 28 android:layout_height="wrap_content" 29 android:textSize="20dp" 30 android:visibility="gone" 31 app:layout_constraintEnd_toEndOf="parent" 32 app:layout_constraintStart_toStartOf="parent" 33 app:layout_constraintTop_toBottomOf="@id/searchView" /> 34 <androidx.recyclerview.widget.RecyclerView 35 android:id="@+id/recyclerView" 36 android:layout_width="0dp" 37 android:layout_height="0dp" 38 app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" 39 app:layout_constraintBottom_toBottomOf="parent" 40 app:layout_constraintEnd_toEndOf="parent" 41 app:layout_constraintStart_toStartOf="parent" 42 app:layout_constraintTop_toBottomOf="@id/messageText" /> 43</androidx.constraintlayout.widget.ConstraintLayout>

CityAdapter.java

java

1import android.view.*; 2import android.widget.TextView; 3 4import androidx.annotation.NonNull; 5import androidx.recyclerview.widget.RecyclerView; 6 7import java.util.*; 8 9public class CityAdapter extends RecyclerView.Adapter<CityAdapter.ViewHolder> { 10 static class ViewHolder extends RecyclerView.ViewHolder { 11 final TextView tv_address1, tv_address2, tv_address3; 12 public ViewHolder(@NonNull View itemView) { 13 super(itemView); 14 this.tv_address1 = itemView.findViewById(R.id.tv_address1); 15 this.tv_address2 = itemView.findViewById(R.id.tv_address2); 16 this.tv_address3 = itemView.findViewById(R.id.tv_address3); 17 } 18 } 19 20 private List<Address> addressList = Collections.emptyList(); 21 22 void setAddressList(List<Address> addressList) { 23 this.addressList = addressList; 24 notifyDataSetChanged(); 25 } 26 27 @NonNull 28 @Override 29 public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 30 View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false); 31 return new ViewHolder(view); 32 } 33 @Override 34 public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 35 Address address = addressList.get(position); 36 holder.tv_address1.setText(address.address1); 37 holder.tv_address2.setText(address.address2); 38 holder.tv_address3.setText(address.address3); 39 } 40 @Override 41 public int getItemCount() { 42 return addressList.size(); 43 } 44}

CityViewModel.java

java

1import android.app.Application; 2 3import androidx.annotation.NonNull; 4import androidx.lifecycle.*; 5 6import java.util.*; 7 8public class CityViewModel extends AndroidViewModel { 9 private MutableLiveData<List<Address>> addressListLiveData = new MutableLiveData<>(Collections.emptyList()); 10 private MutableLiveData<String> messageLiveData = new MutableLiveData<>(""); 11 private CityRepository repository; 12 13 public CityViewModel(@NonNull Application application) { 14 super(application); 15 16 repository = new CityRepository(); 17 } 18 19 LiveData<List<Address>> getAddressList() { return addressListLiveData; } 20 LiveData<String> getMessage() { return messageLiveData; } 21 22 void searchAddress(String zipcode) { 23 repository.requestAddressList(zipcode, new CityRepository.AddressListCallback() { 24 @Override 25 public void onResponce(int status, String message, List<Address> addressList) { 26 addressListLiveData.postValue(addressList); 27 messageLiveData.postValue(message == null ? null : "["+status+"]"+message); 28 } 29 @Override 30 public void onFailure(Throwable t) { 31 messageLiveData.postValue(t.getMessage()); 32 t.printStackTrace(); 33 } 34 }); 35 } 36}

CityRepository.java

java

1import java.util.*; 2 3import retrofit2.*; 4import retrofit2.converter.gson.GsonConverterFactory; 5 6public class CityRepository { 7 interface AddressListCallback { 8 void onResponce(int status, String message, List<Address> addressList); 9 void onFailure(Throwable t); 10 } 11 12 private ApiInterface service; 13 14 CityRepository() { 15 service = new Retrofit.Builder() 16 .baseUrl("https://zipcloud.ibsnet.co.jp/") 17 .addConverterFactory(GsonConverterFactory.create()) 18 .build() 19 .create(ApiInterface.class); 20 } 21 public void requestAddressList(String zipcode, AddressListCallback callback) { 22 Call<ZipcloudResponse> zipcloud = service.request(zipcode); 23 zipcloud.enqueue(new Callback<ZipcloudResponse>() { 24 @Override 25 public void onResponse(Call<ZipcloudResponse> call, Response<ZipcloudResponse> response) { 26 List<Address> list = new ArrayList<>(); 27 ZipcloudResponse body = response.body(); 28 if(body.results != null) { 29 for(ZipcloudResult r : body.results) { 30 list.add(new Address(r.zipcode, r.prefcode, r.address1, r.address2, r.address3, r.kana1, r.kana2, r.kana3)); 31 } 32 } 33 callback.onResponce(body.status, body.message, list); 34 } 35 @Override 36 public void onFailure(Call<ZipcloudResponse> call, Throwable t) { 37 callback.onFailure(t); 38 } 39 }); 40 } 41}

Address.java

java

1public class Address { 2 final String prefcode; 3 final String zipcode; 4 final String address1, address2, address3; 5 final String kana1, kana2, kana3; 6 Address(String zipcode, String prefcode, String address1, String address2, String address3, String kana1, String kana2, String kana3) { 7 this.zipcode = zipcode; 8 this.prefcode = prefcode; 9 this.address1 = address1; 10 this.address2 = address2; 11 this.address3 = address3; 12 this.kana1 = kana1; 13 this.kana2 = kana2; 14 this.kana3 = kana3; 15 } 16}

ZipcloudResponse.java

java

1import java.util.List; 2 3public class ZipcloudResponse { 4 String message; 5 List<ZipcloudResult> results; 6 int status; 7}

ZipcloudResult.java

java

1public class ZipcloudResult { 2 public String zipcode; 3 public String prefcode; 4 public String address1; 5 public String address2; 6 public String address3; 7 public String kana1; 8 public String kana2; 9 public String kana3; 10}

ApiInterface.java

java

1import retrofit2.Call; 2import retrofit2.http.*; 3 4public interface ApiInterface { 5 @GET("api/search") 6 Call<ZipcloudResponse> request(@Query("zipcode") String zipcode); 7}

投稿2022/04/22 10:42

編集2022/04/22 11:11
jimbe

総合スコア12612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nomabe

2022/04/22 13:02 編集

コードを丁寧に掲載してくださり、ありがとうございます。 『Retrofit2 から戻った時の表示までの流れ』とは、どこからどこまでを指しますでしょうか?自身の理解不足で申し訳ございません。 また、ZipcloudResult.javaとAddress.javaではどのような理由で分けているのでしょうか? お手数おかけしますが、よろしくお願いします。
jimbe

2022/04/22 16:57

> Retrofit2 から戻った時の表示までの流れ コードが多くなったので回答に書ける文字数制限に引っかからないようにごく短い文章になってしまいました。すいません。 「自分で試したこと」を見ますと、どのデータがどのタイミングでどこまで来ているかを(取得できていること以外)確認されていません。 ご質問のコメントに書きましたが、取得出来ているなら getAddress メソッドがそのデータを返す(つもりの) コードになっていますが、取得したデータが本当に getAddress メソッドから返されているかを確認した様子はありません。 getAddress が正しく最新のデータを返したとしたら、ではどこまでそのデータは渡されて行っているのか等を確認されているのでしょうか。 > ZipcloudResult.javaとAddress.javaではどのような理由で分けているのでしょうか ZipcloudResult は Zipcloud から得た生データ、 Address はアプリで使う (Recycler の行 ?) 用です。 ZipcloudResponse と ZipcloudResult , ApiInterface は CityRepository しか使わないモノです。
nomabe

2022/04/23 13:40

いえいえ、本当に丁寧な対応ありがとうございます。 どのデータがどこまで来ているのかそもそも曖昧にしていました。申し訳ございません。 CityRepository.javaのgetAddress メソッドの最後の return address の直前に、”Successed to request2" とLog を入れました。すると、”Successed to request2”▶︎”Successed to request”の順で表示されました。ここが逆であれば、ちゃんと反映されるということになりますよね? となると、そもそもretrofit2からデータをうまく取得できていないため、viewmodelにも影響しているのかなと考えました。 ZipcloudResult.javaとAddress.javaの違いは理解致しました。ありがとうございます。
jimbe

2022/04/23 18:17 編集

>そもそもretrofit2からデータをうまく取得できていないため 「Call.enqueue() は非同期で処理を行うメソッド」ということをお分かりになっていないようです。 非同期ということは、enqueue メソッドを呼び出すことで Retrofit が通信を開始する一方、呼び出した側はその通信が終るのを待つこと無く次の処理に進むということです。 つまり Log によって判明した動作が正常で、getAddress メソッドの return 文の実行時点ではまだ address フィールドは更新されていないので古い状態のままであり、郵便番号を更新して次の検索を開始する頃には先の通信が完了し address フィールドが更新されているため、『見た目的に』1回遅れて表示されている状態になっています。 私のコードでは、Retrofit に要求を出す (getAddress に当たる ) requestAddressList メソッドは、値を返しません。 コールバックの onResponse メソッド内から CityRepository.AddressListCallback を通じてビューモデルのデータを更新することで表示を最新にしています。同時に、プログレスを表示して検索中であることを示すようにしています。
nomabe

2022/04/24 10:13

毎回丁寧に解説してくださり、本当にありがとうございます。自身の理解力不足で申し訳ございません。 今回見た目的に一回分遅れて表示されてしまうのは、Call.enqueue()が非同期処理のメソッドであるが故に、古いデータがまだ残った状態が先に表示されてしまうのが原因だと理解致しました。 jimbeさんのコードを参照し、修正致します。修正次第、ベストアンサーとさせていただきます。 ありがとうございます!
jimbe

2022/04/24 12:38

謝ることはありません。理解力不足とかでは無く、単に今まで不明だったことが明らかになったというだけだと思います。 むしろ、コードやどう考えたかまで書いて頂けたので、 teratail のコンテンツとして良い感じになっていると思います。 (回答本文のほうがよっぽどヒドいです orz)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問