Skip to content

Kapitel 18: Interviewfragen

18.1 Grundlegende Konzeptfragen

Frage 1: Was ist Flutter?

Antwort: Flutter ist ein von Google entwickeltes cross-platform UI Framework, mit dem Entwickler mit einer einzigen Codebasis native Apps für iOS, Android, Web und Desktop erstellen können.

Wichtigste Merkmale:

  • Programmiersprache: Dart (offizielle Sprache von Flutter)
  • Ein Codebase: Läuft auf iOS, Android, Web, Windows, Mac, Linux
  • Native Performance: Kompiliert zu nativen ARM-Code
  • Widget-System: Alles ist ein Widget (Komponente)

Frage 2: Was sind die Kernvorteile von Flutter?

Antwort:

VorteilBeschreibung
Cross-Platform KonsistenzGleiches Aussehen und Verhalten auf allen Plattformen
Hohe PerformanceDirect Rendering, keine Bridge wie bei React Native
Hot ReloadSofortige Vorschau von Änderungen ohne App-Neustart
Hohe EntwicklungseffizienzEin Codebase für alle Plattformen
Tiefe Dart-IntegrationNahtlose Zusammenarbeit mit Dart

Frage 3: Was ist der Unterschied zwischen StatelessWidget und StatefulWidget?

Antwort:

MerkmalStatelessWidgetStatefulWidget
ZustandKein ZustandHat Zustand (State)
VeränderlichkeitUnveränderlichVeränderlich
PerformanceBesser (weniger Overhead)Schlechter (Rebuilding)
KomplexitätEinfacherKomplexer
AnwendungStatische InhalteInteraktive Inhalte

Entscheidungshilfe:

Brauche ich interaktive Elemente?
├── NEIN → StatelessWidget
└── JA → StatefulWidget
    ├── Einfache Interaktion → StatefulWidget
    └── Komplexe Zustandsverwaltung → Provider/Bloc (später)

Frage 4: Was ist Hot Reload und wie funktioniert es?

Antwort:Hot Reload:

  • ✅ Aktualisiert UI sofort
  • ✅ Behält App-Zustand bei (Variablen, Daten)
  • ✅ Funktioniert nur im Debug-Modus
  • ✅ Sehr schnell (Millisekunden)

Hot Restart:

  • ✅ Startet App neu
  • ✅ Setzt App-Zustand zurück
  • ✅ Etwas langsamer als Hot Reload

Full Restart:

  • ✅ Stoppt und startet App komplett neu
  • ✅ Erforderlich bei Änderungen an nativen Dateien

18.2 Kernfunktionalitätsfragen

Frage 5: Was sind die wichtigsten Layout-Widgets in Flutter?

Antwort:

1. Row (Horizontales Layout)

dart
Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: <Widget>[
    Icon(Icons.home),
    Text('Startseite'),
    ElevatedButton(onPressed: () {}, child: Text('Go')),
  ],
)

2. Column (Vertikales Layout)

dart
Column(
  mainAxisAlignment: MainAxisAlignment.center,
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: <Widget>[
    Text('Zeile 1'),
    Text('Zeile 2'),
    ElevatedButton(onPressed: () {}, child: Text('Button')),
  ],
)

3. Stack (Stapel-Layout)

dart
Stack(
  children: <Widget>[
    Container(width: 200, height: 200, color: Colors.red),
    Positioned(
      top: 10,
      left: 10,
      child: Icon(Icons.home, size: 30),
    ),
  ],
)

Frage 6: Was ist setState() und wann verwendet man es?

Antwort:setState() ist die einfachste Form der Zustandsverwaltung in Flutter.

Verwendung:

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

  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int _zaehler = 0;
  
  void _erhoehen() {
    setState(() {  // WICHTIG: setState() aktualisiert UI
      _zaehler++;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('$_zaehler', style: const TextStyle(fontSize: 48)),
            ElevatedButton(
              onPressed: _erhoehen,
              child: const Text('Erhöhen'),
            ),
          ],
        ),
      ),
    );
  }
}

