장소 자동 완성 예제

|

장소 검색 텍스트 박스를 자동으로 완성하는 방법입니다. 구글에서 해당 기능을 쉽게 사용할 수 있도록 컴포넌트를 제공하고 있습니다. Place Picker와 마찬가지로 ‘Google Places API for Android’ 라이브러리에대한 Google API Key 등록을 해야 합니다.

장소 자동 완성은 크게 Fragment를 사용하는 방법과 Intent 호출을 이용하는 방법의 두 가지가 있습니다.


Fragment 사용하는 코드

public class PlaceAutocompleteActivity extends AppCompatActivity {

  static final String TAG = "PlaceAutocomplete";
  PlaceAutocompleteFragment autocompleteFragment;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_place_autocomplete);

    autocompleteFragment = (PlaceAutocompleteFragment)
        getFragmentManager().findFragmentById(R.id.place_autocomplete_fragment);

    autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
      @Override
      public void onPlaceSelected(Place place) {
        Log.i(TAG, "Place: " + place.getName());
      }

      @Override
      public void onError(Status status) {
        Log.i(TAG, "An error occurred: " + status);
      }
    });
  }
}


Intent를 이용하는 방법

public class PlaceAutocompleteActivity extends AppCompatActivity {

  int PLACE_AUTOCOMPLETE_REQUEST_CODE = 1;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_place_autocomplete);

    findViewById(R.id.btn_autocomplete).setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        try {
          Intent intent = new PlaceAutocomplete.IntentBuilder(PlaceAutocomplete.MODE_FULLSCREEN)
              .build(PlaceAutocompleteActivity.this);
          startActivityForResult(intent, PLACE_AUTOCOMPLETE_REQUEST_CODE);
        } catch (GooglePlayServicesRepairableException e) {
          // TODO: Handle the error.
        } catch (GooglePlayServicesNotAvailableException e) {
          // TODO: Handle the error.
        }
      }
    });
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == PLACE_AUTOCOMPLETE_REQUEST_CODE) {
      if (resultCode == RESULT_OK) {
        Place place = PlacePicker.getPlace(data, this);
        String toastMsg = String.format("Place: %s", place.getName());
        Toast.makeText(this, toastMsg, Toast.LENGTH_LONG).show();
      }
    }
  }

}

Place Picker 예제

|

Place Picker를 사용하기 위해서는 Google API Key를 등록해야 합니다. Google 라이브러리들 중 ‘Google Places API for Android’를 등록하면 됩니다.


예제 코드

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import com.google.android.gms.location.places.Place;
import com.google.android.gms.location.places.ui.PlacePicker;

public class MainActivity extends AppCompatActivity {

  int PLACE_PICKER_REQUEST = 1;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    findViewById(R.id.btn_place_picker).setOnClickListener(mOnClickListener);
  }

  View.OnClickListener mOnClickListener = new View.OnClickListener() {

    @Override
    public void onClick(View v) {
      switch (v.getId()) {
        case R.id.btn_place_picker:
          callPlacePicker();
          break;
      }
    }
  };

  void callPlacePicker() {
    PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();
    try {
      startActivityForResult(builder.build(this), PLACE_PICKER_REQUEST);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == PLACE_PICKER_REQUEST) {
      if (resultCode == RESULT_OK) {
        Place place = PlacePicker.getPlace(data, this);
        String toastMsg = String.format("Place: %s", place.getName());
        Toast.makeText(this, toastMsg, Toast.LENGTH_LONG).show();
      }
    }
  }
}

Android Studio의 Debug에서의 SHA-1 값 알아내기

|

키스토어(Keystore)의 SHA-1 값이 필요한 경우가 있습니다. 보통 Keystore를 직접 생성하고 콘솔 창에서 SHA-1 값을 확인한다음 해당 Key를 이용해서 배포용 apk 파일을 만드는 경우가 많습니다.

하지만, 개발 도중에 Signed Key를 계속 적용하는 것은 번거롭기 때문에 여기서는 Android Sutdio에서 Debug 모드로 빌드할 때 사용하는 SHA-1 값을 확인하는 방법을 포스팅합니다.


Android Studio에서 SHA-1 값 확인하기

image -fullwidth

Android Studio 오른편에 보면 ‘Gradle’라는 버튼이 있습니다. Gradle 뷰안에서 SHA-1 값을 조회하기를 원하는 프로젝트를 선택한 다음 ‘Tasks → android → signingReport’를 더블 클릭하면 위 그림에서처럼 ‘Gradle Console’에 SHA-1 값이 출력됩니다.

Gradle 뷰 → 프로젝트 선택 → Tasks → android → signingReport


Google 공식 가이드

Google에서는 여기에서 디버그 모드에서의 SHA-1 값을 획득하는 방법을 잘 설명하고 있습니다.

