【问题标题】:How to call Json using Retrofit如何使用 Retrofit 调用 Json
【发布时间】:2020-04-05 00:29:09
【问题描述】:

我有如下 JSON:

{
  "Search": [
    {
      "Title": "Iron Man",
      "Year": "2008"
    },
    {
      "Title": "Iron Man2",
      "Year": "20010"
    },
    {
      "Title": "Iron Man3",
      "Year": "2013"
    }
  ]
}

然后我创建了如下 API 服务:

public interface MyApi {

    @GET("/movies")
    Call<ArrayList<MovieSearch>> getartistdata();
}

我的数据类如下

public class MovieSearch {

    @SerializedName("Search")
    public List<Search> Search =null;

}

public class Search {

    @SerializedName("Title")
    public String Title="";

    @SerializedName("Year")
    public String Year="";

    @SerializedName("Poster")
    public String Poster="";

    public Search() {
    }

    public Search(String Title, String Year, String Poster) {
        this.Title = Title;
        this.Year = Year;
    }
}

现在我正在尝试实现如下视图模型类

public class MyListViewModel extends ViewModel {
    public String Title = "";
    public String Year= "";
    public String Poster = "";
    public MutableLiveData<ArrayList<MyListViewModel>> mutableLiveData = new MutableLiveData<>();
    private ArrayList<MyListViewModel> arrayList;
    private ArrayList<MovieSearch> myList;

    public String getImageurl() {
        return Poster;
    }

    @BindingAdapter({"imageUrl"})
    public static void loadimage(ImageView imageView, String imageUrl) {
        Glide.with(imageView.getContext()).load(imageUrl).apply(RequestOptions.circleCropTransform()).into(imageView);
        //Picasso.with(imageView.getContext()).load(imageUrl).into(imageView);
    }

    public MyListViewModel() {

    }

    public MyListViewModel(MovieSearch myList) {
        this.Title = myList.Title;
        this.Poster = myList.Poster;
        this.Year= myList.Year;
    }

    public MutableLiveData<ArrayList<MyListViewModel>> getMutableLiveData() {

        arrayList = new ArrayList<>();

        MyApi api = MyClient.getInstance().getMyApi();
        Call<ArrayList<MovieSearch>> call = api.getartistdata();
        call.enqueue(new Callback<ArrayList<MovieSearch>>() {
            @Override
            public void onResponse(Call<ArrayList<MovieSearch>> call, Response<ArrayList<MovieSearch>> response) {
                myList = new ArrayList<>();
                myList = response.body();
                for (int i = 0; i < myList.size(); i++) {
                    MovieSearch myk = myList.get(i);
                    MyListViewModel myListViewModel = new MyListViewModel(myk);
                    arrayList.add(myListViewModel);
                    mutableLiveData.setValue(arrayList);
                }

            }

            @Override
            public void onFailure(Call<ArrayList<MovieSearch>> call, Throwable t) {

            }
        });

        return mutableLiveData;
    }
}

但我在以下内容中收到“无法解析符号”错误:

public MyListViewModel(MovieSearch myList) {
        this.Title = myList.Title;
        this.Poster = myList.Poster;
        this.Year= myList.Year;
    }

我正在尝试从 JSON 中获取数据并将其绑定到视图持有者。但我不知道怎么称呼它。请有人帮我解决它。

【问题讨论】:

标签: android retrofit2 android-view android-viewmodel


【解决方案1】:

您已经很接近了,您只需对服务类和视图模型进行一些更改即可完成这项工作。进行以下更改

MyApi 接口: -> 因为你的 json 不是数组列表,而是 MovieSearch 的一个对象,所以在搜索的数组列表中进行相应的更改。

public interface MyApi {

    @GET("/movies")
    Call<MovieSearch> getartistdata();
}

MyListViewModel 类:

    public class MyListViewModel extends ViewModel {

    public MutableLiveData<ArrayList<Search>> mutableLiveData = new MutableLiveData<>();

    @BindingAdapter({"imageUrl"})
    public static void loadimage(ImageView imageView, String imageUrl) {
        Glide.with(imageView.getContext()).load(imageUrl).apply(RequestOptions.circleCropTransform()).into(imageView);
        //Picasso.with(imageView.getContext()).load(imageUrl).into(imageView);
    }


    public MyListViewModel() {
        //do something else, your view model is not POJO it's the handler not storage.
    }

    public MutableLiveData<ArrayList<Search>> getSearchResults() {

        MutableLiveData<ArrayList<Search>> localData = new MutableLiveData<>();

        MyApi api = MyClient.getInstance().getMyApi();
        Call<MovieSearch> call = api.getartistdata();
        call.enqueue(new Callback<MovieSearch>() {
            @Override
            public void onResponse(Call<MovieSearch> call, Response<MovieSearch> response) {
               List<Search> myList = response.body().Search; 
               mutableLiveData.setValue(myList);
               localData.setValue(myList);
            }

            @Override
            public void onFailure(Call<ArrayList<MovieSearch>> call, Throwable t) {
               //handle the error
            }
        });

        return localData;
    }
}

