Flutter এ Data Persistence এবং Local Storage হলো অ্যাপ্লিকেশনের ডেটা সংরক্ষণ করার পদ্ধতি, যা ব্যবহারকারীর অ্যাপ থেকে বের হয়ে যাওয়ার পরও ডেটা ধরে রাখে। এই পদ্ধতির মাধ্যমে আপনি ডেটা যেমন ইউজার সেটিংস, অ্যাপ্লিকেশন স্টেট, ডাটাবেস রেকর্ড, ইত্যাদি স্থানীয়ভাবে (Local Storage) সংরক্ষণ করতে পারেন। Flutter এ কয়েকটি জনপ্রিয় পদ্ধতি রয়েছে যা Data Persistence এবং Local Storage এর জন্য ব্যবহৃত হয়।
Flutter এ Data Persistence এর প্রধান পদ্ধতি:
- SharedPreferences: সাধারণ ডেটা যেমন ইউজার প্রিফারেন্স (Boolean, String, Integer, Double) সংরক্ষণ করার জন্য।
- SQLite (sqflite): স্ট্রাকচারড ডেটা এবং বড় ডেটাবেসের জন্য, যেমন টুডু অ্যাপ, কন্টাক্ট ম্যানেজমেন্ট অ্যাপ ইত্যাদিতে ব্যবহৃত।
- Hive: কীগুলোর মাধ্যমে ডেটা সংরক্ষণ করার জন্য দ্রুত এবং lightweight ডেটাবেস, যা ব্লক ডেটা এবং স্ট্রাকচার্ড ডেটা ম্যানেজ করতে ব্যবহৃত হয়.
- Path Provider: ফাইল সিস্টেমে ফাইল লেখার জন্য ব্যবহৃত হয়।
১. SharedPreferences:
SharedPreferences হলো একটি সহজ এবং হালকা ওজনের পদ্ধতি, যা সাধারণত ইউজার প্রিফারেন্স (যেমন, ডার্ক মোড অন/অফ, ইউজারনেম, ইত্যাদি) সংরক্ষণ করতে ব্যবহৃত হয়।
SharedPreferences সেটআপ করা:
প্রথমে shared_preferences প্যাকেজ ইনস্টল করুন:
dependencies:
shared_preferences: ^2.0.0
SharedPreferences এর উদাহরণ:
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SharedPreferencesExample extends StatefulWidget {
@override
_SharedPreferencesExampleState createState() => _SharedPreferencesExampleState();
}
class _SharedPreferencesExampleState extends State<SharedPreferencesExample> {
String _username = '';
@override
void initState() {
super.initState();
_loadUsername();
}
// ডেটা লোড করা
Future<void> _loadUsername() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_username = prefs.getString('username') ?? 'Guest';
});
}
// ডেটা সংরক্ষণ করা
Future<void> _saveUsername(String username) async {
final prefs = await SharedPreferences.getInstance();
prefs.setString('username', username);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('SharedPreferences Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Hello, $_username!'),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
_saveUsername('John Doe');
_loadUsername();
},
child: Text('Save Username'),
),
],
),
),
);
}
}
- prefs.setString('username', username): এটি একটি কীগুলির মাধ্যমে ডেটা সংরক্ষণ করে।
- prefs.getString('username'): সংরক্ষিত ডেটা রিট্রিভ করে।
২. SQLite (sqflite):
Flutter এ sqflite প্যাকেজ SQLite ডেটাবেস ব্যবস্থাপনার জন্য ব্যবহৃত হয়। এটি স্ট্রাকচারড ডেটা যেমন টাস্ক ম্যানেজমেন্ট, নোট অ্যাপ ইত্যাদি সংরক্ষণ এবং ম্যানেজ করতে সহায়তা করে।
SQLite (sqflite) সেটআপ করা:
প্রথমে sqflite এবং path প্যাকেজ ইনস্টল করুন:
dependencies:
sqflite: ^2.0.0
path: ^1.8.0
SQLite এর উদাহরণ:
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseHelper {
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
static Database? _database;
DatabaseHelper._privateConstructor();
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
Future<Database> _initDatabase() async {
String path = join(await getDatabasesPath(), 'my_database.db');
return await openDatabase(
path,
version: 1,
onCreate: (db, version) {
return db.execute(
'CREATE TABLE tasks(id INTEGER PRIMARY KEY, name TEXT)',
);
},
);
}
Future<void> insertTask(String name) async {
final db = await database;
await db.insert(
'tasks',
{'name': name},
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
Future<List<Map<String, dynamic>>> getTasks() async {
final db = await database;
return await db.query('tasks');
}
}
class SqliteExample extends StatefulWidget {
@override
_SqliteExampleState createState() => _SqliteExampleState();
}
class _SqliteExampleState extends State<SqliteExample> {
List<Map<String, dynamic>> tasks = [];
@override
void initState() {
super.initState();
_loadTasks();
}
Future<void> _loadTasks() async {
tasks = await DatabaseHelper.instance.getTasks();
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('SQLite Example')),
body: ListView.builder(
itemCount: tasks.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(tasks[index]['name']),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await DatabaseHelper.instance.insertTask('New Task');
_loadTasks();
},
child: Icon(Icons.add),
),
);
}
}
- openDatabase: একটি SQLite ডেটাবেস খোলে বা তৈরি করে।
- insertTask: নতুন ডেটা SQLite ডেটাবেসে ইনসার্ট করে।
- getTasks: ডেটা রিট্রিভ করে এবং UI তে প্রদর্শন করে।
৩. Hive:
Hive হলো একটি দ্রুত এবং lightweight local storage সলিউশন, যা Flutter এ ব্যবহার করা যায়। এটি কীগুলির মাধ্যমে ডেটা সংরক্ষণ করে এবং SQLite এর চেয়ে সহজে ব্যবস্থাপনা করা যায়।
Hive সেটআপ করা:
প্রথমে hive এবং hive_flutter প্যাকেজ ইনস্টল করুন:
dependencies:
hive: ^2.0.0
hive_flutter: ^1.1.0
Hive এর উদাহরণ:
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
void main() async {
await Hive.initFlutter();
await Hive.openBox('myBox');
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HiveExample(),
);
}
}
class HiveExample extends StatelessWidget {
final Box box = Hive.box('myBox');
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Hive Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () {
box.put('name', 'John Doe');
},
child: Text('Save Name'),
),
ElevatedButton(
onPressed: () {
String? name = box.get('name');
print('Name: $name');
},
child: Text('Load Name'),
),
],
),
),
);
}
}
- Hive.initFlutter(): Hive ডাটাবেস ইন্টিলাইজ করে।
- Hive.openBox('myBox'): ডেটা সংরক্ষণের জন্য একটি Box খোলে।
- box.put('key', value): ডেটা Box এ সংরক্ষণ করে।
- box.get('key'): Box থেকে ডেটা রিট্রিভ করে।
৪. Path Provider:
Flutter এ Path Provider প্যাকেজ ব্যবহৃত হয় অ্যাপের ফাইল সিস্টেমের বিভিন্ন ডিরেক্টরি অ্যাক্সেস করতে, যেমন Temporary Directory, Application Documents Directory, ইত্যাদি।
Path Provider সেটআপ করা:
প্রথমে path_provider প্যাকেজ ইনস্টল করুন:
dependencies:
path_provider: ^2.0.0
File Storage এর উদাহরণ:
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
class FileExample extends StatefulWidget {
@override
_FileExampleState createState() => _FileExampleState();
}
class _FileExampleState extends State<FileExample> {
String _fileContent = '';
Future<File> _getLocalFile() async {
final directory = await getApplicationDocumentsDirectory();
return File('${directory.path}/my_file.txt');
}
Future<void> _writeToFile(String content) async {
final file = await _getLocalFile();
await file.writeAsString(content);
}
Future<void> _readFromFile() async {
try {
final file = await _getLocalFile();
String contents = await file.readAsString();
setState(() {
_fileContent = contents;
});
} catch (e) {
setState(() {
_fileContent = 'Error reading file';
});
}
}
@override
void initState() {
super.initState();
_readFromFile();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('File Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('File Content: $_fileContent'),
ElevatedButton(
onPressed: () {
_writeToFile('Hello, Flutter!');
_readFromFile();
},
child: Text('Write to File'),
),
],
),
),
);
}
}
- getApplicationDocumentsDirectory(): অ্যাপ্লিকেশন ডকুমেন্টস ডিরেক্টরি রিটার্ন করে।
- File.writeAsString(content): ফাইলে ডেটা লেখে।
- File.readAsString(): ফাইল থেকে ডেটা রিড করে।
Flutter এ Data Persistence এর সংক্ষিপ্ত তুলনা:
| পদ্ধতি | ব্যবহারের ক্ষেত্র | সুবিধা |
|---|---|---|
| SharedPreferences | সাধারণ ইউজার প্রিফারেন্স এবং ছোট ডেটা | সহজ এবং দ্রুত |
| SQLite (sqflite) | স্ট্রাকচারড ডেটাবেসের জন্য | শক্তিশালী এবং স্কেলেবল |
| Hive | দ্রুত এবং lightweight স্টোরেজ সলিউশন | দ্রুত, এবং ব্লক ডেটা ব্যবস্থাপনায় কার্যকর |
| Path Provider | ফাইল ব্যবস্থাপনার জন্য | ডেটা ফাইল আকারে সংরক্ষণ করতে সক্ষম |
Flutter এ Data Persistence এবং Local Storage ব্যবহার করে আপনি একটি কার্যকরী এবং প্রফেশনাল অ্যাপ্লিকেশন তৈরি করতে পারবেন, যেখানে ব্যবহারকারীর ডেটা সুরক্ষিত এবং সঠিকভাবে সংরক্ষিত থাকবে।
Flutter-এ SharedPreferences ব্যবহার করে ডেটা সংরক্ষণ করা একটি সাধারণ এবং কার্যকরী পদ্ধতি, যা আপনাকে ব্যবহারকারীর ডিভাইসে ছোট ডেটা যেমন স্ট্রিং, ইন্টিজার, বুলিয়ান, এবং ডাবল সেভ করতে সাহায্য করে। এটি মূলত ব্যবহারকারীর অ্যাপ্লিকেশনের সেটিংস, প্রেফারেন্স, লগইন তথ্য ইত্যাদি সংরক্ষণ করতে ব্যবহৃত হয়।
SharedPreferences সেটআপ করা
প্রথমে pubspec.yaml ফাইলে shared_preferences প্যাকেজটি যোগ করতে হবে:
dependencies:
flutter:
sdk: flutter
shared_preferences: ^2.0.15
এরপর flutter pub get কমান্ড চালিয়ে প্যাকেজটি ইন্সটল করুন।
SharedPreferences দিয়ে ডেটা সংরক্ষণ এবং রিড করার উদাহরণ
Flutter-এ SharedPreferences ব্যবহার করে কিভাবে ডেটা সংরক্ষণ এবং রিড করা যায় তার উদাহরণ নিচে দেওয়া হলো:
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
String? _savedData;
@override
void initState() {
super.initState();
_loadData(); // অ্যাপ চালু হলে ডেটা লোড করা হচ্ছে
}
// ডেটা লোড করার ফাংশন
Future<void> _loadData() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_savedData = prefs.getString('saved_text') ?? 'No data saved';
});
}
// ডেটা সংরক্ষণ করার ফাংশন
Future<void> _saveData(String value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('saved_text', value);
_loadData(); // ডেটা আপডেট করার পর তা রিফ্রেশ করে দেখানো হচ্ছে
}
// ডেটা রিমুভ করার ফাংশন
Future<void> _removeData() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('saved_text');
_loadData(); // ডেটা রিমুভ করে তা রিফ্রেশ করে দেখানো হচ্ছে
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SharedPreferences Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
_savedData ?? 'No data',
style: TextStyle(fontSize: 20),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
_saveData('Hello, Flutter!');
},
child: Text('Save Data'),
),
ElevatedButton(
onPressed: _removeData,
child: Text('Remove Data'),
),
],
),
),
);
}
}
কোডের ব্যাখ্যা
- SharedPreferences ব্যবহার করা হয়েছে ব্যবহারকারীর ডিভাইসে ছোট ডেটা সংরক্ষণ করার জন্য।
- _loadData: এটি একটি ফাংশন যা SharedPreferences থেকে ডেটা রিড করে এবং setState এর মাধ্যমে UI-তে আপডেট করে।
- _saveData: এটি একটি ফাংশন যা SharedPreferences এ ডেটা সেভ করে। এখানে ডেটা সেভ করার জন্য setString মেথড ব্যবহার করা হয়েছে।
- _removeData: এটি SharedPreferences থেকে নির্দিষ্ট ডেটা রিমুভ করে।
SharedPreferences দিয়ে বিভিন্ন ধরনের ডেটা সংরক্ষণ করা
SharedPreferences-এ শুধুমাত্র প্রিমিটিভ ডেটা টাইপ (String, int, double, bool, এবং String লিস্ট) সেভ করা যায়। নিচে বিভিন্ন ধরনের ডেটা সেভ এবং রিড করার উদাহরণ দেওয়া হলো:
১. String সংরক্ষণ করা
Future<void> saveString(String value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('my_string_key', value);
}
Future<String?> getString() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('my_string_key');
}
২. int সংরক্ষণ করা
Future<void> saveInt(int value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('my_int_key', value);
}
Future<int?> getInt() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getInt('my_int_key');
}
৩. double সংরক্ষণ করা
Future<void> saveDouble(double value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setDouble('my_double_key', value);
}
Future<double?> getDouble() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getDouble('my_double_key');
}
৪. bool সংরক্ষণ করা
Future<void> saveBool(bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('my_bool_key', value);
}
Future<bool?> getBool() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getBool('my_bool_key');
}
৫. List<String> সংরক্ষণ করা
Future<void> saveStringList(List<String> value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setStringList('my_list_key', value);
}
Future<List<String>?> getStringList() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getStringList('my_list_key');
}
SharedPreferences ব্যবহারের টিপস
Key Management: প্রতিটি ডেটা সেভ করার সময় একটি কির প্রয়োজন হয়। কির নাম সবসময় ইউনিক এবং পরিষ্কার রাখুন, যাতে পরবর্তীতে সহজে বোঝা যায়।
Large Data Storage: SharedPreferences শুধুমাত্র ছোট ডেটা (যেমন স্ট্রিং, বুলিয়ান, ইত্যাদি) সংরক্ষণ করার জন্য উপযুক্ত। বড় ডেটা (যেমন JSON অবজেক্ট বা বড় লিস্ট) স্টোর করতে SharedPreferences ব্যবহার না করে, SQLite বা local storage ব্যবহার করুন।
Security: সংবেদনশীল তথ্য যেমন পাসওয়ার্ড বা টোকেন সংরক্ষণের ক্ষেত্রে secure storage ব্যবহার করা ভালো। flutter_secure_storage বা crypto প্যাকেজ ব্যবহার করে ডেটা এনক্রিপ্ট করা যেতে পারে।
Initialization: SharedPreferences অ্যাসিনক্রোনাস পদ্ধতিতে কাজ করে, তাই অ্যাপ্লিকেশনের স্টার্টআপের সময় যদি এটি ইনিশিয়ালাইজ করতে হয়, তবে async এবং await ব্যবহার করে অ্যাসিনক্রোনাসভাবে পরিচালনা করুন।
সারসংক্ষেপ
- SharedPreferences একটি কার্যকরী পদ্ধতি, যা ব্যবহারকারীর ডিভাইসে ছোট ডেটা সংরক্ষণ করতে সাহায্য করে।
- এটি সাধারণত অ্যাপ প্রেফারেন্স, ব্যবহারকারীর সেশন, বা ছোট সেটিংস সংরক্ষণ করতে ব্যবহৃত হয়।
- Flutter-এ setString, getString, setInt, getInt ইত্যাদি মেথড ব্যবহার করে আপনি বিভিন্ন ধরনের ডেটা সেভ এবং রিড করতে পারেন।
- সংবেদনশীল তথ্য সংরক্ষণের ক্ষেত্রে নিরাপত্তার জন্য secure storage ব্যবহার করা উত্তম।
এইভাবে, Flutter-এ SharedPreferences ব্যবহার করে আপনি ডেটা সংরক্ষণ এবং রিড করতে পারেন, যা অ্যাপ্লিকেশনকে আরও কার্যকরী এবং ব্যবহারবান্ধব করে তোলে।
Flutter এ SQLite Database Integration করতে হলে sqflite প্যাকেজ ব্যবহার করতে হয়। এটি Flutter অ্যাপে লোকাল ডেটাবেজ ব্যবস্থাপনার জন্য খুবই কার্যকর এবং জনপ্রিয় একটি প্যাকেজ। নিচে SQLite Database Integration করার ধাপগুলো এবং একটি পূর্ণাঙ্গ উদাহরণ দেওয়া হলো।
SQLite Database Integration এর ধাপসমূহ:
ধাপ ১: sqflite এবং path প্যাকেজ যুক্ত করা:
প্রথমে pubspec.yaml ফাইলে sqflite এবং path প্যাকেজ যুক্ত করতে হবে:
dependencies:
flutter:
sdk: flutter
sqflite: ^2.0.0+3
path: ^1.8.0
sqflite: এটি SQLite ডেটাবেজের জন্য প্যাকেজ।
path: এটি ডিভাইসের লোকাল স্টোরেজে ডেটাবেজের পথ (path) নির্ধারণ করতে সাহায্য করে।
ধাপ ২: মডেল ক্লাস তৈরি করা:
- ডেটাবেজে ডেটা সংরক্ষণ করতে হলে একটি মডেল ক্লাস তৈরি করা হয় যা ডেটার কাঠামো নির্ধারণ করে।
ধাপ ৩: ডেটাবেজ হেল্পার ক্লাস তৈরি করা:
- ডেটাবেজ সংরক্ষণ, আপডেট, মুছে ফেলা, এবং ফেচ করার জন্য একটি ডেটাবেজ হেল্পার ক্লাস তৈরি করা হয়।
Flutter এ SQLite Database Integration এর উদাহরণ:
import 'package:flutter/material.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter SQLite Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('SQLite Database Example'),
),
body: UserListScreen(),
),
);
}
}
// মডেল ক্লাস
class User {
final int? id;
final String name;
final String email;
User({this.id, required this.name, required this.email});
// JSON থেকে User অবজেক্টে রূপান্তর
factory User.fromMap(Map<String, dynamic> json) => User(
id: json['id'],
name: json['name'],
email: json['email'],
);
// User অবজেক্ট থেকে JSON এ রূপান্তর
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
'email': email,
};
}
}
// ডেটাবেজ হেল্পার ক্লাস
class DatabaseHelper {
static final DatabaseHelper instance = DatabaseHelper._init();
static Database? _database;
DatabaseHelper._init();
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDB('users.db');
return _database!;
}
Future<Database> _initDB(String filePath) async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, filePath);
return await openDatabase(
path,
version: 1,
onCreate: _createDB,
);
}
Future _createDB(Database db, int version) async {
const idType = 'INTEGER PRIMARY KEY AUTOINCREMENT';
const textType = 'TEXT NOT NULL';
await db.execute('''
CREATE TABLE users (
id $idType,
name $textType,
email $textType
)
''');
}
Future<void> insertUser(User user) async {
final db = await instance.database;
await db.insert('users', user.toMap());
}
Future<List<User>> getUsers() async {
final db = await instance.database;
final result = await db.query('users');
return result.map((json) => User.fromMap(json)).toList();
}
Future<void> updateUser(User user) async {
final db = await instance.database;
await db.update(
'users',
user.toMap(),
where: 'id = ?',
whereArgs: [user.id],
);
}
Future<void> deleteUser(int id) async {
final db = await instance.database;
await db.delete(
'users',
where: 'id = ?',
whereArgs: [id],
);
}
Future close() async {
final db = await instance.database;
db.close();
}
}
// UI Screen
class UserListScreen extends StatefulWidget {
@override
_UserListScreenState createState() => _UserListScreenState();
}
class _UserListScreenState extends State<UserListScreen> {
late Future<List<User>> _users;
@override
void initState() {
super.initState();
_users = DatabaseHelper.instance.getUsers();
}
@override
Widget build(BuildContext context) {
return FutureBuilder<List<User>>(
future: _users,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else if (snapshot.hasData) {
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
);
},
);
} else {
return Center(child: Text('No users found'));
}
},
);
}
}
ধাপে ধাপে ব্যাখ্যা:
ধাপ ১: মডেল ক্লাস (User):
Userক্লাসে ডেটার স্ট্রাকচার নির্ধারণ করা হয়েছে।fromMapএবংtoMapমেথড তৈরি করা হয়েছে JSON ডেটাকে Dart অবজেক্টে রূপান্তর করতে এবং বিপরীতভাবে Dart অবজেক্টকে JSON এ রূপান্তর করতে।
ধাপ ২: ডেটাবেজ হেল্পার ক্লাস (DatabaseHelper):
- Singleton Pattern ব্যবহার করা হয়েছে যাতে একাধিক ইনস্ট্যান্স তৈরি না হয়।
_initDBমেথডে ডেটাবেজ তৈরি এবং সেটআপ করা হয়।_createDBমেথডে ডেটাবেজের টেবিল গঠন করা হয়েছে।- CRUD অপারেশন:
insertUser: নতুন ইউজার ইনসার্ট করে।getUsers: ডেটাবেজ থেকে সকল ইউজার রিটার্ন করে।updateUser: একটি ইউজার আপডেট করে।deleteUser: একটি ইউজার ডিলিট করে।
ধাপ ৩: UI তৈরি করা (UserListScreen):
FutureBuilderব্যবহার করে ইউজার ডেটা লোড করা হয়েছে এবং UI তে প্রদর্শন করা হয়েছে।- লোডিং, ত্রুটি, এবং ডেটা প্রদর্শনের স্টেট হ্যান্ডেল করা হয়েছে।
SQLite Integration এর সুবিধা:
- লোকাল ডেটা সংরক্ষণ: SQLite ডেটাবেজের মাধ্যমে অফলাইন মোডে ডেটা সংরক্ষণ এবং পুনরুদ্ধার করা যায়।
- ডেটাবেজ অপারেশন সহজে পরিচালনা:
sqfliteপ্যাকেজের মাধ্যমে ডেটাবেজের CRUD অপারেশন সহজে করা যায়। - ছোট এবং কার্যকরী: ছোট অ্যাপ্লিকেশনের জন্য SQLite খুব কার্যকর, কারণ এটি হালকা এবং দ্রুত।
সংক্ষেপে:
sqfliteপ্যাকেজ ব্যবহার করে SQLite ডেটাবেজ ইন্টিগ্রেশন করা হয়।- মডেল ক্লাস তৈরি করে ডেটার কাঠামো নির্ধারণ করা হয়।
- ডেটাবেজ হেল্পার ক্লাস তৈরি করে CRUD অপারেশন পরিচালনা করা হয়।
FutureBuilderব্যবহার করে UI তে ডেটা লোড এবং প্রদর্শন করা হয়।
Flutter এ ObjectBox এবং Hive হলো দুইটি জনপ্রিয় NoSQL ডেটা স্টোরেজ সলিউশন, যা দ্রুত এবং সহজে ডেটা সংরক্ষণ এবং ম্যানেজ করতে সহায়ক। এগুলো SQLite এর বিকল্প হিসেবে ব্যবহৃত হয়, যেখানে ডেটা কীগুলির মাধ্যমে অথবা অবজেক্ট স্টোর করে ম্যানেজ করা যায়। ObjectBox এবং Hive উভয়ই উচ্চ পারফরম্যান্স প্রদান করে এবং সহজে ব্যবহারযোগ্য।
১. ObjectBox
ObjectBox হলো একটি NoSQL ডেটাবেস, যা Flutter এবং Dart এ ব্যবহার করা যায়। এটি Object-Oriented ডেটাবেস হিসেবে কাজ করে, যেখানে ডেটাকে অবজেক্ট আকারে সংরক্ষণ করা হয় এবং তা সহজে অ্যাক্সেস করা যায়। ObjectBox দ্রুত এবং শক্তিশালী, যা বড় আকারের অ্যাপ্লিকেশনেও ব্যবহার করা যায়।
ObjectBox সেটআপ করা:
প্রথমে objectbox এবং objectbox_flutter_libs প্যাকেজ ইনস্টল করুন:
dependencies:
objectbox: ^1.0.0
objectbox_flutter_libs: any
dev_dependencies:
build_runner: ^2.0.0
objectbox_generator: ^1.0.0
ObjectBox এর উদাহরণ:
import 'package:objectbox/objectbox.dart';
@Entity()
class Task {
int id;
String name;
bool isCompleted;
Task({this.id = 0, required this.name, this.isCompleted = false});
}
- @Entity: ক্লাসটিকে একটি ডেটাবেস এনটিটি হিসেবে চিহ্নিত করে।
- id: ObjectBox নিজে থেকে id পরিচালনা করে। এটি স্বয়ংক্রিয়ভাবে জেনারেটেড একটি প্রাথমিক কী।
ObjectBox ডেটাবেস তৈরি করা এবং ব্যবহারের উদাহরণ:
import 'package:flutter/material.dart';
import 'objectbox.g.dart'; // ObjectBox কোড জেনারেশন ফাইল
late Store store; // ডেটাবেস স্টোর
void main() async {
store = await openStore(); // ObjectBox স্টোর খুলছে
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: TaskScreen(),
);
}
}
class TaskScreen extends StatefulWidget {
@override
_TaskScreenState createState() => _TaskScreenState();
}
class _TaskScreenState extends State<TaskScreen> {
late final Box<Task> taskBox;
@override
void initState() {
super.initState();
taskBox = store.box<Task>();
_addTask('First Task');
}
void _addTask(String name) {
final task = Task(name: name);
taskBox.put(task); // ডেটা ObjectBox এ সংরক্ষণ করা হচ্ছে
}
List<Task> _getTasks() {
return taskBox.getAll(); // সকল টাস্ক রিট্রিভ করা হচ্ছে
}
@override
Widget build(BuildContext context) {
final tasks = _getTasks();
return Scaffold(
appBar: AppBar(
title: Text('ObjectBox Example'),
),
body: ListView.builder(
itemCount: tasks.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(tasks[index].name),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_addTask('New Task ${tasks.length + 1}');
setState(() {});
},
child: Icon(Icons.add),
),
);
}
}
ObjectBox এর সুবিধা:
- পারফরম্যান্স: ObjectBox দ্রুত ডেটা অ্যাক্সেস এবং ম্যানেজমেন্টের জন্য কার্যকর।
- Object-Oriented: ObjectBox এ ডেটা অবজেক্ট হিসেবে সংরক্ষিত হয়, যা ডেভেলপারদের জন্য সহজে ব্যবস্থাপনাযোগ্য।
- ব্যাকগ্রাউন্ড ডেটা সিঙ্ক: ObjectBox এ ব্যাকগ্রাউন্ড ডেটা সিঙ্ক এবং রিয়েল-টাইম আপডেট সম্ভব।
২. Hive
Hive হলো একটি lightweight এবং দ্রুত NoSQL ডেটাবেস, যা Flutter এ ব্যবহার করা যায়। এটি সাধারণত কীগুলির মাধ্যমে ডেটা সংরক্ষণ করে এবং বিভিন্ন ডেটা টাইপ সাপোর্ট করে। Hive ডেটাবেস ব্লক স্ট্রাকচার ব্যবহার করে, যা উচ্চ পারফরম্যান্স প্রদান করে।
Hive সেটআপ করা:
প্রথমে hive এবং hive_flutter প্যাকেজ ইনস্টল করুন:
dependencies:
hive: ^2.0.0
hive_flutter: ^1.1.0
dev_dependencies:
hive_generator: ^1.0.0
build_runner: ^2.0.0
Hive এর উদাহরণ:
import 'package:hive/hive.dart';
part 'task.g.dart'; // কোড জেনারেশন
@HiveType(typeId: 0)
class Task extends HiveObject {
@HiveField(0)
String name;
@HiveField(1)
bool isCompleted;
Task({required this.name, this.isCompleted = false});
}
- @HiveType এবং @HiveField: এগুলো Hive এর এনটিটি এবং ফিল্ড ডিফাইন করতে ব্যবহৃত হয়।
Hive ডেটাবেস তৈরি করা এবং ব্যবহারের উদাহরণ:
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'task.dart'; // আপনার Task ক্লাস
void main() async {
await Hive.initFlutter();
Hive.registerAdapter(TaskAdapter());
await Hive.openBox<Task>('taskBox');
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: TaskScreen(),
);
}
}
class TaskScreen extends StatefulWidget {
@override
_TaskScreenState createState() => _TaskScreenState();
}
class _TaskScreenState extends State<TaskScreen> {
final Box<Task> taskBox = Hive.box<Task>('taskBox');
void _addTask(String name) {
final task = Task(name: name);
taskBox.add(task); // ডেটা Hive এ সংরক্ষণ করা হচ্ছে
}
List<Task> _getTasks() {
return taskBox.values.toList(); // সকল টাস্ক রিট্রিভ করা হচ্ছে
}
@override
Widget build(BuildContext context) {
final tasks = _getTasks();
return Scaffold(
appBar: AppBar(
title: Text('Hive Example'),
),
body: ListView.builder(
itemCount: tasks.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(tasks[index].name),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_addTask('New Task ${tasks.length + 1}');
setState(() {});
},
child: Icon(Icons.add),
),
);
}
}
Hive এর সুবিধা:
- Lightweight: Hive খুবই হালকা ওজনের এবং ডিভাইসে খুব কম মেমোরি ব্যবহার করে।
- High Performance: এটি দ্রুত ডেটা রিড এবং রাইট করতে পারে।
- কীগুলির মাধ্যমে স্টোরেজ: কীগুলির মাধ্যমে ডেটা অ্যাক্সেস করা যায়, যা সহজ এবং দ্রুত।
ObjectBox এবং Hive এর তুলনা:
| বৈশিষ্ট্য | ObjectBox | Hive |
|---|---|---|
| পারফরম্যান্স | দ্রুত এবং উচ্চ পারফরম্যান্স প্রদান করে | খুব দ্রুত এবং lightweight |
| ডেটা স্ট্রাকচার | Object-Oriented ডেটা স্ট্রাকচার | কীগুলির মাধ্যমে ডেটা সংরক্ষণ |
| ব্যবহারিক ক্ষেত্র | বড় এবং জটিল অ্যাপ্লিকেশন | ছোট থেকে মাঝারি আকারের অ্যাপ্লিকেশন |
| কোড জেনারেশন | Build Runner ব্যবহার করে কোড জেনারেশন করতে হয় | কোড জেনারেশন করতে হয়, তবে সেটআপ সহজ |
| ডেটা স্টোরেজ | ব্লক ডেটা এবং স্ট্রাকচার্ড ডেটা সাপোর্ট করে | ডেটা কীগুলির মাধ্যমে এবং ব্লক স্ট্রাকচারে |
কোনটি ব্যবহার করবেন:
- ObjectBox: যদি আপনার অ্যাপ্লিকেশন বড় এবং জটিল হয় এবং Object-Oriented ডেটা ব্যবস্থাপনার প্রয়োজন হয়, তাহলে ObjectBox একটি ভালো পছন্দ।
- Hive: যদি আপনার অ্যাপ্লিকেশন ছোট থেকে মাঝারি আকারের এবং দ্রুত ডেটা সংরক্ষণের প্রয়োজন হয়, তাহলে Hive একটি কার্যকর সমাধান।
Flutter এ ObjectBox এবং Hive উভয়ই শক্তিশালী এবং কার্যকরী NoSQL ডেটা স্টোরেজ সলিউশন, যা অ্যাপ্লিকেশনের ডেটা দ্রুত এবং নিরাপদে সংরক্ষণ করতে সহায়তা করে। আপনার অ্যাপ্লিকেশনের প্রয়োজন অনুযায়ী সঠিক ডেটা স্টোরেজ সমাধান বেছে নিন।
Flutter-এ File I/O (Input/Output) এবং JSON ডেটা ম্যানিপুলেশন অ্যাপ্লিকেশনের ডেটা সংরক্ষণ, ফাইল থেকে ডেটা পড়া এবং JSON ডেটা প্রসেস করার জন্য ব্যবহৃত হয়। এটি অ্যাপ্লিকেশনকে আরও কার্যকরী করে এবং অফলাইন ডেটা স্টোরেজের ক্ষেত্রে বিশেষভাবে সহায়ক। এখানে Flutter-এ File I/O এবং JSON ডেটা ম্যানিপুলেশন নিয়ে বিস্তারিত আলোচনা করা হলো:
১. File I/O (Input/Output) ব্যবহারের ধাপ
Flutter-এ dart
লাইব্রেরি ব্যবহার করে আপনি ফাইল পড়া, লেখা, এবং ম্যানিপুলেট করতে পারেন। path_provider প্যাকেজের সাহায্যে আপনি ডিভাইসের লোকাল ডিরেক্টরির (যেমন অ্যাপ্লিকেশনের ডকুমেন্ট বা ক্যাশ ডিরেক্টরি) পাথ পেতে পারেন।
ধাপ ১: path_provider প্যাকেজ ইন্সটল করা
প্রথমে pubspec.yaml ফাইলে path_provider প্যাকেজ যোগ করুন:
dependencies:
flutter:
sdk: flutter
path_provider: ^2.0.11
এরপর flutter pub get কমান্ড চালিয়ে প্যাকেজটি ইন্সটল করুন।
ধাপ ২: ফাইল লেখা এবং পড়া
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FileExampleScreen(),
);
}
}
class FileExampleScreen extends StatefulWidget {
@override
_FileExampleScreenState createState() => _FileExampleScreenState();
}
class _FileExampleScreenState extends State<FileExampleScreen> {
String _fileContent = 'No Data';
// ফাইলের পথ পাওয়া
Future<File> _getLocalFile() async {
final directory = await getApplicationDocumentsDirectory();
return File('${directory.path}/data.txt');
}
// ফাইল থেকে ডেটা রিড করা
Future<void> _readFromFile() async {
try {
final file = await _getLocalFile();
String contents = await file.readAsString();
setState(() {
_fileContent = contents;
});
} catch (e) {
setState(() {
_fileContent = 'Error reading file';
});
}
}
// ফাইলে ডেটা লেখা
Future<void> _writeToFile(String content) async {
final file = await _getLocalFile();
await file.writeAsString(content);
_readFromFile();
}
@override
void initState() {
super.initState();
_readFromFile(); // অ্যাপ চালু হলে ফাইল থেকে ডেটা লোড করা হচ্ছে
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('File I/O Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
_fileContent,
style: TextStyle(fontSize: 20),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
_writeToFile('Hello, Flutter!');
},
child: Text('Write to File'),
),
],
),
),
);
}
}
কোডের ব্যাখ্যা
- getApplicationDocumentsDirectory(): path_provider প্যাকেজ থেকে এই ফাংশনটি ব্যবহার করে অ্যাপ্লিকেশনের ডকুমেন্ট ডিরেক্টরির পাথ পাওয়া হয়।
- File.writeAsString(): ফাইলে স্ট্রিং ডেটা লিখতে ব্যবহৃত হয়।
- File.readAsString(): ফাইল থেকে ডেটা স্ট্রিং আকারে পড়তে ব্যবহৃত হয়।
- setState: ফাইলের ডেটা পড়ে UI আপডেট করা হয়।
২. JSON ডেটা ম্যানিপুলেশন
JSON ডেটা অনেক API এবং ডাটাবেস রেসপন্সে ব্যবহৃত হয়। Flutter-এ dart
প্যাকেজ ব্যবহার করে JSON ডেটা পার্স এবং ম্যানিপুলেট করা যায়।
JSON ডেটা পার্স করা
dart
প্যাকেজের json.decode() ব্যবহার করে JSON স্ট্রিং থেকে Dart অবজেক্টে কনভার্ট করা হয়।
import 'dart:convert';
void main() {
String jsonString = '''
{
"name": "John Doe",
"age": 25,
"email": "john.doe@example.com"
}
''';
// JSON থেকে Dart Map এ কনভার্ট করা
Map<String, dynamic> user = json.decode(jsonString);
print('Name: ${user['name']}');
print('Age: ${user['age']}');
print('Email: ${user['email']}');
}
JSON ডেটা থেকে Dart ক্লাসে কনভার্ট করা
প্রায়শই API থেকে আসা JSON ডেটাকে Dart ক্লাসে কনভার্ট করা হয়, যাতে ডেটা ম্যানিপুলেট করা এবং UI তে উপস্থাপন করা সহজ হয়।
উদাহরণ: JSON ডেটা থেকে Dart ক্লাসে কনভার্ট করা
import 'dart:convert';
class User {
final String name;
final int age;
final String email;
User({required this.name, required this.age, required this.email});
// JSON থেকে Dart অবজেক্ট তৈরি করার ফ্যাক্টরি কন্সট্রাক্টর
factory User.fromJson(Map<String, dynamic> json) {
return User(
name: json['name'],
age: json['age'],
email: json['email'],
);
}
// Dart অবজেক্ট থেকে JSON তৈরি করার মেথড
Map<String, dynamic> toJson() {
return {
'name': name,
'age': age,
'email': email,
};
}
}
void main() {
String jsonString = '''
{
"name": "John Doe",
"age": 25,
"email": "john.doe@example.com"
}
''';
// JSON থেকে User অবজেক্ট তৈরি করা
Map<String, dynamic> userMap = json.decode(jsonString);
User user = User.fromJson(userMap);
print('Name: ${user.name}');
print('Age: ${user.age}');
print('Email: ${user.email}');
// User অবজেক্ট থেকে JSON তৈরি করা
String encodedJson = json.encode(user.toJson());
print('Encoded JSON: $encodedJson');
}
কোডের ব্যাখ্যা
- User.fromJson(): JSON ডেটা থেকে Dart অবজেক্ট তৈরি করার জন্য একটি ফ্যাক্টরি কন্সট্রাক্টর।
- toJson(): Dart অবজেক্ট থেকে JSON ডেটা তৈরি করার জন্য একটি মেথড।
- json.decode(): JSON স্ট্রিংকে Map<String, dynamic> এ কনভার্ট করা হয়।
- json.encode(): Dart অবজেক্টকে JSON স্ট্রিংয়ে কনভার্ট করা হয়।
৩. JSON ডেটা ফাইল I/O এর সাথে সংযুক্ত করা
Flutter-এ JSON ডেটা ফাইল থেকে পড়া এবং লেখা সম্ভব। নিচে ফাইল I/O এবং JSON ম্যানিপুলেশন একত্রে ব্যবহারের উদাহরণ দেওয়া হলো:
import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:convert';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: JsonFileExampleScreen(),
);
}
}
class JsonFileExampleScreen extends StatefulWidget {
@override
_JsonFileExampleScreenState createState() => _JsonFileExampleScreenState();
}
class _JsonFileExampleScreenState extends State<JsonFileExampleScreen> {
Map<String, dynamic>? _data;
Future<File> _getLocalFile() async {
final directory = await getApplicationDocumentsDirectory();
return File('${directory.path}/data.json');
}
Future<void> _readJsonFromFile() async {
try {
final file = await _getLocalFile();
String contents = await file.readAsString();
setState(() {
_data = json.decode(contents);
});
} catch (e) {
setState(() {
_data = {'message': 'Error reading file'};
});
}
}
Future<void> _writeJsonToFile(Map<String, dynamic> data) async {
final file = await _getLocalFile();
await file.writeAsString(json.encode(data));
_readJsonFromFile();
}
@override
void initState() {
super.initState();
_readJsonFromFile();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('JSON File I/O Example')),
body: Center(
child: _data == null
? CircularProgressIndicator()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Name: ${_data!['name'] ?? 'N/A'}'),
Text('Age: ${_data!['age'] ?? 'N/A'}'),
ElevatedButton(
onPressed: () {
_writeJsonToFile({'name': 'John Doe', 'age': 30});
},
child: Text('Save JSON Data'),
),
],
),
),
);
}
}
সংক্ষেপে
- Flutter-এ File I/O করতে dartএবং path_provider প্যাকেজ ব্যবহার করা হয়।
- JSON ডেটা ম্যানিপুলেশন করতে dartপ্যাকেজ ব্যবহার করা হয়, যা JSON ডেটা পার্স এবং এনকোড করতে সাহায্য করে।
- ফাইল সিস্টেমে JSON ডেটা সংরক্ষণ এবং পড়া সম্ভব, যা অ্যাপ্লিকেশনের ডেটা ম্যানেজমেন্টকে আরও কার্যকরী করে।
এভাবে, Flutter-এ File I/O এবং JSON ডেটা ম্যানিপুলেশন ব্যবহার করে অ্যাপ্লিকেশনকে আরও ফ্লেক্সিবল এবং ডাইনামিক করা যায়।
Read more