Wann setState() verwenden?

  • ✅ Einfache Zustände (lokaler Zustand)
  • ✅ Wenige Widgets betroffen
  • ✅ Keine komplexe Zustandsverwaltung notwendig

Frage 7: Was ist Provider und wann verwendet man es?

Antwort:Provider ist eine offiziell empfohlene Lösung für Zustandsverwaltung in Flutter.

Vorteile:

  • ✅ Einfach zu verwenden
  • ✅ Gute Leistung
  • ✅ Gute Dokumentation

Verwendung (3 Schritte):

Schritt 1: Zustands-Klasse definieren (ChangeNotifier)

dart
class CounterProvider extends ChangeNotifier {
  int _zaehler = 0;
  
  int get zaehler => _zaehler;
  
  void erhoehen() {
    _zaehler++;
    notifyListeners();  // WICHTIG: Benachrichtigt alle Zuhörer!
  }
}

Schritt 2: Zustand bereitstellen (Provider)

dart
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => CounterProvider(),
      child: const MyApp(),
    ),
  );
}

Schritt 3: Zustand verbrauchen (Consumer / Provider.of)

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Consumer<CounterProvider>(
            builder: (context, provider, child) {
              return Text(
                '${provider.zaehler}',
                style: const TextStyle(fontSize: 48),
              );
            },
          ),
          const SizedBox(height: 20),
          ElevatedButton(
            onPressed: () {
              Provider.of<CounterProvider>(context, listen: false).erhoehen();
            },
            child: const Text('Erhöhen'),
          ),
        ],
      ),
    );
  }
}

18.3 Praxisszenario-Fragen

Frage 8: Wie erstellt man eine Login-Seite mit Formularvalidierung?

Antwort:

Vollständiger Code:

dart
import 'package:flutter/material.dart';

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

  @override
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final _formKey = GlobalKey<FormState>();
  final _usernameController = TextEditingController();
  final _passwordController = TextEditingController();
  
  void _login() {
    if (_formKey.currentState!.validate()) {
      // Formular ist gültig
      final username = _usernameController.text;
      final password = _passwordController.text;
      
      if (username == 'admin' && password == '123456') {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('Login erfolgreich!')),
        );
        // Hier zur nächsten Seite navigieren
      } else {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text('Login fehlgeschlagen!'),
            backgroundColor: Colors.red,
          ),
        );
      }
    }
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Login')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              TextFormField(
                controller: _usernameController,
                decoration: const InputDecoration(
                  labelText: 'Benutzername',
                  prefixIcon: Icon(Icons.person),
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Bitte Benutzernamen eingeben';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: _passwordController,
                obscureText: true,
                decoration: const InputDecoration(
                  labelText: 'Passwort',
                  prefixIcon: Icon(Icons.lock),
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Bitte Passwort eingeben';
                  }
                },
              ),
              const SizedBox(height: 24),
              ElevatedButton(
                onPressed: _login,
                child: const Text('Login'),
              ),
            ],
          ),
        ),
      ),
    );
  }
  
  @override
  void dispose() {
    _usernameController.dispose();
    _passwordController.dispose();
    super.dispose();
  }
}

Frage 9: Wie ruft man Daten von einer API ab und zeigt sie in einer Liste an?

Antwort:

Vollständiger Code:

dart
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';

// Modellklasse
class Post {
  final int id;
  final String title;
  final String body;
  
  Post({required this.id, required this.title, required this.body});
  
  factory Post.fromJson(Map<String, dynamic> json) {
    return Post(
      id: json['id'],
      title: json['title'],
      body: json['body'],
    );
  }
}

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

  @override
  State<PostsPage> createState() => _PostsPageState();
}

class _PostsPageState extends State<PostsPage> {
  List<Post> _posts = [];
  bool _isLoading = false;
  String _errorMessage = '';
  
