Flutter Networking/ Http Fetch

 

Fetch Data From The Internet (İnternetten Veri Çekmek)

 

Öncelikle, uygulamalarımızda internetten veri çekmek için http paketini uygulamamızın pubspec.yaml adlı dosyasına güncel sürümü ile birlikte import etmemiz gerekiyor.

Network request (ağ isteği) oluşturabilmemiz için http kütüphanesinin http.get() metodunu kullanıyoruz. Bu metod Future sınıfı geri döndürür ve bu metot Response adında bir değişken içerir. Response değişkeni ile birlikte network requestimizin başarılı olup olmadığını kontrol edebiliriz.

Future sınıfı ise bir async operasyonları için kullanılan bir Dart sınıfıdır. Future nesnesi gelecek zamanda gelebilecek potansiyel bir değeri (value) veya hatayı temsil eder.

Her zaman belirttiğim gibi yazılarımda Google tarafından hazırlanmış Flutter dosyalarından yararlanıyorum ve oradaki basit http.get fonksiyonunun kullanımını görelim.

 

Future<http.Response> fetchAlbum() {

  return http.get('https://jsonplaceholder.typicode.com/albums/1');

}

 

Yukarıdaki kullanımda görüyoruz ki <http.Response> adında bir variable geri dönecek. Yani Future sınıfından bir fonksiyon oluştururken vermiş olduğunuz parametreye göre fonksiyonunuz şekillenecek bunu göz önünde bulundurmalısınız.

Daha sonrasında fonksiyonda http.get fonksiyonunun kullanıldığı yeri daha iyi anlayacağınızı düşünüyorum.

http.get fonksiyonunun içerisinde ise gördüğünüz adres dummy projelerde http kütüphanesinin kullanımındaki örneklerde kullanılan bir örnektir, kafanız karışmasın oradan bir fotoğraf fetch edilmeye çalışılıyor.

http.get fonksiyonunu oluşturduktan sonra döndüreceği response değerine göre başarılı olup olmayacağını göreceğiz demiştik. İşinizi kolaylaştırmak için http.Response değişkenini bir Dart nesnesine dönüştürebilirsiniz.

Fonksiyonumuzu oluşturduk ancak yapacağımız işler henüz bitmedi. Şimdi ise önceki yazılarımda, daha sonra kullanacağımızı söylediğim model kavramına geldik. Model dememin sebebi networking, service gibi kavramları öğrenmeye başladıktan sonra artık Flutter’da belirli seviyelere gelmiş olmanız kaçınılmazdır ve yazacağınız projelerde yazdığınız kodun okunaklı, iyi bir şekilde sınıflandırılıp, isimlendirilmesi gerekmekte.

Örneğimize dönecek olursak, http.get fonksiyonunun içerisindeki linkten de anlaşılacağı üzere bir görsel çekeceğiz. Bu görsel/görseller için bir albüm modeli (sınıfı) oluşturuyoruz. Bu modelimiz network requestimiz için kullanılacak dataları içerir. Ki aşağıdaki örnek kodda bu değişkenlerin isimlerinden rahatlıkla anlaşılabilir gözükmekte.

Ayrıca bu sınıf JSON’dan Album objesi yaratan factory constructoru içerir. JSON dosyalarının yazılım şekli de aşağıdaki örnekte gözükmektedir.

class Album {

  final int userId;

  final int id;

  final String title;

  Album({this.userId, this.id, this.title});

  factory Album.fromJson(Map<String, dynamic> json) {

    return Album(

      userId: json['userId'],

      id: json['id'],

      title: json['title'],

    );
  }
}

 

 

Modelimizi de oluşturduktan sonra yukarıdaki paragrafta belirttiğim http.Response değişkenini convert etmemiz gerekiyor.

 

Bu aşamada ilk kod örneğindeki fetchAlbum() ismindeki fonksiyonumuzu biraz daha geliştirmemiz gerekiyor. Geliştirilen fonksiyonumuz Future<Album> geri döndürecek.

 

