본문 바로가기

프로그램/앱인벤터

[문제풀이]앱인벤터2 - "07. 내 차를 찾아줘" 확장하기2 P147-0

앱인벤터2 문제풀이 - 147페이지 "내 차를 찾아줘" 확장하기



1. 이제 친구들끼리 위치를 공유하는 <다들 어디 있어?>라는 앱을 만들어 보자. 이는 친구들과 등산을 하거나 공원에서 놀다가 흩어졌을 때 서로를 찾는 시간을 절약할 수 있을 뿐 아니라, 때로는 생명까지도 구할 수 있다. 여기서 여러 명의 위치 데이터를 공유해야 하므로, TinyDB 대신 TinyWebDB를 사용해야 한다. 데이터베이스에 대한 보다 자세한 내용은 22장을 참조한다.  




아래 그림은 실행화면이다. 


사용자가 "자신의 위치 저장" 버튼을 누르면, 화면 아래에 "위도, 적도"가 표시되며 웹DB에 사용자 이름은 인덱스로 위도, 적도는 데이터값으로 리스트 목록에 추가 저장되고, "동료찾기"란 버튼을 누르면, 가운데 그림처럼 입력된 동료들의 이름이 인텍스 형태로 나열되어 있고, 그 중 한명의 이름을 선택할 때 지도앱으로 그 사람의 위치가 나오도록 구성해 봤다.



  디자이너탭에서 Label, LocationSensor, TinyWebDB, Nodify, Button, ActivityStater를 추가하여 아래와 같은 형태로 만든다. 


블록탭에서 아래와 같이 3개의 전역변수의 선언이 필요하다. 

모든 변수를 "create empty list"로 초기화한다. 

visiterList_2는 동료들의 이름을 리스트형태로 WebDB에 저장하여 Value 값으로 가져올 때 필요한 전역변수고, urlsList2는 동료들 위치를 url형태로 저장하고 리스트형태로 가져올 때, myName2는 동료중 한명이 앱에 접속해서 이름을 입력(responce)할 때 각각의 사용자명이 저장되는 변수다.  


그리고, 사용자가 앱을 열었을 때, 이름을 입력해야만 다음화면으로 들어갈수 있게, 앱이 실행되면 맨처음 실행되는 when Screen1.Initialize do에 call Notifier1.ShowTextDialog massage title cancelable 에 다음 순서대로, "이름을 입력하세요", "사용자로그인", "true"를 입력하여 알림창 이벤트를 설정하고, 사용자의 이름이 입력되면 바뀌는 화면을 처리하기위해 when Notifier1.AfterTextInput do (response) 를 열어 set global myName2 to get response와 set myNameLabel1.Text to join get global myName2, "님 : " 을 넣고, call TinyWebDB1.GetValue tag "name_2", call TinyWebDB1.GetValue tag "urls_2" 를 추가하여 웹에 동료들명단과 URL 리스트 데이터를 웹DB에 요청한다.

  그리고, 앱 처음화면에 사용자의 위치가 자동으로 찍히도록 when LocationSensor1.LocationChanged do (latitude, longitude altitude speed)에 set CurrentAddressDataLabel.Text to LocationSensor1.CurrentAddress와 set CurrentLatLabel.Text to get latitudeset CurrentLongLabel.Text to get longitudeset RememberButton.Enabled to true를 설정해주는데, 이 Changed 블록은 사용자가 이동할 때 마다 수시로 위치센서가 변화하는 것을 처리해 준다. 

  그리고 "자신의 위치"버튼 이벤트를 처리하는 when RememberButton.Click do를 가져와서 자신의 위치를 표시하는 레이블 set RememberedLatLabel.Text to join 에 LocationSensor1.Latitude와 ","와 LocationSensor1.Longitude를 추가하고 이 값을 웹DB에 리스트형태로 저장하기위해, add items to list list item을 2개 꺼내어 첫번째 블록은 add items to list list item(1) get global visiterList_2과 get global myName2를 대입하여, 입력된 동료의 이름을 visiterList_2리스트에, 두번째블록은 add items to list list item(2) get global urlsList2와 join(스트링3개 추가) "https://www.google.com/maps/dir/", 

RememberedLatLabel.Text"/" 로 동료 이름별 위치를 저장한다. 그리고 call TinyWebDB1.StoreValue, tag, valueToStore에 순서대로 name_2get global visiterList_2를, call TinyWebDB1.StoreValue, tag, valueToStore에 순서대로 urls_2get global urlsList2 를 입력한다.



 그리고, TinyWebDB1에서, 리스트를 받아오는 요청을 하는데 GetValue 호출이 여러군데에서 일어나면, 모든 경우를 처리할 수 있게 신중하게 코딩해야하므로 when TinyWebDB1.GotValue do에서 아래 그림처럼 여러가지 설정을 해준다. 여기에서 tagFromWebDB는 매개변수로 저장시점에 이름이 되고, valueFromWebDB는 저장되어진 값(위도, 적도)으로 보면 될 것 같다.


