#flutter #dart
Вопрос:
Это мой первый месяц в качестве программиста. Я пытаюсь разработать приложение «близлежащие места». Когда я использовал следующие коды, я получал ошибку «оператор проверки null, используемый для нулевого значения». Но на основании того, что я вижу, или когда я напечатал URL и проверил вручную, или когда я использовал условие if, я не вижу проблем или ошибок. Как раз когда я визуализировал экран, я получил эту ошибку. Я хотел бы спросить, может ли кто-нибудь указать мне, в чем дело ? Заранее спасибо!
Строка, в которой я получаю ошибку, — это LocationName: locationSuggestion!.запрос.страницы[0]!.заголовок. Вероятностно и в соответствии с классом определения местоположения.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_udemy_examples/http_api_data/get_location_data_final.dart';
import 'package:flutter_udemy_examples/http_api_data/get_location_names.dart';
import 'package:flutter_udemy_examples/screens/login_ekrani.dart';
import 'package:flutter_udemy_examples/screens/map_screen.dart';
import 'login_ekrani.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../banner.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_udemy_examples/http_api_data/get_location_images.dart';
// ignore: must_be_immutable
class HomeScreen extends StatefulWidget {
@override
State<HomeScreen> createState() => HomeScreenState();
}
class HomeScreenState extends State<HomeScreen> {
LocationDataFinal? locationSuggestion;
bool isLoading = true;
@override
void initState() {
super.initState();
asyncInitState();
}
Future<void> asyncInitState() async {
await fecthlocationData();
}
Future fecthlocationData() async {
var locations = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
final double enlem = locations.latitude;
final double boylam = locations.longitude;
final url = Uri.parse(
"https://en.wikipedia.org/w/api.php?action=queryamp;format=jsonamp;prop=coordinates|pageimages|description|extractsamp;generator=geosearchamp;piprop=originalamp;descprefersource=centralamp;exlimit=20amp;exintro=1amp;explaintext=1amp;exsectionformat=plainamp;ggscoord=${enlem}|${boylam}amp;ggsradius=10000");
print(url);
final response = await http.get(url);
//print(response.body);
if (response.statusCode == 200) {
locationSuggestion = await locationDataFinalFromJson(response.body);
if (locationSuggestion != null) {
setState(() {
isLoading = false;
});
} else {
print("null1");
}
} else {
print("null2");
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: _buildAppBar(context),
body: isLoading
? Center(
child: CircularProgressIndicator(),
)
: ListView(
children: [
MyBanner(
// info: locationSuggestion!.query.pages[0]!.description,
locationName: locationSuggestion!.query.pages[0]!.title,
imagePath:
locationSuggestion!.query.pages[0]!.original.source,
context: context,
),
MyBanner(
//info: locationSuggestion!.query.pages[1]!.description,
locationName: locationSuggestion!.query.pages[1]!.title,
imagePath:
locationSuggestion!.query.pages[1]!.original.source,
context: context,
),
MyBanner(
// info: locationSuggestion!.query.pages[2]!.description,
locationName: locationSuggestion!.query.pages[2]!.title,
imagePath:
locationSuggestion!.query.pages[2]!.original.source,
context: context,
),
MyBanner(
// info: locationSuggestion!.query.pages[3]!.description,
locationName: locationSuggestion!.query.pages[3]!.title,
imagePath:
locationSuggestion!.query.pages[3]!.original.source,
context: context,
),
MyBanner(
// info: locationSuggestion!.query.pages[4]!.description,
locationName: locationSuggestion!.query.pages[4]!.title,
imagePath:
locationSuggestion!.query.pages[4]!.original.source,
context: context,
),
],
),
);
}
AppBar _buildAppBar(BuildContext context) {
return AppBar(
automaticallyImplyLeading: false,
leading: RotatedBox(
quarterTurns: 2,
child: _buildExitButton(context),
),
actions: [
_buildOpenMapButton(),
_buildCallEmergencyNumberButton(),
],
titleSpacing: 25,
shadowColor: Colors.white,
elevation: 0.0,
backgroundColor: Colors.blue[800],
//titleSpacing: Padding(padding: EdgeInsets.fromLTRB(25.85.0, 0, 25.85.0, 0)),
title: Text("Traveler Doctor"),
);
}
Widget _buildCallEmergencyNumberButton() {
return IconButton(
disabledColor: Colors.red,
color: Colors.red,
icon: Icon(Icons.phone_enabled),
tooltip: "Local emergency number",
onPressed: null,
);
}
Widget _buildOpenMapButton() {
return IconButton(
disabledColor: Colors.orangeAccent,
color: Colors.limeAccent,
icon: Icon(Icons.map_rounded),
tooltip: "Map",
enableFeedback: false,
onPressed: () => {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) => MapScreen()))
},
);
}
}
Widget _buildExitButton(BuildContext context) {
return IconButton(
onPressed: () async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('KullaniciAdi', "");
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (BuildContext context) => LoginEkrani()));
},
icon: Icon(
Icons.exit_to_app,
color: Colors.red,
),
tooltip: "Exit",
);
}
И это модель, которую я использую для анализа ответа api
import 'dart:convert';
LocationDataFinal locationDataFinalFromJson(String str) =>
LocationDataFinal.fromJson(json.decode(str));
class LocationDataFinal {
LocationDataFinal({
required this.batchcomplete,
required this.query,
});
String batchcomplete;
Query query;
factory LocationDataFinal.fromJson(Map<String, dynamic> json) =>
LocationDataFinal(
batchcomplete: json["batchcomplete"],
query: Query.fromJson(json["query"]),
);
}
class Query {
Query({
required this.pages,
});
Map<String, Page> pages;
factory Query.fromJson(Map<String, dynamic> json) => Query(
pages: Map.from(json["pages"])
.map((k, v) => MapEntry<String, Page>(k, Page.fromJson(v))),
);
}
class Page {
Page({
required this.pageid,
required this.ns,
required this.title,
required this.index,
required this.coordinates,
required this.original,
required this.description,
required this.descriptionsource,
required this.extract,
});
int pageid;
int ns;
String title;
int index;
List<Coordinate> coordinates;
Original original;
String description;
String descriptionsource;
String extract;
factory Page.fromJson(Map<String, dynamic> json) => Page(
pageid: json["pageid"],
ns: json["ns"],
title: json["title"],
index: json["index"],
coordinates: List<Coordinate>.from(
json["coordinates"].map((x) => Coordinate.fromJson(x))),
original: json["original"] == null
? Original(
source:
"https://tigres.com.tr/wp-content/uploads/2016/11/orionthemes-placeholder-image-1.png",
width: 300,
height: 200)
: Original.fromJson(json["original"]),
description: json["description"] == null ? "asd" : json["description"],
descriptionsource:
json["descriptionsource"] == null ? " " : json["descriptionsource"],
extract: json["extract"],
);
}
class Coordinate {
Coordinate({
required this.lat,
required this.lon,
required this.primary,
required this.globe,
});
double lat;
double lon;
String primary;
Globe globe;
factory Coordinate.fromJson(Map<String, dynamic> json) => Coordinate(
lat: json["lat"].toDouble(),
lon: json["lon"].toDouble(),
primary: json["primary"],
globe: globeValues.map[json["globe"]]!,
);
}
enum Globe { EARTH }
final globeValues = EnumValues({"earth": Globe.EARTH});
class Original {
Original({
required this.source,
required this.width,
required this.height,
});
String source;
int width;
int height;
factory Original.fromJson(Map<String, dynamic> json) => Original(
source: json["source"],
width: json["width"],
height: json["height"],
);
}
class EnumValues<T> {
late Map<String, T> map;
late Map<T, String> reverseMap;
EnumValues(this.map);
}
Я буду часто проверять этот пост.
Еще раз заранее спасибо.
Искренне ваш программист-нуб.
Ответ №1:
Я бы оставил это в качестве комментария, но, по-видимому, у меня достаточно репутации, чтобы писать ответы.
На страницах объекта запроса есть a Map<String, Page>
, но вы обращаетесь к нему с помощью ключа int: locationSuggestion!.query.pages[0]!.title
Чтобы получить доступ к карте с помощью ключа int, он должен быть Map<int,Page>
(или List<Page>
)
Комментарии:
1. Привет @Pat9RB Thnx за твой ответ! ` factory LocationDataFinal.FromJSON(Карта<Строка, динамический> json) =<Строка, динамический>> LocationDataFinal( пакетное выполнение: json[«пакетное выполнение»], запрос: Запрос.Из json(json[«запрос»])», решения ur, похоже, улучшаются, но на этот раз раздел кода, который я привел вверху, выдает ошибку. Например, «»_TypeError (тип «_InternalLinkedHashMap<Строка, динамическая>» не является подтипом типа » Карта<Строка, динамическая><int, динамическая>»)»» Есть идеи ?
2. Dart::преобразование json.decode() преобразует json в отображение<Строка,динамическая>. Если вы хотите использовать значения как какой-то другой тип, вам нужно его преобразовать. Например, если у вас есть json {«метка»: «значение»}, а затем вы хотите использовать «значение» в качестве строки, вам нужно будет привести его: Сопоставить<String, dynamic> json = json.decode(‘{«метка»: «значение»}’); Строка myString = json[«метка»] в качестве строки; Если вы можете опубликовать пример своего json (или пример URL-адреса, который вы используете для его извлечения с заполненными значениями) Я, вероятно, смогу больше помочь в том, как получить к нему доступ.
3. Спасибо за ваше терпение! это URL-адрес api, с которого я получаю данные. Если бы я преобразовал страницы в список вместо карты, это решило бы проблему ? Поскольку каждый элемент страниц-это карта ? ссылка
4. Вы могли бы сохранить существующую реализацию
pages
какMap<String, Page>
и, вместо вызоваlocationSuggestion!.query.pages[0]!.title
, позвонитьlocationSuggestion!.query.pages.entries.first.value.title
. Обратите внимание, что,Iterable.first
возвращает тип, не допускающий значения null, но будет выдаватьStateError
значение, если оно пустое, поэтому стоит убедитьсяlocationSuggestion!.query.pages.isNotEmpty
, прежде чем обращаться к нему.5. Глядя на ваш источник JSON, «страницы» преобразуются в a
Map<String,Map<String,dynamic>>
, потому что «страницы» — это объект ( «{}» ), содержащий множество объектов. Вы можете получитьList
ключи , содержащиеся в разделе «страницы», с помощьюpages.keys
и получить доступ к каждому дочернему объекту страницы, напримерpages[pages.keys[0]]
. Сохраните все на карте<String, dynamic> (не на карте<String, dynamic><Int,…>) и попробуйте получить доступ к разным страницам с помощьюlocationSuggestion!.query.pages[pages.keys[0]]
Ответ №2:
Несколько я решил проблему, заменив locationSuggestion!.query.pages[0]!.title
на
locationSuggestion!.query.pages.values.elementAt(0).title
Этот способ решения проблемы решил для меня 🙂