Menu
CoddyTech
flag Ar iconالعربيةdown icon

قراءة JSON

جزء من قسم البيانات والشبكة في رحلة Flutter على Coddy. الدرس 15 من 27.

نادرًا ما تجيب الخوادم بجملة عادية. فهي ترسل JSON: نصًا يحتوي على بيانات، بأسماء بين علامتي اقتباس وقيم بعد نقطتين. وتُرجع واجهة API التجريبية عند طلب /user ما يلي:

{
  "name": "Maya Chen",
  "email": "maya@example.com",
  "age": 28,
  "isPro": true
}

بالنسبة إلى تطبيقك، هذا عبارة عن String طويل. تحوّل jsonDecode، من مكتبة dart:convert في Dart، هذا النص إلى قيم Dart. وتصبح الأقواس المعقوفة Map: الأسماء هي مفاتيحها.

import 'dart:convert';

final Map<String, dynamic> user = jsonDecode(body);
print(user['name']);   // مايا تشين

المفاتيح دائمًا سلاسل نصية. ويمكن أن تكون القيم نصوصًا أو أرقامًا أو true أو false أو قوائم أو خرائط أخرى، لذا يكون نوعها dynamic: «أي نوع، يُحدَّد أثناء تشغيل التطبيق». يجب أن تتطابق المفاتيح تمامًا: user['Name'] ليست user['name']، والمفتاح غير الموجود يعطي null.

فكّ ترميز الإجابة في الموضع الذي تجلبها فيه، داخل دالة مستقلة، لكي تحصل الشاشة على بيانات جاهزة للاستخدام.

challenge icon

التحدي

متوسط

تعرض شاشة الملف الشخصي بيانات JSON الخام. اعرض الشخص بدلًا من ذلك:

  • تعيد loadUser قيمة من النوع Future<Map<String, dynamic>>: تنتظر fetch('/user') وتعيد نتيجة jsonDecode للمتن (استورد dart:convert)
  • يستخدم كلٌّ من _user وFutureBuilder هذا النوع أيضًا
  • عند وصول البيانات، اعرض Column يحتوي على user['name'] (بحجم 28 وبخط عريض)، وتحته user['email']

جرّب بنفسك

import 'package:flutter/material.dart';

import 'api.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: ProfileScreen(),
    );
  }
}

class ProfileScreen extends StatefulWidget {
  const ProfileScreen({super.key});

  @override
  State<ProfileScreen> createState() => _ProfileScreenState();
}

class _ProfileScreenState extends State<ProfileScreen> {
  late Future<String> _user;

  @override
  void initState() {
    super.initState();
    _user = loadUser();
  }

  Future<String> loadUser() async {
    return fetch('/user');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Profile')),
      body: Center(
        child: FutureBuilder<String>(
          future: _user,
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              return Text('Could not load: ${snapshot.error}');
            }
            if (snapshot.hasData) {
              return Text(snapshot.data!);
            }
            return const CircularProgressIndicator();
          },
        ),
      ),
    );
  }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البيانات والشبكة

تدرّب بنفسك: مترجم Flutter عبر الإنترنت