Konsep capaian data dari mobile app ke pangkalan data online melalui format JSON.
IDE: Tutorial Flutter berikut menggunakan IDE VSCode dengan Flutter plugins.
SERVER: Apache/PHP & MySQL (jana data format JSON)
Keperluan server/pangkalan data online
Data dalam server online perlu dijana dalam format JSON seperti rajah di bawah. Alamat URL data ada di https://khirulnizam.com/training/searchflutter.php
Jadual yang digunakan untuk simpan data: training
searchflutter.php
Kod untuk PHP berikut mengandungi arahan JSON_ENCODE untuk menjana data dari database kepada format JSON. (Kod lengkap di GITHUB)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
<?php header('Content-Type: application/json'); //to make json format pretty // code @GITHUB // bit.ly/gitjson // searchflutter.php include "connect.php"; //keyword if(!isset($_GET['key'])) $key=null; else $key=$_GET['key']; //generate JSON from table $traininglist= array(); $response=array(); $sql="SELECT id,trainingname,website, trainingdesc FROM a_training WHERE trainingname LIKE '%$key%' OR trainingdesc LIKE '%$key%' "; //run query $rs=mysqli_query($db,$sql); if($rs==false){ echo mysqli_error($rs); } //no record found if (mysqli_num_rows($rs)==0){ } else{//found some records while($rec=mysqli_fetch_array($rs)){ //capture one record $traininglist=array(); $traininglist["id"] = $rec["id"]; $traininglist["trainingname"] = $rec["trainingname"]; $traininglist["website"] = $rec["website"]; $traininglist["trainingdesc"] = $rec["trainingdesc"]; //push to response array_push($response, $traininglist); }//end while }//end found records //generate JSON encoded data //print_r $traininglist; echo json_encode($response); //output JSON format ?> |
Koding Dart/Flutter
pubspec.yaml
Terdapat tambahan kepada fail ini ;
- simple_permissions: “^0.1.2” //uses-permission capaian INTERNE
- http: ^0.12.0+1 //dart API plugin handle HTTP connection
-
url_launcher: ^5.0.0 //buka alamat URL webpage pada browser
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
name: flutter_json_fetch_data description: A new Flutter application. # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # Read more about versioning at semver.org. version: 1.0.0+1 # to allow internet uses-permission simple_permissions: "^0.1.2" environment: sdk: ">=2.0.0-dev.68.0 <3.0.0" dependencies: flutter: sdk: flutter http: ^0.12.0+1 #to add http service to apps url_launcher: ^5.0.0 #to provide webpage view # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2 dev_dependencies: flutter_test: sdk: flutter # For information on the generic Dart part of this file, see the # following page: https://www.dartlang.org/tools/pub/pubspec # The following section is specific to Flutter. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.io/assets-and-images/#resolution-aware. # For details regarding adding assets from package dependencies, see # https://flutter.io/assets-and-images/#from-packages # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.io/custom-fonts/#from-packages |
training.dart
Spesifikasi struktur data rekod TRAINING, yang mengandungi table dengan skema berikut
training(id, trainingname, trainingdesc, website)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Training { final String id; final String trainingname; final String website; final String trainingdesc; //this.website, //website: json['website'] as String, Training({this.id, this.trainingname, this.website, this.trainingdesc}); factory Training.fromJson(Map<String, dynamic> json) { return Training( id: json['id'] as String, trainingname: json['trainingname'] as String, website: json['website'] as String, trainingdesc: json['trainingdesc'] as String, ); } } |
listtraining.dart
Kod ini menjana ListItem dan populasikan ListView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
import 'package:flutter/material.dart'; import 'training.dart'; import 'package:url_launcher/url_launcher.dart'; class ListViewTrainings extends StatelessWidget { final List<Training> trainings; ListViewTrainings({Key key, this.trainings}) : super(key: key); @override Widget build(BuildContext context) { return Container( child: ListView.builder( itemCount: trainings.length, padding: const EdgeInsets.all(15.0), itemBuilder: (context, position) { return Column( children: <Widget>[ Divider(height: 5.0), ListTile( title: Text( '${trainings[position].trainingname}', style: TextStyle( fontSize: 22.0, color: Colors.deepOrangeAccent, ), ), subtitle: Text( '${trainings[position].trainingdesc}', style: new TextStyle( fontSize: 18.0, fontStyle: FontStyle.italic, ), ), leading: Column( children: <Widget>[ CircleAvatar( backgroundColor: Colors.blueAccent, radius: 35.0, child: Text( '${trainings[position].id}', style: TextStyle( fontSize: 22.0, color: Colors.white, ), ), ) ], ), //onTap: () => _onTapItem(context, trainings[position]) onTap: ()=> _launchURL('${trainings[position].website}'), ), ], ); }), ); } void _onTapItem(BuildContext context, Training training) { Scaffold .of(context) .showSnackBar( new SnackBar(content: new Text(training.id + ' - ' + training.trainingname)) ); } _launchURL(String website) async { String url = website; if (await canLaunch(url)) { await launch(url); } else { throw 'Could not launch $url'; } } } |
main.dart
Fail dart utama untuk set appTitle dan theme
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
import 'package:flutter/material.dart'; import 'home.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { final appTitle = 'TrainingFSTM'; return MaterialApp( title: appTitle, theme: ThemeData( // Define the default Brightness and Colors brightness: Brightness.dark, primaryColor: Colors.lightBlue[800], accentColor: Colors.cyan[600], // Define the default Font Family fontFamily: 'Montserrat', // Define the default TextTheme. Use this to specify the default // text styling for headlines, titles, bodies of text, and more. textTheme: TextTheme( headline: TextStyle(fontSize: 72.0, fontWeight: FontWeight.bold), title: TextStyle(fontSize: 36.0, fontStyle: FontStyle.italic), body1: TextStyle(fontSize: 14.0, fontFamily: 'Hind'), ), ), home: HomePage(title: appTitle), ); } } |
home.dart
Paparan laman pertama di mana capaian ke server akan dibuat, dan ListView akan dipaparkan.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
import 'package:flutter/material.dart'; import 'dart:async'; import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'training.dart'; import 'listtrainings.dart'; Future<List<Training>> fetchTrainings(http.Client client) async { //fetch JSON data from server final response = await client.get('http://khirulnizam.com/training/searchflutter.php'); // return compute(parseTrainings, response.body);//capture data body } List<Training> parseTrainings(String responseBody) { final parsed = json.decode(responseBody).cast<Map<String, dynamic>>(); //return data in linked list return parsed.map<Training>((json) => Training.fromJson(json)).toList(); } class HomePage extends StatelessWidget { final String title; HomePage({Key key, this.title}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(title), ), body: FutureBuilder<List<Training>>( future: fetchTrainings(http.Client()), builder: (context, snapshot) { if (snapshot.hasError) print(snapshot.error); return snapshot.hasData ? ListViewTrainings(trainings: snapshot.data) : Center(child: CircularProgressIndicator()); }, ), ); } } |
Penulis tutorial:
KHIRULNIZAM ABD RAHMAN, Pensyarah Jabatan Sains Komputer, FSTM KUIS.
Beliau merupakan seorang trainer dalam bidang pengaturcaraan server dan antaramuka web (web front-end & backend) semenjak tahun 2000. Disamping itu juga amat berminat dalam pembangunan applikasi mobile Android, JSON, LARAVEL dan PHP-MySQL.
Blog peribadi beliau di khirulnizam.com . Beliau boleh dihubungi melalui email khirulnizam@gmail.com , atau Whatsapp: http://wasap.my/60129034614