İlk olarak, response bodysini dart:convert paketini kullanarak JSON Map içerisine convert etmemiz gerekiyor.

Eğer veri çekilen server response olarak olumlu değer (statusCode = 200) geri döndürüyorsa, JSON Mapini fromJson() constructor factory metodunu kullanarak convert ediyoruz.

Eğer server tarafından olumlu değer değil de hata mesajı alıyorsak (404 gibi) bir exception fırlatmalıyız. İnternet üzerinden veriler ile çalışırken fetch, send, kodlamalar içerisindeki snapshot v.b asla geri null değer döndürmemeliyiz. Null değer döndürüldüğünde oluşacak hatadan dolayı tüm uygulamamız patlayabilir.

import 'dart:convert';

Future<Album> fetchAlbum() async {

  final response = await http.get('https://jsonplaceholder.typicode.com/albums/1');

  if (response.statusCode == 200) {

    return Album.fromJson(jsonDecode(response.body));

  } else {

    throw Exception('Failed to load album');

  }

}

fetchAlbum() metodumuzu da güncelledikten sonra artık veriyi çekmeye hazırız. Şimdi arayüzümüzü oluşturmuş olduğumuz sınıfımızda yazacağımız kodlara geçebiliriz.

 

Datayı çekebilmemiz için fetch() metodumuzu uygulamamızın initState() ya da didChangeDependencies() metotlarının içerisinde çağırmamız gerekiyor. initState() metodunun içerisinde çağırmamızın sebebi bu metot yalnızca bir kere çağrılacaktır. Ancak build fonksiyonunun içerisine yazmış olsaydık her arayüz değişikliğinde defalarca çağrılması gerekecekti ki bundan “State Management” yazımda bahsetmiştim.

class _MyAppState extends State<MyApp> {

  Future<Album> futureAlbum;

@override

  void initState() {

    super.initState();

    futureAlbum = fetchAlbum();

  }


Zorlu yazımız bitmek üzere merak etmeyin, geldik son aşamaya. Çektiğimiz dataları görüntüleyelim.

Ekranda çektiğimiz verileri görüntüleyebilmemiz için, FutureBuilder widgetini kullanıyoruz. FutureBuilder widgeti asenkron (async) veriler ile çalışırken kullanabileceğimiz Flutter tarafından sağlanan oldukça kullanışlı bir metotdur.

İki adet parametreye ihtiyacımız olacak,

Bunlardan ilki, tabiki de çalışmak istediğimiz Future sınıfı olacak ki bunu da güncellemiş olduğumuz fetchAlbum() metodumuz bile birlikte geri döndürüyorduk,

İkincisi ise, bir builder fonksiyonu olacaktır ki bildiğimiz üzere uygulamanın durumuna bağlı olarak Flutter frameworküne neyin render edileceğini söyler.

 

Yukarıda belirtmiş olduğum fetchAlbum() metodumuzda null değer geri döndürmektense exception fırlatmamızın sebebi burada karşımıza çıkıyor. snapshot yalnızca null olmayan bir değer içerdiğinde snapshot.hasData,  true değerini döndürür. Çünkü bir üst paragrafta belirttiğim build fonksiyonu uygulamanın durumuna bağlı olarak işlemlerini gerçekleştireceği için fetchAlbum() metodundan gelen bir null değer ProgressIndicator’umuzu sonsuz şekilde döndürecektir.

 

FutureBuilder<Album>(

  future: futureAlbum,

  builder: (context, snapshot) {

    if (snapshot.hasData) {

      return Text(snapshot.data.title);

    } else if (snapshot.hasError) {

      return Text("${snapshot.error}");

    }




    // By default, show a loading spinner.

    return CircularProgressIndicator();

  },

);


Bu yazımın da sonuna gelmiş bulunmaktayız, bir sonraki yazımda ise networking konularından devam edeceğiz.