我正在通过Head First Android开发工作,我遇到了问题。我尝试使用以下代码并使用从另一个类中的方法返回的数组填充listview,但我收到错误并且不明白为什么。如果我尝试在新的ArrayAdapter中调用该方法,它似乎只会给我错误,就像这样....
public class ListBikeStands extends ListActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ListView listStands = getListView();
ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1,
BikesStands.getStandName());
listStands.setAdapter(listAdapter);
}
它调用的类/方法如下......
public class BikeStands {
private static OkHttpClient client = new OkHttpClient();
private static final String key = "key";
private static final String contract = "contract";
public static String getJSON(String url) throws IOException {
Request request = new Request.Builder().url(url).build();
Response response = client.newCall(request).execute();
return response.body().string();
}
private static String[] getStandName() {
String json = null;
try {
json = getJSON("https://api.jcdecaux.com/vls/v1/stations?contract=" + contract + "&apiKey=" + key);
} catch (IOException e) {
e.printStackTrace();
}
Gson gson = new Gson();
DBikesStation[] bikesAPI = gson.fromJson(json, DBikesStation[].class);
String[] bikeStands = new String[bikesAPI.length];
for (int i = 0; i < bikesAPI.length; ++i) {
bikeStands[i] = bikesAPI[i].getName();
}
;
return bikeStands;
}
我收到以下错误...
java.lang.RuntimeException:无法启动活动 ComponentInfo {包...... dublinbikes.ListBikeStands}: android.os.NetworkOnMainThreadException
我确实将ListBikeStands作为AndroidManifest.xml中的一个活动。
非常感谢任何帮助。谢谢。
答案 0 :(得分:1)
您正在主线程中设置适配器。在适配器中,您正在调用方法&#34; getJSON()&#34;它做了一些网络。但是,您不能在主线程上进行联网。你需要在一个单独的线程中获取JSON - 使用Asynctask(在&#34中获取JSON; doInBackground()&#34;然后在&#34; onPostExecute()&#34;)中设置适配器<) / p>
答案 1 :(得分:1)
您对OkHTTPClient的使用并不完全正确。您已在UI线程上发出同步请求,因此您的错误。
public static String getJSON(String url) throws IOException {
Request request = new Request.Builder().url(url).build();
Response response = client.newCall(request).execute();
return response.body().string();
}
为了发出异步请求,在后台尝试这样的事情。传递Callback
并使用enqueue
。
重要提示:如果您认为在异步方法中需要return
,则通常不正确。看到我将方法更改为void
类型。回调是return
变量的方法。
public static void getJSON(String url, Callback callback) throws IOException {
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(callback);
}
要调用它,请定义回调 - 在此处显示为变量,但也可以在方法调用中内嵌,就像View.OnClickListner
将用于按钮一样。
您应该在Activity类中定义它,因为您将更新适配器。
final Callback bikeStandCallback = new Callback() {
@Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
String body = response.body().string();
Gson gson = new Gson();
DBikesStation[] bikesAPI = gson.fromJson(body, DBikesStation[].class);
for (int i = 0; i < bikesAPI.length; ++i) {
adapter.add(bikesAPI[i].getName());
}
}
};
在你需要的时候传递它。
public class ListBikeStands extends ListActivity {
private ListView listStands;
private ArrayAdapter<String> listAdapter;
// TODO: Define above bikeStandCallback here
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listStands = getListView();
ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1);
listStands.setAdapter(listAdapter);
// TODO: Get url value
BikeStands.getJSON(url, bikeStandCallback);
}
}
而且,在我看来,这是非常灵活的,因为您可以为各种数据定义多个回调,再次使用不同的参数调用BikeStands.getJSON
,然后对该请求执行任何操作。
总的来说,这有点像Retrofit所做的,除了可以为你添加Gson转换器。
答案 2 :(得分:0)
当您填充适配器但是因为您尝试在主线程上进行网络操作时,不会抛出您获得的错误。
您必须在其他线程上进行网络操作,您可以使用AsyncTask,您可以在this question
中找到有关该错误的其他信息主线程上的网络被禁止,因为它通常是异步和资源密集型的,所以它可能会生成一个ANR(应用程序没有响应)