I am trying to make a pokemon app. But I get this error:
"The getter 'pokemon' was called on null.
Receiver: null
Tried calling: pokemon"
I am putting error page to here.
I am using this API url for data "https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json"
And my Pokemon class is here:**
class Pokedex {
List<Pokemon> pokemon;
Pokedex({
this.pokemon});
Pokedex.fromJson(dynamic json) {
if (json["pokemon"] != null) {
pokemon = [];
json["pokemon"].forEach((v) {
pokemon.add(Pokemon.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
var map = <String, dynamic>{};
if (pokemon != null) {
map["pokemon"] = pokemon.map((v) => v.toJson()).toList();
}
return map;
}
}
class Pokemon {
int id;
String num;
String name;
String img;
List<String> type;
String height;
String weight;
String candy;
int candyCount;
String egg;
double spawnChance;
int avgSpawns;
String spawnTime;
List<double> multipliers;
List<String> weaknesses;
List<Next_evolution> nextEvolution;
Pokemon({
this.id,
this.num,
this.name,
this.img,
this.type,
this.height,
this.weight,
this.candy,
this.candyCount,
this.egg,
this.spawnChance,
this.avgSpawns,
this.spawnTime,
this.multipliers,
this.weaknesses,
this.nextEvolution});
Pokemon.fromJson(dynamic json) {
id = json["id"];
num = json["num"];
name = json["name"];
img = json["img"];
type = json["type"] != null ? json["type"].cast<String>() : [];
height = json["height"];
weight = json["weight"];
candy = json["candy"];
candyCount = json["candy_count"];
egg = json["egg"];
spawnChance = json["spawn_chance"];
avgSpawns = json["avg_spawns"];
spawnTime = json["spawn_time"];
multipliers = json["multipliers"] != null ? json["multipliers"].cast<double>() : [];
weaknesses = json["weaknesses"] != null ? json["weaknesses"].cast<String>() : [];
if (json["next_evolution"] != null) {
nextEvolution = [];
json["next_evolution"].forEach((v) {
nextEvolution.add(Next_evolution.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
var map = <String, dynamic>{};
map["id"] = id;
map["num"] = num;
map["name"] = name;
map["img"] = img;
map["type"] = type;
map["height"] = height;
map["weight"] = weight;
map["candy"] = candy;
map["candy_count"] = candyCount;
map["egg"] = egg;
map["spawn_chance"] = spawnChance;
map["avg_spawns"] = avgSpawns;
map["spawn_time"] = spawnTime;
map["multipliers"] = multipliers;
map["weaknesses"] = weaknesses;
if (nextEvolution != null) {
map["next_evolution"] = nextEvolution.map((v) => v.toJson()).toList();
}
return map;
}
}
class Next_evolution {
String num;
String name;
Next_evolution({
this.num,
this.name});
Next_evolution.fromJson(dynamic json) {
num = json["num"];
name = json["name"];
}
Map<String, dynamic> toJson() {
var map = <String, dynamic>{};
map["num"] = num;
map["name"] = name;
return map;
}
}
And this is my main.dart file:
import 'package:flutter/material.dart';
import 'package:pokemon_api/pokemon_list.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PokemonList(),
);
}
}
And this is my pokemon_list.dart file:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'model/pokedex.dart';
class PokemonList extends StatefulWidget {
const PokemonList({Key key}) : super(key: key);
#override
_PokemonListState createState() => _PokemonListState();
}
class _PokemonListState extends State<PokemonList> {
String url =
"https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json";
Pokedex pokedex;
var response;
Future<Pokedex> PokemonlariGetir() async {
response= await http.get(Uri.parse(url)).then((value){
var decodedJson = json.decode(response.body);
pokedex = Pokedex.fromJson(decodedJson);
});
debugPrint(pokedex.toString());
return pokedex;
}
#override
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Pokemon"),
),
body: FutureBuilder(
future: PokemonlariGetir(),
builder: (context, AsyncSnapshot<Pokedex> gelenPokedex) {
if (gelenPokedex.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else if (gelenPokedex.connectionState==ConnectionState.done) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2),
itemBuilder: (context,index){
return Text(gelenPokedex.data.pokemon[index].name);
});
// return GridView.count(crossAxisCount: 2,children:gelenPokedex.data.pokemon.map((poke){
// return Text(poke.name);
// }).toList(),);
}else{
return Center(child: CircularProgressIndicator(),);
}
}),
);
}
}
Related
I got this error on terminal
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY
╞═══════════════════════════════════════════════════════════ The
following TypeErrorImpl was thrown building GameScreen(dirty,
dependencies: [_InheritedProviderScope<RoomDataProvider?>], state:
_GameScreenState#df23f): type 'Null' is not a 'bool' in boolean expression The relevant error-causing widget was: GameScreen
This is my code:
import 'package:flutter/material.dart';
import 'package:game/provider/room_data_provider.dart';
import 'package:game/resources/socket_method.dart';
import 'package:provider/provider.dart';
import '../viiews/waiting_lobby.dart';
class GameScreen extends StatefulWidget {
static String routeName = '/game';
const GameScreen({Key? key}) : super(key: key);
#override
State<GameScreen> createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> {
final SocketMethods _socketMethods = SocketMethods();
#override
void initState() {
super.initState();
_socketMethods.updateRoomListener(context);
_socketMethods.updatePlayerStateListener(context);
// _socketMethods.pointIncreaseListener(context);
// _socketMethods.endGameListener(context);
}
#override
Widget build(BuildContext context) {
RoomDataProvider roomDataProvider = Provider.of<RoomDataProvider>(context);
return Scaffold(
body: roomDataProvider.roomData['isJoin']
? const WaitingLobby()
: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
// const Scoreboard(),
// const TicTacToeBoard(),
Text(
'${roomDataProvider.roomData['turn']['nickname']}\'s turn'),
],
),
),
);
}
}
room_data_provider.dart
import 'package:flutter/material.dart';
import 'package:game/models/player.dart';
class RoomDataProvider extends ChangeNotifier {
Map<String, dynamic> _roomData = {};
Player _player1 =
Player(nickname: "", socketID: "", points: 0, playerType: "X");
Player _player2 =
Player(nickname: "", socketID: "", points: 0, playerType: "O");
Map<String, dynamic> get roomData => _roomData;
Player get player1 => _player1;
Player get player2 => _player2;
void updateRoomData(Map<String, dynamic> data) {
_roomData = data;
notifyListeners();
}
void updatePlayer1(Map<String, dynamic> player1Data) {
_player1 = Player.fromMap(player1Data);
notifyListeners();
}
void updatePlayer2(Map<String, dynamic> player2Data) {
_player2 = Player.fromMap(player2Data);
notifyListeners();
}
}
index.js
socket.on("joinRoom", async ({ nickname, roomId }) => {
try {
if (!roomId.match(/^[0-9a-fA-F]{24}$/)) {
socket.emit("errorOccurred", "Please enter a valid room ID.");
return;
}
let room = await Room.findById(roomId);
if (room.isJoin) {
let player = {
nickname,
socketID: socket.id,
playerType: "O",
};
socket.join(roomId);
room.players.push(player);
room.isJoin = false;
room = await room.save();
io.to(roomId).emit("joinRoomSuccess", room);
io.to(roomId).emit("updatePlayers", room.players);
io.to(roomId).emit("updateRoom", room);
} else {
socket.emit(
"errorOccurred",
"The game is in progress, try again later."
);
}
} catch (e) {
console.log(e);
}
});
How can I solve this issue ?
Thanks for any help you can provide
I am invoking a method from native Swift code by using the platform channel like this:
channel.invokeMethod(METHOD_NAME, arguments: STRING_ARGUMENT)
in my Flutter class I handle the respective method call by using a callback
platform.setMethodCallHandler(_receiveFromHost);
The setMethodCallHandler() requires the callback to return a Future and I set state in _receiveFromHost method in Dart.
Problem is that my UI is not updated when Swift invokes the callback. Why?
call.method catch method string, state is set, but UI don't update.
video
This is my code in Swift:
let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
let flutterViewController = FlutterViewController(engine: flutterEngine!, nibName: nil, bundle: nil)
let channel = FlutterMethodChannel(name: "flutter_apple_pay", binaryMessenger: flutterViewController.binaryMessenger)
channel.invokeMethod("sendDidFinishAdding", arguments: "payment success")
And this is my code in Flutter:
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'dart:convert';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: const Text("Native Code from Dart"),
),
body: new MyHomePage(title: ""),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _state = "Waiting results...";
static const platform = const MethodChannel("flutter_apple_pay");
_MyHomePageState() {
platform.setMethodCallHandler(_receiveFromHost);
}
// #override
// void initState() {
// platform.setMethodCallHandler(_receiveFromHost);
// super.initState();
// }
Future<dynamic> _receiveFromHost(MethodCall call) async {
List certificatesBase64Encoded;
String nonceBase64Encoded;
String nonceSignatureBase64Encoded;
String state;
try {
print(call.method);
if (call.method == "sendGenerateRequestWithData") {
final String data = call.arguments;
final jData = jsonDecode(data);
certificatesBase64Encoded = jData['certificatesBase64Encoded'];
nonceBase64Encoded = jData['nonceBase64Encoded'];
nonceSignatureBase64Encoded = jData['nonceSignatureBase64Encoded'];
print(certificatesBase64Encoded);
print(nonceBase64Encoded);
print(nonceSignatureBase64Encoded);
state = "sendGenerateRequestWithData";
platform.invokeMethod("SendTokenizationData", "TokenizationDataString");
} else if (call.method == "sendDidFinishAdding") {
final String result = call.arguments;
print(result);
state = result;
}
} on PlatformException catch (e) {
print(e);
}
setState(() {
_state = state;
});
print(_state);
}
Future<void> _checkCardState() async {
String cardState;
const primaryAccountIdentifiers = ["a", "b"];
try {
final String result = await platform.invokeMethod(
"checkCardState", primaryAccountIdentifiers);
cardState = result;
} on PlatformException catch (e) {
cardState = "Failed to Invoke: '${e.message}'.";
}
setState(() {
_state = cardState;
});
}
Future<void> _startApplePay() async {
const _cardNetwork = "cn/AMEX";
const _cardHolderName = "pero peric";
const _primaryAccountIdentifier = "a";
const _primaryAccountSuffix = "1234";
const _localizedDescription = "AMEX";
Map<String, dynamic> resultMap = Map();
resultMap['cardNetwork'] = _cardNetwork;
resultMap['cardHolderName'] = _cardHolderName;
resultMap['primaryAccountIdentifier'] = _primaryAccountIdentifier;
resultMap['primaryAccountSuffix'] = _primaryAccountSuffix;
resultMap['localizedDescription'] = _localizedDescription;
platform.invokeMethod("startApplePay", resultMap);
}
#override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
child: Text('Check Card State'),
onPressed: _checkCardState,
),
ElevatedButton(
child: Text('Start Apple Pay'),
onPressed: _startApplePay,
),
Text(_state),
],
),
),
);
}
}
Thanks!
I have JSON file below.
Data.json
[{
"rownum": 1,
"total": 10.99793271,
"total2": 106.65666751,
}, {
"rownum": 2,
"total": 10.99793271,
"total2": 106.65666751,
}]
and the class Item and List
List <Item> item;
class Item {
String row;
String total;
String total2;
Student({this.row, this.total, this.total2});
}
How can I get data from data.json and add them into List <Item> item on the initState()?
Like this
class MyAppState extends State<MyApp> {
#override
void initState() {
Future<String> _loadAStudentAsset() async {
return await rootBundle.loadString('assets/data.json');
}
//....some code to add value into list
super.initState();
}
That solution is also valid for you:
Flutter: How to display a short text file from assets on screen of phone?
If we make another example with same template:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
void main() {
runApp(Test());
}
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
Future _future;
Future<String> loadString() async =>
await rootBundle.loadString('assets/data.json');
#override
void initState() {
_future = loadString();
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: FutureBuilder(
future: _future,
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Text('Loading...');
}
List<dynamic> parsedJson = jsonDecode(snapshot.data);
items = parsedJson.map((element) {
return Item(
row: element['rownum'].toString(),
total: element['total'].toString(),
total2: element['total2'].toString(),
);
}).toList();
;
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return Column(
children: <Widget>[
Text(item.row),
Text(item.total),
Text(item.total2),
],
);
},
);
},
),
),
);
}
}
List<Item> items;
class Item {
String row;
String total;
String total2;
Item({this.row, this.total, this.total2});
}
class Item {
static final String db_row = "rownum";
static final String db_total = "total";
static final String db_total2 = "total2";
int row;
double total;
double total2;
Item({this.row, this.total, this.total2});
Item.fromMap(Map map) {
this.row = map[Item.db_row];
this.total = map[Item.db_total];
this.total2 = map[Item.db_total2];
}
Map toMap() =>
{Item.db_row: row, Item.db_total: total, Item.db_total2: total2};
static List<Item> fromMapList(mapList) {
List<Item> items = new List();
new List.from(mapList).forEach((mapItem) {
items.add(Item.fromMap(mapItem));
});
return items;
}
}
And
List <Item> items = Item.fromMapList(await rootBundle.loadString('assets/data.json'));
i am using the following function to retrive the UID:
FirebaseAuth auth = FirebaseAuth.instance;
getUID() async {
final FirebaseUser user = await auth.currentUser();
final uid = user.uid;
return uid;
}
After that, i would like to use the UID to acces the right database-doc:
return new StreamBuilder(
stream: Firestore.instance.collection('users').document(getUID()).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return new Text("Loading");
}
var userDocument = snapshot.data;
But i get the error
Future<dynamic> is not a subtype of type "string"
What is the right way to do it?
FULL CODE
class Settings extends StatelessWidget{
FirebaseAuth auth = FirebaseAuth.instance;
getUID() async {
final FirebaseUser user = await auth.currentUser();
final uid = user.uid;
return uid;
}
static GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Indstillinger"),
),
body: _buildSetting(context),
);
}
Widget _buildSetting(BuildContext context) {
return new StreamBuilder(
stream: Firestore.instance.collection('users').document(getUID()).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return new Text("Loading");
}
var userDocument = snapshot.data;
You need to use stateful widget, like
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
class Settings extends StatefulWidget {
#override
_SettingsState createState() {
return _SettingsState();
}
}
class _SettingsState extends State<Settings> {
FirebaseUser user;
String error;
void setUser(FirebaseUser user) {
setState(() {
this.user = user;
this.error = null;
});
}
void setError(e) {
setState(() {
this.user = null;
this.error = e.toString();
});
}
#override
void initState() {
super.initState();
FirebaseAuth.instance.currentUser().then(setUser).catchError(setError);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Indstillinger"),
),
body: user != null ? _buildSetting(context) : Text("Error: $error"),
);
}
Widget _buildSetting(BuildContext context) {
return new StreamBuilder(
stream: Firestore.instance.collection('users').document(user.uid).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return new Text("Loading");
}
var userDocument = snapshot.data;
// User userDocument here ..........
return new Text(userDocument.toString());
});
}
}
You're passing the function without actually awaiting for it to return. You could store the returned value in a variable before calling StreamBuilder.
final documentId = await getUID();
return new StreamBuilder(
stream: Firestore.instance.collection('users').document(documentId).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return new Text("Loading");
}
var userDocument = snapshot.data;
Here is my code:
I response key event in Android MainActivity, and use BasicMessageChannel to post key message:
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "scroll";
private static final String KEY_LEFT = "keyLeft";
private static final String KEY_RIGHT = "keyRight";
private BasicMessageChannel messageChannel;
private FlutterView flutterView;
private String[] getArgsFromIntent(Intent intent) {
// Before adding more entries to this list, consider that arbitrary
// Android applications can generate intents with extra data and that
// there are many security-sensitive args in the binary.
ArrayList<String> args = new ArrayList<String>();
if (intent.getBooleanExtra("trace-startup", false)) {
args.add("--trace-startup");
}
if (intent.getBooleanExtra("start-paused", false)) {
args.add("--start-paused");
}
if (intent.getBooleanExtra("enable-dart-profiling", false)) {
args.add("--enable-dart-profiling");
}
if (!args.isEmpty()) {
String[] argsArray = new String[args.size()];
return args.toArray(argsArray);
}
return null;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
flutterView = new FlutterView(this);
String[] args = getArgsFromIntent(getIntent());
FlutterMain.ensureInitializationComplete(getApplicationContext(), args);
flutterView.runFromBundle(FlutterMain.findAppBundlePath(getApplicationContext()), null);
messageChannel = new BasicMessageChannel<>(flutterView, CHANNEL, StringCodec.INSTANCE);
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
Log.d(TAG, "dispatchKeyEvent: ACTION_DOWN keyCode = " + event.getKeyCode());
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_LEFT:
messageChannel.send(KEY_LEFT);
return true;
case KeyEvent.KEYCODE_DPAD_RIGHT:
messageChannel.send(KEY_RIGHT);
return true;
default:
break;
}
}
return super.dispatchKeyEvent(event);
}
#Override
protected void onDestroy() {
if (flutterView != null) {
flutterView.destroy();
}
super.onDestroy();
}
#Override
protected void onPause() {
super.onPause();
flutterView.onPause();
}
#Override
protected void onPostResume() {
super.onPostResume();
flutterView.onPostResume();
}
}
When Flutter receives the message, I call nextPage() and previousPage() to scroll PageView, it doesn't work. But I find if I call nextPage() and previousPage() in onTap() method of the GestureDetector, it works:
class _Page {
_Page({
this.imagePath,
});
final String imagePath;
}
final List<_Page> _allPages = <_Page>[
new _Page(imagePath: 'images/1.jpg'),
new _Page(imagePath: 'images/2.jpg'),
new _Page(imagePath: 'images/3.jpg'),
new _Page(imagePath: 'images/4.jpg'),
new _Page(imagePath: 'images/5.jpg'),
new _Page(imagePath: 'images/6.jpg'),
];
class ScrollablePageDemo extends StatefulWidget {
#override
_ScrollablePageDemoState createState() => new _ScrollablePageDemoState();
}
class _ScrollablePageDemoState extends State<ScrollablePageDemo>
with SingleTickerProviderStateMixin {
PageController _controller;
static const String _channel = 'scroll';
static const String _emptyMessage = '';
static const String KEY_LEFT = "keyLeft";
static const String KEY_RIGHT = "keyRight";
static const BasicMessageChannel<String> platform =
const BasicMessageChannel<String>(_channel, const StringCodec());
#override
void initState() {
super.initState();
_controller = new PageController(
initialPage: 0, keepPage: true, viewportFraction: 1.0);
platform.setMessageHandler(changePage);
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
Future<String> changePage(String message) async {
setState(() {
print(message);
if (message == KEY_RIGHT) {
//here doesn't work
_controller.nextPage(duration: kTabScrollDuration, curve: Curves.ease);
print("tab right: page = " + _controller.page.toString());
} else if (message == KEY_LEFT) {
//here doesn't work
_controller.previousPage(duration: kTabScrollDuration, curve: Curves.ease);
print("tab left: page = " + _controller.page.toString());
}
});
return _emptyMessage;
}
PageView buildPageView() {
return new PageView(
controller: _controller,
children: _allPages.map((_Page page) {
return new Container(
key: new ObjectKey(page.imagePath),
padding: const EdgeInsets.all(12.0),
child: new Card(
child: new Image.asset(page.imagePath, fit: BoxFit.fill)));
}).toList(),
);
}
#override
Widget build(BuildContext context) {
return new GestureDetector(
onTap: () {
print('Listen PageView');
//here works
_controller.nextPage(duration: kTabScrollDuration, curve: Curves.ease);
},
child: new Scaffold(
appBar: new AppBar(
title: new Text('PageView'),
),
body: buildPageView()));
}
}
void main() {
runApp(new MaterialApp(
title: 'Flutter Study',
home: new ScrollablePageDemo(),
));
}
The problem is with setState method inside changePage. The setState invokes build method whenever the state set. Thus the page gets built again whenever setState called. You can just remove the setState from changePage method.
example:
Future<String> changePage(String message) async {
print(message);
if (message == KEY_RIGHT) {
_controller.nextPage(duration: kTabScrollDuration, curve: Curves.ease);
print("tab right: page = " + _controller.page.toString());
} else if (message == KEY_LEFT) {
_controller.previousPage(duration: kTabScrollDuration, curve: Curves.ease);
print("tab left: page = " + _controller.page.toString());
}
return _emptyMessage;
}
Hope that helped!