  @override
  void initState() {
    super.initState();
    _ladePosts();
  }
  
  Future<void> _ladePosts() async {
    setState(() {
      _isLoading = true;
      _errorMessage = '';
    });
    
    try {
      final dio = Dio();
      final response = await dio.get('https://jsonplaceholder.typicode.com/posts?_limit=10');
      
      final List<dynamic> data = response.data;
      final posts = data.map((json) => Post.fromJson(json)).toList();
      
      setState(() {
        _posts = posts;
        _isLoading = false;
      });
    } catch (e) {
      setState(() {
        _errorMessage = 'Fehler beim Laden: $e';
        _isLoading = false;
      });
    }
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Posts')),
      body: _buildBody(),
      floatingActionButton: FloatingActionButton(
        onPressed: _ladePosts,
        child: const Icon(Icons.refresh),
      ),
    );
  }
  
  Widget _buildBody() {
    if (_isLoading) {
      return const Center(child: CircularProgressIndicator());
    }
    
    if (_errorMessage.isNotEmpty) {
      return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Icon(Icons.error, size: 64, color: Colors.red),
            const SizedBox(height: 16),
            Text(_errorMessage, textAlign: TextAlign.center),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: _ladePosts,
              child: const Text('Erneut versuchen'),
            ),
          ],
        ),
      );
    }
    
    return ListView.builder(
      itemCount: _posts.length,
      itemBuilder: (context, index) {
        final post = _posts[index];
        return Card(
          margin: const EdgeInsets.all(8),
          child: ListTile(
            title: Text(
              post.title,
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
            ),
            subtitle: Text(
              post.body,
              maxLines: 2,
              overflow: TextOverflow.ellipsis,
            ),
          ),
        );
      },
    );
  }
}

18.4 Häufige Fehlerpunkte-Fragen

Frage 10: Was sind häufige Fehler bei der Zustandsverwaltung?

Antwort:

Fehler 1: setState() vergessen

dart
// FALSCH
void _erhoehen() {
  _zaehler++;  // UI wird NICHT aktualisiert!
}

// RICHTIG
void _erhoehen() {
  setState(() {
    _zaehler++;  // UI wird aktualisiert!
  });
}

Fehler 2: notifyListeners() vergessen (bei Provider)

dart
// FALSCH
void erhoehen() {
  _zaehler++;
  // notifyListeners() vergessen! UI wird nicht aktualisiert.
}

// RICHTIG
void erhoehen() {
  _zaehler++;
  notifyListeners();  // UI wird aktualisiert!
}

Fehler 3: Zustand kann nicht einfach zwischen nicht-verwandten Widgets geteilt werden

  • Lösung: Provider oder andere Zustandsverwaltungs-Lösung verwenden.

Frage 11: Was sind häufige Fehler bei Netzwerkanfragen?

Antwort:

Fehler 1: Internet-Berechtigung fehlt (Android)

  • Lösung: android/app/src/main/AndroidManifest.xml bearbeiten:
xml
<manifest xmlns:android="...">
    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- Weitere Konfiguration -->
</manifest>

Fehler 2: await vergessen

dart
// FALSCH
void ladeDaten() {
  final response = dio.get('https://example.com');  // Future nicht awaited!
  print(response.data);  // Fehler: response ist kein Response-Objekt
}

// RICHTIG
Future<void> ladeDaten() async {
  final response = await dio.get('https://example.com');  // await verwenden!
  print(response.data);
}

Fehler 3: Fehlerbehandlung vergessen

  • Lösung: try-catch verwenden.

18.5 Dart-Verbindungsfragen

Frage 12: Was ist die Beziehung zwischen Dart und Flutter?

Antwort:

  • Dart ist die Programmiersprache von Flutter.
  • ✅ Flutter verwendet Dart als Programmiersprache.
  • ✅ Dart wurde von Google speziell für Flutter entwickelt.
  • ✅ Flutter verwendet Dart's Widget-System, um UI-Elemente zu erstellen.