디버그 모드에서 사용하는 Keystore는 debug.keystore 파일이며, 이 파일의 위치는

  • Windows : C:\Users\your_user_name.android\
  • MacOS 및 Linux : ~/.android/

입니다. 해당 위치로 이동하여 다음 커맨드를 입력하면 SHA-1 값을 획득할 수 있습니다.

  • Windows : keystore” -alias androiddebugkey -storepass android -keypass android
  • MacOS 및 Linux : keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

C++11 Future와 Async

|

Thread의 결과값 획득하는 방법

std::futurestd::promise를 이용하면 다른 Thread의 결과값을 쉽게 획득할 수 있습니다. Thread에서 연산을 완료한 후 그 결과값은 promise에 저장합니다. 이후, future를 이용해서 그 값을 획득할 수 있습니다.

Thread 결과값은 다음과 같은 코드를 이용해서 획득가능합니다. Thread의 결과값을 받을 때까지 get() 부분은 Blocking 되어 대기합니다.

  future<T> fut = ...; 
  T res = fut.get();

promise의 사용은 다음과 같이 할 수 있습니다.

  promise prom = ...;
  T val = ...;
  prom.set_value(val);


async 함수

async 함수를 사용하면 특정 함수 등을 Thread로 구동시키고 그 결과를 리턴받을 수 있습니다. 다음과 같은 예제 코드를 살펴보면,

#include <cstdio>
#include <future>

using namespace std;

int fun() {
  for (int i = 1; i <= 10; i++) {
    printf("fun[%d]\n", i);
  }

  return 200;
}

int main() {
  //auto fut = async(fun);
  auto fut = async(launch::async, fun);
  //auto fut = async(launch::deferred, fun);

  for (int i = 1; i <= 10; i++) {
    printf("main[%d]\t", i);
  }
  printf("\n");

  int result = fut.get();

  printf("result : %d\n", result);

  return 0;
}

async를 통해 실행한 결과값을 get() 함수를 이용해서 돌려받을 수 있는 것을 확인할 수 있습니다.

위 예제에서 async 호출하는 부분을 3가지 예시로 들었는데, 만약

  auto fut = async(launch::async, fun);

으로 수행하면, 함수 fun()은 즉시 실행이 되고 그 결과는 future에 저장이 됩니다. (실행해보면 메인 Thread와 별도 Thread가 동시에 돌아가는 것을 확인할 수 있습니다.)


만약, async 부분을 다음과 같이 호출한 경우는

  auto fut = async(fun);    // 또는
  auto fut = async(launch::deferred, fun);

fun() 함수는 바로 실행되는 것이 아니라 ‘int result = fut.get()’ 코드가 실행될 때 fun() 함수가 실행되는 것을 확인할 수 있습니다.

C++11 조건 변수(Condition Variable)

|

조건 변수

조건 변수는 헤더 파일을 `include` 해야 사용할 수 있습니다.

조건 변수를 사용하면 특정 조건이 만족될 때까지 현재 Thread를 Blocking 할 수 있습니다. 이 때 특정 조건으로는 notify 이벤트를 주거나 타임 아웃 등이 될 수 있습니다.

조건 변수는 각 Thread를 Blocking 함으로 호출 순서를 조절하게 해서 결과적으로는 Thread 간 통신을 가능하게 해주는 효과를 가집니다.


조건 변수의 구성

조건 변수는 크게 wait()notify_one()이나 notify_all() 함수를 세트로 구성되어집니다.

notify_one() 함수는 해당 조건 변수를 기다리고 있는 Thread들 중 한 개의 Thread를 깨웁니다. notify_all() 함수는 조건 변수를 기다리는 모든 Thread를 깨웁니다.

wait()를 호출하는 Thread는 먼저 락 객체를 점유하고 있는 상태여야 합니다. wait()를 호출하면 해당 락 객체의 unlock()이 호출되고 Thread가 Blocking 됩니다.


조건 변수의 활용

조건 변수를 가장 잘 활용할 수 있는 예제로 메세지 큐(Message Queue)를 들 수 있습니다.

다음과 같은 코드를 이용해서 Queue에 명령을 집어넣고 notify_one() 이벤트를 날립니다.

  void enqueue(T t) {
    unique_lock<std::mutex> lock(mMutex);
    mQueue.push(t);
    mCondition.notify_one();
  }


또한 해당 Thread는 메세지를 처리하고, 다시 wait()로 Blocking 상태로 들어갑니다.

  T dequeue(void) {
   unique_lock<std::mutex> lock(mMutex);
    while((mIsLoop)&&(mQueue.empty())) {
      mCondition.wait(lock);
    }
    T val = mQueue.front();
    mQueue.pop();
    return val;
  }