TIL #014
191121 목
오늘 배운 점
<Flutter>
1. Shared Preferences
- key-value 형태의 데이터를 디스크에 저장해서 사용하는 방법..이라고 한다. 앱을 종료한 후 다시 시작해도 shared preference로 관리되는 데이터는 이전에 앱을 실행했을 때의 값을 저장해서 불러오기 때문에 저장된 데이터 값을 출력한다.
- Flutter의 Hello World인 increment counter를 shared preference로 적용한 예시를 확인해보았다.
//@pubspec.yaml
dependencies:
shared_preferences:
import 'package:shared_preferences/shared_preferences.dart';
// shared preference 값 얻기
final prefs = await SharedPreferences.getInstance();
// 데이터 저장
prefs.setInt('counter', counter);
// counter key에서 데이터 읽기. 존재하지 않으면 0 반환
final counter = prefs.getInt('counter') ?? 0;
// 데이터 삭제
prefs.remove('counter');
//예시
const MethodChannel('plugins.flutter.io/shared_preferences')
.setMockMethodCallHandler((MethodCall methodCall) async {
if (methodCall.method == 'getAll') {
return <String, dynamic>{}; // set initial values here if desired
}
return null;
});
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
@override
void initState() {
super.initState();
_loadCounter();
}
//카운터 값 불러오기
_loadCounter() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_counter = (prefs.getInt('counter') ?? 0);
});
}
//클릭할 때마다 카운터 숫자 증가
_incrementCounter() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_counter = (prefs.getInt('counter') ?? 0) + 1;
prefs.setInt('counter', _counter);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
- 아래는 조금 더 응용하여 로그인이 필요할 때 사용자의 ID와 패스워드 등을 기억하는 기능을 구현한 예시다.
SharedPreferences sharedPreferences;
@override
void initState() {
super.initState();
getCredential();
}
_onChanged(bool value) async {
sharedPreferences = await SharedPreferences.getInstance();
setState(() {
checkValue = value;
sharedPreferences.setBool("check", checkValue);
sharedPreferences.setString("username", username.text);
sharedPreferences.setString("password", password.text);
sharedPreferences.commit();
getCredential();
});
}
getCredential() async {
sharedPreferences = await SharedPreferences.getInstance();
setState(() {
checkValue = sharedPreferences.getBool("check");
if (checkValue != null) {
if (checkValue) {
username.text = sharedPreferences.getString("username");
password.text = sharedPreferences.getString("password");
} else {
username.clear();
password.clear();
sharedPreferences.clear();
}
} else {
checkValue = false;
}
});
}
2. Performance profiling
- 나중에 배포 단계가 되었을 때, 아이템 목록을 스크롤링하며 사용자 경험에 불편함이 없는지 테스트를 할 때 이런 식으로 테스트 코드를 작성한다고 한다.
- 우선 이런식으로 스크롤링 테스트 파일을 작성하고,
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp(
items: List<String>.generate(10000, (i) => "Item $i"),
));
}
class MyApp extends StatelessWidget {
final List<String> items;
MyApp({Key key, @required this.items}) : super(key: key);
@override
Widget build(BuildContext context) {
final title = 'Long List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: ListView.builder(
// Add a key to the ListView. This makes it possible to
// find the list and scroll through it in the tests.
key: Key('long_list'),
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
'${items[index]}',
// Add a key to the Text widget for each item. This makes
// it possible to look for a particular item in the list
// and verify that the text is correct
key: Key('item_${index}_text'),
),
);
},
),
),
);
}
}
- 성능을 기록하는 파일을 생성한다.
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';
void main() {
group('Scrollable App', () {
FlutterDriver driver;
setUpAll(() async {
driver = await FlutterDriver.connect();
});
tearDownAll(() async {
if (driver != null) {
driver.close();
}
});
test('verifies the list contains a specific item', () async {
final listFinder = find.byValueKey('long_list');
final itemFinder = find.byValueKey('item_50_text');
// 성능 기록
final timeline = await driver.traceAction(() async {
await driver.scrollUntilVisible(
listFinder,
itemFinder,
dyScroll: -300.0,
);
expect(await driver.getText(itemFinder), 'Item 50');
});
// 좀 더 읽고 이해하기 쉽게 TimelineSummary로 전환
final summary = new TimelineSummary.summarize(timeline);
// disk에 저장
summary.writeSummaryToFile('scrolling_summary', pretty: true);
// json 형태로 timeline을 disk에 작성. chrome://tracing 에서 열 수 있는 형태
summary.writeTimelineToFile('scrolling_timeline', pretty: true);
});
});
}
내일 배울 점
<Flutter>
1. 다중 이미지와 텍스트를 함께 POST할 수 있는 글 작성 기능을 구현할 예정이다.
- 예전에 실습으로 성공했던 이미지 3장 MultipartFile로 한번에 보내기와 TextEditingController로 TextField에 작성된 String을 handleSubmit 함수로 http.post 요청 보내기 기능을 활용하면 될 것 같다.
2. devops 과정에 필요한 내용들을 숙지할 필요가 있을 것 같아서 더 알아봐야겠다.
더보기
- 요즘은 과제하느라 Flutter보다 R을 더 많이 쓰고 있다 하하...
- TIL을 쓸 물리적인 시간이 너무 부족하지만 최대한 짬을 내서 기록해야 겠다.
'삽질하는 개발자 hashblown' 카테고리의 다른 글
프론트엔드 개발자의 TIL #016 (0) | 2019.11.24 |
---|---|
프론트엔드 개발자의 TIL #015 (0) | 2019.11.23 |
프론트엔드 개발자의 TIL #013 (0) | 2019.11.20 |
프론트엔드 개발자의 TIL #012 (0) | 2019.11.18 |
프론트엔드 개발자의 TIL #011 (0) | 2019.11.16 |
댓글