Android 中 View Model class 中的错误解决方法
Error resolving method in View Model class in Android
我是 Android Devlopement 的新手,我试图使用 API 调用从网站获取地震列表,并使用 Recycler 视图将它们显示在屏幕上。我现在正在尝试将 ViewModel 合并到我的应用程序中,以便在屏幕旋转时不会进行多次 API 调用,但我不明白为什么会出现错误:Cannot resolve method 'getEarthquakes' in ViewModel
这是我的 MainActivity (EarthquakeActivity) 和 ViewModel(MyModel) class 在 Java 中的实现。
EarthquakeActivity.java
package com.example.android.earthquake;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.app.SearchManager;
import android.content.ClipData;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class EarthquakeActivity extends AppCompatActivity {
private ViewModel mViewModel;
private ViewModelProvider mViewModelProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.earthquake_activity);
mViewModelProvider = new ViewModelProvider(this);
mViewModel = mViewModelProvider.get(MyModel.class);
// find a reference to the {@link RecyclerView} in the layout
RecyclerView recyclerView = findViewById(R.id.earthquakes);
// fetch the list of earthquakes
ArrayList<Earthquake> earthquakes = mViewModel.getEarthquakes();// error on this line
// create adapter passing in the earthquake data
EarthquakeAdapter earthquakeAdapter = new EarthquakeAdapter(EarthquakeActivity.this,earthquakes);
// attach the adapter to the recyclerView to populate the items
recyclerView.setAdapter(earthquakeAdapter);
// set the layout manager to position the items
recyclerView.setLayoutManager(new LinearLayoutManager(EarthquakeActivity.this));
// click listener for when an item is clicked
earthquakeAdapter.setClickListener((view, position) -> searchWeb(earthquakes.get(position).getUrl()));
}
private void searchWeb (String url) {
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,url);
if(intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
}
和MyModel.java
package com.example.android.earthquake;
import android.os.Handler;
import android.os.Looper;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyModel extends ViewModel {
private ArrayList<Earthquake> mEarthquakes;
public ArrayList<Earthquake> getEarthquakes() {
// perform the network request on separate thread
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
@Override
public void run() {
// create array list of earthquakes
mEarthquakes = QueryUtils.fetchEarthquakeData("https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&eventtype=earthquake&orderby=time&minmag=6&limit=10");
}
});
executorService.shutdown();
return mEarthquakes;
}
}
即使编写这么多的 ViewModel 对我来说也很难,因为几乎所有教程都使用 Kotlin,而且我发现 Loaders 已被弃用。另外,如果可能的话,如果 API 在新地震发生时发生变化而无需重新启动应用程序,有人能告诉我如何用最新的地震数据更新 UI 吗?我将不胜感激。
我可以看到这里有很多空白。
让我们从您的 EarthquakeActivity 开始,这里您的 mViewModel 的类型是 ViewModel,它应该是 MyModel,并且由于 ViewModel class 中没有 getEarthquakes() 方法,您会收到该错误。
在行中,ArrayList earthquakes = mViewModel.getEarthquakes();
您要求您的视图模型为您提供列表,网络调用需要一些时间,而且它也是异步的,因此您将收到一个空列表。
要解决此问题,您需要在视图模型中使用 MutableLiveData 并且需要在 activity 中观察它,以便在从网络调用,我也会建议你使用retrofit进行网络调用。
因此您的最终代码将如下所示,
EarthquakeActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.app.SearchManager;
import android.content.ClipData;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class EarthquakeActivity extends AppCompatActivity {
private MyModel mViewModel;
private ViewModelProvider mViewModelProvider;
private RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.earthquake_activity);
//init viewmodel
mViewModelProvider = new ViewModelProvider(this);
mViewModel = mViewModelProvider.get(MyModel.class);
// find a reference to the {@link RecyclerView} in the layout
recyclerView = findViewById(R.id.earthquakes);
// fetch and observer the list of earthquakes
mViewModel.getEarthquakes().observe(this, new Observer<ArrayList<Earthquake>>() {
@Override
public void onChanged(ArrayList<Earthquake> earthquakes) {
//setup recycler view with this data, this will work even if you rotate the device
setUpRecyclerView(earthquakes);
}
});
}
private void setUpRecyclerView(ArrayList<Earthquake> earthquakes) {
// create adapter passing in the earthquake data
EarthquakeAdapter earthquakeAdapter = new EarthquakeAdapter(EarthquakeActivity.this,earthquakes);
// attach the adapter to the recyclerView to populate the items
recyclerView.setAdapter(earthquakeAdapter);
// set the layout manager to position the items
recyclerView.setLayoutManager(new LinearLayoutManager(EarthquakeActivity.this));
// click listener for when an item is clicked
earthquakeAdapter.setClickListener((view, position) -> searchWeb(earthquakes.get(position).getUrl()));
}
private void searchWeb (String url) {
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,url);
if(intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
}
还有你的MyModel.java
import android.os.Handler;
import android.os.Looper;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyModel extends ViewModel {
private MutableLiveData<ArrayList<Earthquake>> mEarthquakesLiveData;
public MutableLiveData<ArrayList<Earthquake>> getEarthquakes() {
// perform the network request on separate thread
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
@Override
public void run() {
// create array list of earthquakes
mEarthquakesLiveData.setValue(QueryUtils.fetchEarthquakeData("https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&eventtype=earthquake&orderby=time&minmag=6&limit=10"));
}
});
executorService.shutdown();
return mEarthquakesLiveData;
}
}
希望对您有所帮助,欢迎点个赞。美好的一天,伙计!!
我是 Android Devlopement 的新手,我试图使用 API 调用从网站获取地震列表,并使用 Recycler 视图将它们显示在屏幕上。我现在正在尝试将 ViewModel 合并到我的应用程序中,以便在屏幕旋转时不会进行多次 API 调用,但我不明白为什么会出现错误:Cannot resolve method 'getEarthquakes' in ViewModel
这是我的 MainActivity (EarthquakeActivity) 和 ViewModel(MyModel) class 在 Java 中的实现。
EarthquakeActivity.java
package com.example.android.earthquake;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.app.SearchManager;
import android.content.ClipData;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class EarthquakeActivity extends AppCompatActivity {
private ViewModel mViewModel;
private ViewModelProvider mViewModelProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.earthquake_activity);
mViewModelProvider = new ViewModelProvider(this);
mViewModel = mViewModelProvider.get(MyModel.class);
// find a reference to the {@link RecyclerView} in the layout
RecyclerView recyclerView = findViewById(R.id.earthquakes);
// fetch the list of earthquakes
ArrayList<Earthquake> earthquakes = mViewModel.getEarthquakes();// error on this line
// create adapter passing in the earthquake data
EarthquakeAdapter earthquakeAdapter = new EarthquakeAdapter(EarthquakeActivity.this,earthquakes);
// attach the adapter to the recyclerView to populate the items
recyclerView.setAdapter(earthquakeAdapter);
// set the layout manager to position the items
recyclerView.setLayoutManager(new LinearLayoutManager(EarthquakeActivity.this));
// click listener for when an item is clicked
earthquakeAdapter.setClickListener((view, position) -> searchWeb(earthquakes.get(position).getUrl()));
}
private void searchWeb (String url) {
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,url);
if(intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
}
和MyModel.java
package com.example.android.earthquake;
import android.os.Handler;
import android.os.Looper;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyModel extends ViewModel {
private ArrayList<Earthquake> mEarthquakes;
public ArrayList<Earthquake> getEarthquakes() {
// perform the network request on separate thread
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
@Override
public void run() {
// create array list of earthquakes
mEarthquakes = QueryUtils.fetchEarthquakeData("https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&eventtype=earthquake&orderby=time&minmag=6&limit=10");
}
});
executorService.shutdown();
return mEarthquakes;
}
}
即使编写这么多的 ViewModel 对我来说也很难,因为几乎所有教程都使用 Kotlin,而且我发现 Loaders 已被弃用。另外,如果可能的话,如果 API 在新地震发生时发生变化而无需重新启动应用程序,有人能告诉我如何用最新的地震数据更新 UI 吗?我将不胜感激。
我可以看到这里有很多空白。
让我们从您的 EarthquakeActivity 开始,这里您的 mViewModel 的类型是 ViewModel,它应该是 MyModel,并且由于 ViewModel class 中没有 getEarthquakes() 方法,您会收到该错误。
在行中,ArrayList earthquakes = mViewModel.getEarthquakes(); 您要求您的视图模型为您提供列表,网络调用需要一些时间,而且它也是异步的,因此您将收到一个空列表。
要解决此问题,您需要在视图模型中使用 MutableLiveData
因此您的最终代码将如下所示,
EarthquakeActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.app.SearchManager;
import android.content.ClipData;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class EarthquakeActivity extends AppCompatActivity {
private MyModel mViewModel;
private ViewModelProvider mViewModelProvider;
private RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.earthquake_activity);
//init viewmodel
mViewModelProvider = new ViewModelProvider(this);
mViewModel = mViewModelProvider.get(MyModel.class);
// find a reference to the {@link RecyclerView} in the layout
recyclerView = findViewById(R.id.earthquakes);
// fetch and observer the list of earthquakes
mViewModel.getEarthquakes().observe(this, new Observer<ArrayList<Earthquake>>() {
@Override
public void onChanged(ArrayList<Earthquake> earthquakes) {
//setup recycler view with this data, this will work even if you rotate the device
setUpRecyclerView(earthquakes);
}
});
}
private void setUpRecyclerView(ArrayList<Earthquake> earthquakes) {
// create adapter passing in the earthquake data
EarthquakeAdapter earthquakeAdapter = new EarthquakeAdapter(EarthquakeActivity.this,earthquakes);
// attach the adapter to the recyclerView to populate the items
recyclerView.setAdapter(earthquakeAdapter);
// set the layout manager to position the items
recyclerView.setLayoutManager(new LinearLayoutManager(EarthquakeActivity.this));
// click listener for when an item is clicked
earthquakeAdapter.setClickListener((view, position) -> searchWeb(earthquakes.get(position).getUrl()));
}
private void searchWeb (String url) {
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,url);
if(intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
}
还有你的MyModel.java
import android.os.Handler;
import android.os.Looper;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyModel extends ViewModel {
private MutableLiveData<ArrayList<Earthquake>> mEarthquakesLiveData;
public MutableLiveData<ArrayList<Earthquake>> getEarthquakes() {
// perform the network request on separate thread
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
@Override
public void run() {
// create array list of earthquakes
mEarthquakesLiveData.setValue(QueryUtils.fetchEarthquakeData("https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&eventtype=earthquake&orderby=time&minmag=6&limit=10"));
}
});
executorService.shutdown();
return mEarthquakesLiveData;
}
}
希望对您有所帮助,欢迎点个赞。美好的一天,伙计!!