通过创建视图模型的对象并在某个函数内部调用上述视图模型。这部分通常放在一些 UI 类活动或片段中:

  //listening for change in live data
  // this would be in ui layer
    myListViewModelObject.getSearchResults().observe(this, new Observer<ArrayList<Search>>() {
        @Override
        public void onChanged(@Nullable ArrayList<Search> obj) {
           // handle changes here, to use the data write code below
        }
    });

建议:不要使用您的视图模型来存储不适合的数据。它用于处理数据和操作,而不是数据的保存者。在视图模型中管理数据和业务逻辑会导致很多问题。如果可能的话,总是把事情分解成更小的部分,比如从其他类中获取改造对象,或者不要把它放在调用方法本身中,这会重复代码,也可能会影响性能。

注意:我没有测试代码,只是做了最好的更改,它应该可以运行。如果我删除了任何缺少的部分,请添加。

【讨论】:

  • 我已按照您的建议更改了 Adapter 和 MainActivity(请参阅更新部分)。但是我在这里遇到错误: public void bind(Search myli){ this.myListBinding.setMylistmodel(myli); myListBinding.executePendingBindings(); }
  • 您遇到了什么样的错误。如果您正确获取数据,那么它主要是一个 ui 数据绑定问题。在此处发布您的错误日志或创建一个新问题,否则一个问题中的信息过多,人们将无法了解上下文。
【解决方案2】:

在这里,我注意到您保留了一组 ViewModel。主要的是 ViewModel 不适合那样使用。

我认为最好阅读一些文档和 ViewModel 的示例实现以更好地理解。


在您的实施中,一切看起来都很好,但有一件事是将您的 MovieSearch 列表转换为 MyListViewModel 列表。

在 ViewModel 中

public class MyListViewModel extends ViewModel {
    private MutableLiveData<MovieSearch> mutableLiveData = new MutableLiveData<>();

    @BindingAdapter({"imageUrl"})
    public static void loadimage(ImageView imageView, String imageUrl) {
        Glide.with(imageView.getContext()).load(imageUrl).apply(RequestOptions.circleCropTransform()).into(imageView);
        //Picasso.with(imageView.getContext()).load(imageUrl).into(imageView);
    }

    public LiveData<MovieSearch> getMutableLiveData() {
        loadData();
        return mutableLiveData;
    }

    private void loadData(){
MyApi api = MyClient.getInstance().getMyApi();
        Call<MovieSearch> call = api.getartistdata();
        call.enqueue(new Callback<MovieSearch>() {
            @Override
            public void onResponse(Call<MovieSearch> call, Response<MovieSearch> response) {
                MovieSearch movieSearch = response.body();
                mutableLiveData.setValue(myList); 

            }

            @Override
            public void onFailure(Call<ArrayList<MovieSearch>> call, Throwable t) {

            }
        });
    }
}

在activity或fragment中,可以通过getMutableLiveData()访问liveData,并将List&lt;MovieSearch&gt;设置为adapter。


还有一件事,鉴于您的响应 JSON,您的 API 应该如下所示

public interface MyApi {

    @GET("/movies")
    Call<MovieSearch> getartistdata();
}

MovieSearch 不在列表中


适配器

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private ArrayList<Search> arrayList = new ArrayList<>;
    private LayoutInflater layoutInflater;

    public void submitList(ArrayList<Search> searchList){
        this.arrayList = searchList;
        notifyDataSetChanged();
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (layoutInflater==null){
            layoutInflater=LayoutInflater.from(parent.getContext());
        }
        MyListBinding myListBinding= DataBindingUtil.inflate(layoutInflater, R.layout.mylist,parent,false);
        return new ViewHolder(myListBinding);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Search search =arrayList.get(position);
        holder.bind(search);
    }

    @Override
    public int getItemCount() {
        return arrayList.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder{
        private MyListBinding myListBinding;
        public ViewHolder(@NonNull MyListBinding myListBinding) {
            super(myListBinding.getRoot());
            this.myListBinding=myListBinding;
        }
        public void bind(Search myli){
            this.myListBinding.setMylistmodel(myli);
            myListBinding.executePendingBindings();
        }
        public MyListBinding getMyListBinding(){
            return myListBinding;
        }
    }
}

活动

adapter = MyAdapter();

recyclerview=(RecyclerView)findViewById(R.id.recyclerView);
recyclerview.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyclerview.setAdapter(adapter);

myListViewModel = ViewModelProviders.of(this).get(MyListViewModel.class);
        myListViewModel.getSearchResults().observe(this, new Observer<MovieSearch>() {
            @Override
            public void onChanged(@Nullable MovieSearch movieSearch) {
                // handle changes here, to use the data write code below
                adapter.submitList(movieSearch.Search);

            }
        });

还有一件小事,请不要以大写字母开头的变量名。最好从一开始就遵循命名约定。

【讨论】:

  • 你是不是打算像上面那样改变适配器?
猜你喜欢
  • 2015-11-08
  • 1970-01-01
  • 2022-01-15
  • 2017-11-20
  • 2019-03-17
  • 2021-01-17
  • 2022-01-21
  • 2016-01-09
  • 2016-11-03
相关资源
最近更新 更多