यह पृष्ठ पुर्तगाली से मशीन-अनुवादित है और इसमें त्रुटियाँ हो सकती हैं। पुर्तगाली संस्करण प्रामाणिक है।
ऐप आर्किटेक्चर
CrossFly आर्किटेक्चर नहीं थोपता और इसमें न DI है न रिएक्टिव बाइंडिंग (देखें स्थिति और डेटा प्रवाह)। यह स्वतंत्रता है — और ज़िम्मेदारी भी। नीचे, सुझाए गए परंपराएँ (संगत, अनिवार्य नहीं) जो स्केल होती हैं। यह अध्याय 32 का कार्य-केंद्रित अंश है।
सुझाई गई पैकेज संरचना
app/
├─ ui/screens/ → uma tela = uma subclasse de Window
├─ viewmodel/ → estado + lógica de apresentação por tela
├─ data/repository → fachada sobre dev.crossfly.sqlite / rede
└─ service/ → serviços de app (singletons) + service locator
एक स्क्रीन = एक Window
public class ClientesScreen extends Window {
private final ClientesVM vm = new ClientesVM(Services.get(ClienteRepository.class));
@Override public void onShow() throws Exception {
super.onShow(); // यहाँ UI बनाएँ (मान्य bounds)
// … UI ↔ vm जोड़ता है …
vm.observe(this::render); // स्थिति बदलने पर पुनः रेंडर करता है
vm.carregar();
}
@Override public void onRemove() { vm.dispose(); super.onRemove(); } // संसाधन मुक्त करें
}
हल्का ViewModel (बिना setState)
चूँकि कोई रिएक्टिव बाइंडिंग नहीं है, ViewModel स्थिति रखता है और एक observe(Runnable) एक्सपोज़ करता है;
View मैन्युअल रूप से पुनः-रेंडर होता है:
public class ClientesVM {
private final ClienteRepository repo;
private Runnable onChange;
public List<Cliente> clientes = List.of();
public ClientesVM(ClienteRepository repo) { this.repo = repo; }
public void observe(Runnable r) { this.onChange = r; }
public void carregar() {
new Thread(() -> {
List<Cliente> dados = repo.listar();
Component.onUI(() -> { clientes = dados; if (onChange != null) onChange.run(); });
}).start();
}
public void dispose() { onChange = null; }
}
SQLite पर Repository
डेटा एक्सेस को एक फ़ेसाड में अलग करें — UI कभी सीधे SQL नहीं बोलती:
public class ClienteRepository {
public List<Cliente> listar() {
try (SqliteDb db = SqliteDb.open("app.db");
SqliteCursor c = db.query("SELECT id, nome FROM cliente")) {
List<Cliente> out = new ArrayList<>();
while (c.next()) out.add(new Cliente(c.getLong(0), c.getString(1)));
return out;
}
}
}
DI के स्थान पर: एक सरल सर्विस लोकेटर
पुराना Registry हटा दिया गया है। एक अपना Map<Class,Object> इसे हल करता है (या कंस्ट्रक्टर द्वारा इंजेक्शन):
public final class Services {
private static final Map<Class<?>, Object> reg = new HashMap<>();
public static <T> void put(Class<T> k, T v) { reg.put(k, v); }
public static <T> T get(Class<T> k) { return k.cast(reg.get(k)); }
}
// bootstrap में: Services.put(ClienteRepository.class, new ClienteRepository());
अच्छी प्रथाएँ
- UI
onShow()में, संसाधनonRemove()में मुक्त किए जाते हैं। - स्थिति ViewModel में; म्यूटेशन
onUIके माध्यम से paint thread पर वापस आते हैं; View स्थिति→कंपोनेंट में अनुवाद करता है। - Repository SQLite/नेटवर्क को छिपाता है; स्क्रीन SQL नहीं जानती।
आम गलतियाँ
- Flutter के DI/observable ढूँढना — वे मौजूद नहीं हैं; सर्विस लोकेटर + मैन्युअल
observe(...)का उपयोग करें। Windowमें सीधे SQL/HTTP डालना (यह जोड़ता है और UI को अवरुद्ध करता है)।- ऐप की स्थिति को
Windowके फ़ील्ड में रखना (नेविगेट करने पर गायब हो जाती है)।
यह भी देखें
- अवधारणा: स्थिति और डेटा प्रवाह · स्थिति प्रबंधन
क्या यह पृष्ठ उपयोगी था?प्रतिक्रिया के लिए धन्यवाद!