Frage 13: Wie wird Dart in Flutter verwendet?

Antwort:

1. Variablen & Datentypen

dart
// In Flutter verwenden Sie oft Widget-Typen
Widget meinWidget = Text('Hallo');  // Widget-Typ
const String titel = 'Meine App';   // Konstante (Compile-Zeit)
final int zaehler = 0;              // Final (Laufzeit-Konstante)

2. Funktionen & Arrow-Syntax

dart
// Normale Funktion
Widget buildButton() {
  return ElevatedButton(
    onPressed: () {},
    child: Text('Klick mich'),
  );
}

// Arrow Function (kurz)
Widget buildText() => Text('Kurz und knapp');

// Callback-Funktion (wichtig für Events!)
ElevatedButton(
  onPressed: () {
    print('Button geklickt!');
  },
  child: Text('Klick'),
)

3. Asynchrone Programmierung (Future, async/await)

dart
// In Flutter sehr wichtig für Netzwerkrequests!
Future<String> ladeDaten() async {
  // Simuliere Netzwerkrequest
  await Future.delayed(Duration(seconds: 2));
  return 'Daten geladen';
}

// Verwendung in Flutter
ElevatedButton(
  onPressed: () async {
    String ergebnis = await ladeDaten();
    print(ergebnis);
  },
  child: Text('Daten laden'),
)

18.6 Interview-Tipps

Tipp 1: Kernkonzepte schnell memorieren

Wichtigste Konzepte:

  1. Widget: Alles ist ein Widget.
  2. StatelessWidget vs. StatefulWidget: Unterschied verstehen.
  3. setState(): Zustand aktualisieren.
  4. Provider: Zustand verwalten.
  5. Hot Reload: Schnelle Entwicklung.

Tipp 2: Fragen beantworten

Vorgehensweise:

  1. Frage verstehen: Stellen Sie sicher, dass Sie die Frage verstanden haben.
  2. Antwort strukturieren: Unterteilen Sie die Antwort in klare Punkte.
  3. Beispiele geben: Verwenden Sie Code-Beispiele, um Ihre Antwort zu verdeutlichen.
  4. Ehrlich sein: Wenn Sie etwas nicht wissen, sagen Sie es ehrlich.

Tipp 3: Praktische Fähigkeiten demonstrieren

Wichtigste Fähigkeiten:

  1. Flutter-Projekt erstellen: flutter create mein_projekt
  2. Widget erstellen: StatelessWidget / StatefulWidget
  3. Layouts erstellen: Row, Column, Stack
  4. Netzwerkrequests: Dio verwenden
  5. Zustandsverwaltung: setState(), Provider

Zusammenfassung

In diesem Kapitel haben Sie:

  • ✅ Grundlegende Konzeptfragen beantwortet
  • ✅ Kernfunktionalitätsfragen beantwortet
  • ✅ Praxisszenario-Fragen beantwortet
  • ✅ Häufige Fehlerpunkte-Fragen beantwortet
  • ✅ Dart-Verbindungsfragen beantwortet
  • ✅ Interview-Tipps gelernt

Nächstes Kapitel: Wir werden Erweiterte Lernswege lernen.


Übungsaufgaben:

  1. Beantworten Sie die Fragen in diesem Kapitel ohne Nachschauen.
  2. Erstellen Sie ein einfaches Flutter-Projekt und erklären Sie den Code.
  3. Üben Sie die Erklärung von Flutter-Konzepten (Widget, setState, Provider).

Häufige Fehler:

  • ❌ Konzepte nicht verstanden → Wiederholen Sie die vorherigen Kapitel!
  • ❌ Praktische Fähigkeiten nicht demonstrieren können → Üben Sie!
  • ❌ Fragen nicht strukturiert beantworten → Üben Sie!

Frei für alle Anfänger