将 retfofit 与 MVVM 一起使用时出现错误

Posted

技术标签:

【中文标题】将 retfofit 与 MVVM 一起使用时出现错误【英文标题】:I am getting error while using retfofit with MVVM 【发布时间】:2021-06-25 14:48:22 【问题描述】:

我正在尝试使用带有 MVVM 架构的改造来获取数据。 当我想在控制台上打印数据时,它可以工作。

但是当我想在RecyclerView 上使用它们时,我得到了这个错误:

E/androidRuntime: 致命异常: main 进程:com.example.movi​​eapp,PID:4275 android.os.NetworkOnMainThreadException。

这是我的代码:

电影资料库

public class MovieRepository 

private static MovieService movieService;
private final MutableLiveData<List<Movie>> listOfPopularMovie ;

private static MovieRepository newsRepository;


public static MovieRepository getInstance()
    if(newsRepository == null)
        newsRepository=new MovieRepository();
    
    return newsRepository;

public MovieRepository()
    movieService= RetrofitService.getMovieService();
    listOfPopularMovie=new MutableLiveData<>();


public MutableLiveData<List<Movie>> getListOfPopularMovie(String key,int page) 
    Call<MovieResponse> popularMovies= movieService.getPopularMovie(key,page);
    popularMovies.enqueue(new Callback<MovieResponse>() 
        @Override
        public void onResponse(Call<MovieResponse> call, Response<MovieResponse> response) 
            listOfPopularMovie.setValue(response.body().getResults());
        

        @Override
        public void onFailure(Call<MovieResponse> call, Throwable t) 
            listOfPopularMovie.postValue(null);
        
    );
    return listOfPopularMovie;

主视图模型

public class MainViewModel extends AndroidViewModel 
private MutableLiveData<List<Movie>> listOfPopularMovies = new MutableLiveData<>();
private MovieRepository movieRepository;


public MainViewModel(@NonNull Application application) 
    super(application);
    movieRepository = MovieRepository.getInstance();


public MutableLiveData<List<Movie>> getListOfPopularMovies(String key, int page) 
    listOfPopularMovies=movieRepository.getListOfPopularMovie(key,page);
    return listOfPopularMovies;

电影适配器

public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.MovieViewHolder> 
private List<Movie> movies;
private Context mContext;
public MovieAdapter(Context context)
    mContext=context;


@NonNull
@Override
public MovieViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
    View view= LayoutInflater.from(mContext).inflate(R.layout.item_view,parent,false);

    return new MovieViewHolder(view);


@Override
public void onBindViewHolder(@NonNull MovieViewHolder holder, int position) 
    Movie movie=movies.get(position);
    String currentTitle=movie.getTitle();
    String imageUrl="https://image.tmdb.org/t/p/original";
    imageUrl +=movie.getBackdrop_path();
    try 
        URL url=new URL(imageUrl);
        Bitmap bmp=BitmapFactory.decodeStream(url.openConnection().getInputStream());
        Drawable drawable=new BitmapDrawable(mContext.getResources(),bmp);
        holder.image.setBackground(drawable);
        holder.title.setText(currentTitle);
     catch (MalformedURLException e) 
        e.printStackTrace();
     catch (IOException e) 
        e.printStackTrace();
    





@Override
public int getItemCount() 
    if(movies == null)
        return 0;
    return movies.size();

public void setMovie(List<Movie> taskEntries) 
    movies = taskEntries;
    notifyDataSetChanged();


class MovieViewHolder extends RecyclerView.ViewHolder 

    LinearLayout image;
    TextView title;
    public MovieViewHolder(@NonNull View itemView) 
        super(itemView);
        image=itemView.findViewById(R.id.movie_image);
        title=itemView.findViewById(R.id.movie_title);
    

主要活动

public class MainActivity extends AppCompatActivity 

MovieAdapter movieAdapter;
RecyclerView recyclerView;
MainViewModel mainViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    recyclerView= findViewById(R.id.recycler_view);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    movieAdapter= new MovieAdapter(this);
    recyclerView.setAdapter(movieAdapter);
    DividerItemDecoration decoration = new DividerItemDecoration(getApplicationContext(), VERTICAL);
    recyclerView.addItemDecoration(decoration);
    mainViewModel= new ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication())).get(MainViewModel.class);
    mainViewModel.getListOfPopularMovies("9e2629973011b0744ce3b589dff1fb32",1).observe(this, new Observer<List<Movie>>() 
        @Override
        public void onChanged(List<Movie> movies) 
           movieAdapter.setMovie(movies);
        
    );



【问题讨论】:

这能回答你的问题吗? How to fix 'android.os.NetworkOnMainThreadException'? 【参考方案1】:

您的异常发生是因为您在 UI 线程中使用了网络。 我在您的 MovieAdapter 代码中发现了问题。

@Override
public void onBindViewHolder(@NonNull MovieViewHolder holder, int position) 
    ......................
    URL url = new URL(imageUrl);
    Bitmap bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
    Drawable drawable = new BitmapDrawable(mContext.getResources(),bmp);
    holder.image.setBackground(drawable);
    .............................

所以你在 MovieAdapter 类的 onBindViewHolder 方法中使用了 url.openConnection() 代码。 但是 onBindViewHolder 是在 UI 线程中调用的。

所以,答案是你不应该在 onBindViewHolder 方法中调用这个函数。

我的建议是你可以使用 Glide 或 Picasso 等图片加载库。

https://github.com/bumptech/glidehttps://github.com/square/picasso

如果你使用 Glide,你的 onBindViewHolder 方法是这样的。

Glide.with(holder.image.getContext()).load(imageUrl).into(holder.image);

我希望这会有所帮助。

【讨论】:

如果对您有帮助,请接受我的回答。

以上是关于将 retfofit 与 MVVM 一起使用时出现错误的主要内容,如果未能解决你的问题,请参考以下文章

将 Jackson JSON 库与骆驼一起使用时出现异常

将 AutoMapper 与实体框架一起使用时出现异常

将 Typescript 与 React-Redux 一起使用时出现类型错误

将 Firebase 与 RecyclearView 一起使用时出现错误

将 objcopy 与“薄存档”文件一起使用时出现问题

将 QuerydslPredicateExecutor 与 JpaRepository 一起使用时出现 IllegalAccessException