우선, if then(1)를 꺼내어 웹에서 가져온 값에 리스트 데이터가 있는 경우와 없는 경우를 처리하는데, if(1)에 is a list? thing get valueFromWebDB로 데이터가 있는지 확인하고, then(1)에 중첩되는 if then else(1-2)를 꺼내어  if(1-2)에 get tagFromWebDB = "name_2" 와 값이 같은지 확인하고 값이 같으면,  then(1-2)에 set global visiterList_2 to get valueFromWebDB를 그렇지 않으면, else(1-2)에 set global urlsList2 to에 get valueFromWebDB를 넣는다.


그 다음 if then(2)를 꺼내어 if(2)에 length of list list get global visiterList_2 "=" length of list list get global urlsList2 를 넣어서 이름리스트와 위치값리스트의 데이터가 동일한 개수로 들어 있는지 확인한 후, 그렇다면 then(2)에   set FindListPicker1.Elements to 에 get global visiterList_2를 삽입한다.



그리고, "동료찾기" 버튼을 눌렀을 때 구글지도 앱으로 연결되어 선택한 친구의 위도, 적도가 표시되도록 처리하는데 필요한 버튼이벤트 처리를 위해서, when FindListPiker1.AfterPicking do를 꺼내어, set ActivityStart1.Action to 에 "android.intent.action.VIEW"를 set ActivityStart1.DataUri to 에 select list item list, index에 순서대로 get global urlsList2 와 FindListPicker1.SelectionIndex 를 삽입한다.

그리고, 마지막으로 call ActivityStarter1.StartActivity 를 추가하면 된다.


2. 이동한 궤적을 리스트에 기록하는 <Breadcrumb> 앱을 만들어 보자. 여기서 새로운 위치는 일정한 시간이 지나거나 일정한 거리를 이동한 후에 기록해야 한다. GPS는 약간만 이동해도 새로운 좌표를 제공하므로, 많은 양의 위치 데이터가 리스트에 저장되어 메모리 낭비 문제가 발생할 수 있기 때문이다. 이 리스트에 대해서는 19장을 참조한다. 


다음은 완성 후 화면이다.



  디자이너탭에서 Clock을 추가하여 TimerInterval을  5000(=5초)으로 하고, CurrentLatLabel(0.0), Comma(,), CurrentLongLabel(0.0), tempLabel1, StopButton1, TinyWebDB, RememberButton을 넣는다. 


  블록탭에서 initialize global DistanceList to make a list "" 로 리스트 변수선언하고, 

when LcationSensor1.LocationChanged do(0.001초단위 GPS로 위치정보를 가져옴)에 set CurrentLatLabel.Text to get latitudeset CurrentLongLabel.Text to get longitude를 넣고, 화면아래 자동으로 표시될 리스트를 만드는 프로시저를 만드는데, to procedure do(리스트를 만들어 화면에 보여줌) 를 열어서 procedure = "리스트한줄에하나-> 톱니클릭 -> input -> x = list 변경, 이 프로시저에 set tempLabel1.Text to " "for each item in list do(리스트가 행이 아니고, 열로 입력됨) 블럭을 넣고, get list 와 set tempLabel1.Text to join get item"\n(엔터)"tempLabel1.Text 를 넣어서 프로시저를 완성한다. 



그리고 when Clock1.Timer do(0.001초단위로 동작함/수시로 리스트기록되게 할 것임) 를 열어 if then을 삽입하고, if에 CurrentLatLabel.Text0.0 and CurrentLongLabel.Text0.0 을, then에 add items to list list get global DistanceListjoin CurrentLatLabel.Text","CurrentLongLabel.Text를 입력하고, 그 밑에 call 리스트한줄에하나 list get global DistanceListcall TinyWebDB.StoreValue tag Distance_1valueToStore get global DistanceList를 넣어서 마무리 한다. 


그리고 when Screen.Initialize do(앱실행과 동시에 시작됨)에 call TinyWebDB.GetValue tag Distance_1를 넣는다.


그리고 when StopButton1.Click do에 set Clock.TimerEnabled to flase (기록멈춤) / when RememberButton.Click do set Clock.TimerEnabled to true (다시시작)을 넣어서 작업을 마친다. 








<출처 :  David Wolber, Hal Abelson, Ellen Spertus, Liz Looney(2015), 

앱인벤터2(초판)(오일석, 이진선 번역, 서울:한빛아카데미. (원서는 2014년에 출판)>