Java 如何在android中异步读取JSON并使用其数据?
我试图从一个链接下载代码,名为JSONJSON-link:并呈现它。代码如下:Java 如何在android中异步读取JSON并使用其数据?,java,android,android-asynctask,Java,Android,Android Asynctask,我试图从一个链接下载代码,名为JSONJSON-link:并呈现它。代码如下: public class FetchJSON extends AsyncTask<Void,Void,Void> { String data = ""; String id, name, address, lat, lng, type = ""; @Override protected Void doInBackground(Void... voids) {
public class FetchJSON extends AsyncTask<Void,Void,Void> {
String data = "";
String id, name, address, lat, lng, type = "";
@Override
protected Void doInBackground(Void... voids) {
Log.i("", "TEST");
try {
URL url = new URL("https://api.myjson.com/bins/ehzqu");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = "";
while(line!=null){
line = bufferedReader.readLine();
data = data + line;
}
Log.i("", "TEST2");
JSONArray JA = new JSONArray(data);
for( int i = 0 ; i < JA.length();i++)
{
JSONObject JO = (JSONObject) JA.get(i);
//Log.i("", JO.toString());
id = (String) JO.get("id");
name = (String) JO.get("name");
address = (String) JO.get("address");
lat = JO.get("lat").toString();
lng = JO.get("lng").toString();
Log.i("JSON Values", lat + " " + lng); //////////////////////////
type = (String) JO.get("type");
}
Log.i("", "TEST3");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
TrackDifferentLocation.data.setText(this.data);
super.onPostExecute(aVoid);
}
public void printLat()
{
Log.i("", lat);
}
public String getLat (){
return lat;
}
public String getLng (){
return lng;
}
public String getName (){
return name;
}
public String getAddress (){
return address;
}
public String getID (){
return id;
}
public String getType (){
return type;
}
}
但是在运行这段代码时,android上的应用程序崩溃了
如果我将纬度和经度硬编码为getLat/getLng函数中设置的数字,那么代码工作得很好。请注意,我已删除此问题的导入和包名称
编辑:
公共类TrackDifferentitLocation扩展了AppCompativeActivity在MapReadyCallback上的实现{
私有谷歌地图;
LatLng mLatlng;
字符串json_字符串;
公共静态文本视图数据;
LatLng LatLng=null;
@凌驾
受保护的void onCreate Bundle savedInstanceState{
super.onCreatesavedInstanceState;
//Toast.makeTextthis,跟踪位置…,Toast.LENGTH\u LONG.show;
setContentViewR.layout.activity\u track\u其他位置;
SupportMapFragment mapFragment=SupportMapFragment getSupportFragmentManager
.findFragmentByIdR.id.map_片段;
mapFragment.getMapAsyncthis;
getSupportActionBar.setDisplayShowHomeEnabledtrue;
getSupportActionBar.SetDisplayHomeAsupabledTrue;
//new FetchJSON.execute;//语法无效
FetchJSON f=新的FetchJSON;
}
@凌驾
谷歌地图上的公共空白{
mMap=谷歌地图;
Log.i,已于4月1日;
显示标记;
}
私有无效显示标记{
ifmMap==null返回;
ifmLatlng==null返回;
mMap.addMarkernew MarkerOptions.positionmLatlng;
}
//部分菜单见下文
@凌驾
公共布尔onCreateOptions菜单菜单{
getMenuInflater.inflateR.menu.menu,menu;
返回super.onCreateOptions菜单;
}
@凌驾
公共布尔值OnOptions ItemSelectedMenuItem项{
int id=item.getItemId;
如果id==android.R.id.home{
//结束活动
这是我的终点;
}
开关item.getItemId{
案例R.id.mapTypeNone:
mMap.setMapTypeGoogleMap.MAP_TYPE_NONE;
打破
案例R.id.mapTypeNormal:
mMap.setMapTypeGoogleMap.MAP_TYPE_NORMAL;
打破
案例R.id.mapTypeTerrain:
mMap.setMapTypeGoogleMap.MAP\u TYPE\u地形;
打破
案例R.id.mapTypeSatellite:
mMap.setMapTypeGoogleMap.MAP_TYPE_卫星;
打破
案例R.id.mapTypeHybrid:
mMap.setMapTypeGoogleMap.MAP_TYPE_HYBRID;
打破
违约:
打破
}
返回super.on选项ItemSelectedItem;
}
类FetchJSON扩展异步任务{
字符串JSONStr=;
字符串名称,地址,类型=;
字符串lat=;
字符串lng=;
字符串id=;
//双lat,液化天然气;
内定;
double latDouble=-1;
双lngDouble=-1;
受保护的LatLng doInBackgroundString…args{
//LatLng LatLng=null;
试一试{
URL=新URLhttps://api.myjson.com/bins/ehzqu;
HttpURLConnection HttpURLConnection=HttpURLConnection url.openConnection;
InputStream InputStream=httpURLConnection.getInputStream;
BufferedReader BufferedReader=新的BufferedReadernew InputStreamReaderinputStream;
字符串行=;
while line!=null{
line=bufferedReader.readLine;
JSONStr=JSONStr+线路;
}
Log.i,TEST2;
JSONObject obj=新的JSONObject JSONSTR;
JSONArray数组=obj.getJSONArrayserver响应;
对于int i=0;i@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
Log.i("", "onMapReady()");
FetchJSON f = new FetchJSON(mMap);
}
并在已知纬度和经度时在FetchJSON中设置标记:
@Override
protected Void doInBackground(Void... voids) {
....
lat = JO.get("lat").toString();
lng = JO.get("lng").toString();
type = (String) JO.get("type");
// Set the marker here:
double latitude = Double.valueOf(f.getLat());
double longitude = Double.valueOf(f.getLng());
LatLng latlng = new LatLng(latitude,longitude);
mMap.addMarker(new MarkerOptions().position(latlng));
....
}
或者更好的做法可能是在onPostExecute方法中执行,该方法在doInBackground方法之后调用:
另外,您没有正确读取JSON,您期望的是一个JSONArray,而实际上它是一个JSONObject,其中包含一个JSONArray。此示例适用于您在链接中获得的JSON:
String data = "{\"server response\":[{\"id\":\"991\",\"name\":\"GPSname\",\"address\":\"GPSaddress\",\"lat\":\"52.948616\",\"lng\":\"-1.169131\",\"type\":\"GPStype\"}]}";
Log.i("TAG", data);
String id, name, address, lat, lng, type;
try {
JSONObject json = new JSONObject(data);
JSONArray serverResponse = json.getJSONArray("server response");
for (int i = 0; i < serverResponse.length(); i++) {
JSONObject JO = (JSONObject) serverResponse.get(i);
id = (String) JO.get("id");
name = (String) JO.get("name");
address = (String) JO.get("address");
lat = JO.get("lat").toString();
lng = JO.get("lng").toString();
type = (String) JO.get("type");
Log.i("TAG", String.format(
"JSON Values: id=%s, name=%s, address=%s, lat=%s, lng=%s, type=%s",
id, name, address, lat, lng, type));
}
} catch (Exception e) {
Log.e("TAG", "exception", e);
}
FetchJSON是一个异步任务,因此当您尝试访问f.getLat时,它还没有值,因为任务尚未完成,您需要等待FetchJSON对象完成,然后再尝试访问getLat getter 我认为你可以按照以下思路做一些事情: 将映射传递给FetchJSON对象:
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
Log.i("", "onMapReady()");
FetchJSON f = new FetchJSON(mMap);
}
并在已知纬度和经度时在FetchJSON中设置标记:
@Override
protected Void doInBackground(Void... voids) {
....
lat = JO.get("lat").toString();
lng = JO.get("lng").toString();
type = (String) JO.get("type");
// Set the marker here:
double latitude = Double.valueOf(f.getLat());
double longitude = Double.valueOf(f.getLng());
LatLng latlng = new LatLng(latitude,longitude);
mMap.addMarker(new MarkerOptions().position(latlng));
....
}
或者更好的做法可能是在onPostExecute方法中执行,该方法在doInBackground方法之后调用:
另外,您没有正确读取JSON,您期望的是一个JSONArray,而实际上它是一个JSONObject,其中包含一个JSONArray。此示例适用于您在链接中获得的JSON:
String data = "{\"server response\":[{\"id\":\"991\",\"name\":\"GPSname\",\"address\":\"GPSaddress\",\"lat\":\"52.948616\",\"lng\":\"-1.169131\",\"type\":\"GPStype\"}]}";
Log.i("TAG", data);
String id, name, address, lat, lng, type;
try {
JSONObject json = new JSONObject(data);
JSONArray serverResponse = json.getJSONArray("server response");
for (int i = 0; i < serverResponse.length(); i++) {
JSONObject JO = (JSONObject) serverResponse.get(i);
id = (String) JO.get("id");
name = (String) JO.get("name");
address = (String) JO.get("address");
lat = JO.get("lat").toString();
lng = JO.get("lng").toString();
type = (String) JO.get("type");
Log.i("TAG", String.format(
"JSON Values: id=%s, name=%s, address=%s, lat=%s, lng=%s, type=%s",
id, name, address, lat, lng, type));
}
} catch (Exception e) {
Log.e("TAG", "exception", e);
}
链接中显示的数据不是JSONArray {服务器 回复:[{id:991,名称:GPSname,地址:GPSaddress,lat:52.948616,lng:-1.169131,类型:GPStype}]} 它是一个带有JSONArray子对象的JSONObject 编辑 为Latlng值创建一个类变量 Latlng mLatlng 现在,在onCreate方法中添加: 装载位置 以下是新代码:
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
displayMarker();
}
private void loadLocation() {
new FetchJSON().execute();
}
class FetchJSON extends AsyncTask<String, Integer, LatLng> {
@Override
protected LatLng doInBackground(String... params) {
LatLng latLng = null;
try {
URL url = new URL("https://api.myjson.com/bins/ehzqu");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close();
String json = stringBuilder.toString();
Log.e(TAG, "Return = " + json);
String lat= "";
String lng= "";
JSONObject obj = new JSONObject(json);
JSONArray array = obj.getJSONArray("server response");
for(int i = 0; i < array.length(); i++){
JSONObject o = array.getJSONObject(i);
lat = o.optString("lat");
lng = o.optString("lng");
}
Log.e(TAG, "Lat = " + lat);
Log.e(TAG, "lng = " + lng);
double latDouble = Double.parseDouble(lat);
double lngDouble = Double.parseDouble(lng);
latLng = new LatLng(latDouble, lngDouble);
}
catch (Exception ex) {
Log.e(TAG, "doInBackground --- " + ex.getMessage());
}
return latLng;
}
@Override
protected void onPostExecute(LatLng latLng) {
try{
if(latLng != null){
mLatLng = latLng;
displayMarker();
}
}
catch(Exception ex){
Log.e(TAG, "onPostExecute" + ex.getMessage());
}
}
}
private void displayMarker(){
if(mMap == null) return;
if(mLatLng == null) return;
MarkerOptions markerOption = new MarkerOptions();
markerOption.position(mLatLng);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mLatLng, zoomFactor));
mMap.addMarker(markerOption);
}
在我的设备上显示的结果:
当你的谷歌地图准备好后,它将调用displayMarkers。如果由于FetchJSON未完成而导致mLatLng为null,则不会发生任何事情
您可以按照建议从onMapReady方法调用FetchJSON,但是为什么不在系统准备好GoogleMap时在后台线程中下载数据呢?您在链接中显示的数据不是JSONArray {服务器 回复:[{id:991,名称:GPSname,地址:GPSaddress,lat:52.948616,lng:-1.169131,类型:GPStype}]} 它是一个带有JSONArray子对象的JSONObject 编辑 为Latlng值创建一个类变量 Latlng mLatlng 现在,在onCreate方法中添加: 装载位置 以下是新代码:
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
displayMarker();
}
private void loadLocation() {
new FetchJSON().execute();
}
class FetchJSON extends AsyncTask<String, Integer, LatLng> {
@Override
protected LatLng doInBackground(String... params) {
LatLng latLng = null;
try {
URL url = new URL("https://api.myjson.com/bins/ehzqu");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close();
String json = stringBuilder.toString();
Log.e(TAG, "Return = " + json);
String lat= "";
String lng= "";
JSONObject obj = new JSONObject(json);
JSONArray array = obj.getJSONArray("server response");
for(int i = 0; i < array.length(); i++){
JSONObject o = array.getJSONObject(i);
lat = o.optString("lat");
lng = o.optString("lng");
}
Log.e(TAG, "Lat = " + lat);
Log.e(TAG, "lng = " + lng);
double latDouble = Double.parseDouble(lat);
double lngDouble = Double.parseDouble(lng);
latLng = new LatLng(latDouble, lngDouble);
}
catch (Exception ex) {
Log.e(TAG, "doInBackground --- " + ex.getMessage());
}
return latLng;
}
@Override
protected void onPostExecute(LatLng latLng) {
try{
if(latLng != null){
mLatLng = latLng;
displayMarker();
}
}
catch(Exception ex){
Log.e(TAG, "onPostExecute" + ex.getMessage());
}
}
}
private void displayMarker(){
if(mMap == null) return;
if(mLatLng == null) return;
MarkerOptions markerOption = new MarkerOptions();
markerOption.position(mLatLng);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mLatLng, zoomFactor));
mMap.addMarker(markerOption);
}
在我的设备上显示的结果:
当你的谷歌地图准备好后,它将调用displayMarkers。如果由于FetchJSON未完成而导致mLatLng为null,则不会发生任何事情
您可以按照建议从onMapReady方法调用FetchJSON,但是为什么不在系统准备好GoogleMap时在后台线程中下载数据呢?请提供stack traceFetchJSON是一个异步任务,因此当您尝试访问f.getLat时,它还没有值,因为任务尚未完成,在尝试访问getLat getter之前,您需要等待FetchJSON对象完成。我非常确定这是java,不是javascript。请您提供一个带有修复的答案,以便我可以标记它fixed@JackGiffin正确,自动更正在我发布时为我更改了它请提供堆栈traceFetchJSON是一个异步任务,因此,当您尝试访问f.getLat时,它还没有值,因为任务尚未完成,您需要等待FetchJSON对象完成,然后再尝试访问getLat getter。我非常确定这是java,而不是javascript。请您提供一个解决方案,以便我可以标记它fixed@JackGiffin对的“自动更正”在我发布Hi时为我更改了它,好吧,所以你给了我一个想法。我在对象初始化结束时创建了一个双lngdouble和latdouble。然后设置一个while循环,使其在值被填充之前不执行任何操作。这最终使地图能够正常工作而不会崩溃。现在的问题是,他们将lat和lon分别设置为0,从而将标记放置在错误的位置。我如何从JSON存储lat和lon有问题吗?下面是一个指向JSON的链接:@JamesDoh96我在JSON解析中添加了一点,以正确提取值。@JamesDoh96使用AsyncTask.onPostExecute更新了我的答案,这可能是这里的最佳做法。好的,你给了我一个主意。我在对象初始化结束时创建了一个双lngdouble和latdouble。然后设置一个while循环,使其在值被填充之前不执行任何操作。这最终使地图能够正常工作而不会崩溃。现在的问题是,他们将lat和lon分别设置为0,从而将标记放置在错误的位置。我如何从JSON存储lat和lon有问题吗?下面是指向JSON的链接:@JamesDoh96我在JSON解析中添加了一点,以正确提取值。@JamesDoh96 update
使用AsyncTask.onPostExecute(这可能是这里的最佳实践)编辑我的答案嗨,感谢您的回复-我已将代码更新为您的代码,但在运行emulator时,nexus 6会加载映射,但其位置为-1,0,-1,0。我在do inbackground中硬编码了一个latDouble=-5,它仍然显示-1.0,-1.0-所以我不认为它在运行?这并不不幸,这真的令人沮丧!我想我的问题是我的调试器。一分钟前,一切正常,logcat等等。另外,我的数据字符串通过httpconnection(打印到logcat的JSON数组)接收JSON。现在,在我的日志中没有发生任何事情,或者在我使用调试程序时没有发生任何事情。很难连接到应用程序。现在查看代码-行.execute似乎不是有效的行?另外,DisplayMarkers方法—您是否将其放在DetchJSON活动/类或TrackDifferentLocation活动/类中?但是你所做的一切都是有道理的还有,你得到了什么结果?结果本身似乎不是一个有效的变量!对于.execute问题,我使用FetchJSON f=newfetchjson启动;您好,感谢您的回复-我已经将我的代码更新为您的代码,但是在运行emulator时,Nexus6会加载映射,但它位于-1,0,-1,0。我在do inbackground中硬编码了一个latDouble=-5,它仍然显示-1.0,-1.0-所以我不认为它在运行?这并不不幸,这真的令人沮丧!我想我的问题是我的调试器。一分钟前,一切正常,logcat等等。另外,我的数据字符串通过httpconnection(打印到logcat的JSON数组)接收JSON。现在,在我的日志中没有发生任何事情,或者在我使用调试程序时没有发生任何事情。很难连接到应用程序。现在查看代码-行.execute似乎不是有效的行?另外,DisplayMarkers方法—您是否将其放在DetchJSON活动/类或TrackDifferentLocation活动/类中?但是你所做的一切都是有道理的还有,你得到了什么结果?结果本身似乎不是一个有效的变量!对于.execute问题,我使用FetchJSON f=newfetchjson启动;