27 Feb 2019
|
Android
Java에서 enum으로 정의한 값을 문자열로 변경하는 방법은 여러가지가 있습니다.
toString 메소드를 오버라이딩
public enum LogLevel {
VERB {
@Override
public String toString() {
return "Verbose";
}
},
INFO {
@Override
public String toString() {
return "Info";
}
},
DEBUG {
@Override
public String toString() {
return "Debug";
}
},
WARN {
@Override
public String toString() {
return "Warning";
}
},
ERROR {
@Override
public String toString() {
return "Error";
}
}
}
public static void main(String[] args) {
System.out.println(LogLevel.INFO);
}
name 메소드 사용하는 방법
public enum LogLevel {
VERB,
INFO,
DEBUG,
WARN,
ERROR,
}
public static void main(String[] args) {
System.out.println(LogLevel.INFO.name());
}
반대로 문자열을 이용해서 Enum을 생성하는 방법
public enum LogLevel {
VERB,
INFO,
DEBUG,
WARN,
ERROR,
}
public static void main(String[] args) {
LogLevel ll = Enum.valueOf(LogLevel.class, "ERROR")
System.out.println(ll.name());
}
16 Feb 2019
|
ROS
ROS 2.0 Crystal 버전부터는 Ubuntu의 apt install 명령어를 이용해서 더욱 더 간편하게 설치할 수 있게 되었습니다.
다음 포스팅은 Ubuntu 18.04 기준이며, 포맷 후 처음 설치하는 과정입니다.
Locale 설정
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8
GPG Key 설치
sudo apt update && sudo apt install curl gnupg2 lsb-release
curl http://repo.ros2.org/repos.key | sudo apt-key add -
sudo sh -c 'echo "deb [arch=amd64,arm64] http://packages.ros.org/ros2/ubuntu `lsb_release -cs` main" > /etc/apt/sources.list.d/ros2-latest.list'
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 0xB01FA116
sudo apt-get update
sudo apt-get install python3-vcstool
기본 컴포넌트 설치
sudo apt update && sudo apt install -y \
build-essential \
cmake \
git \
python3-colcon-common-extensions \
python3-pip \
wget
sudo apt install -y libpython3-dev
python3 -m pip install -U \
argcomplete \
flake8 \
flake8-blind-except \
flake8-builtins \
flake8-class-newline \
flake8-comprehensions \
flake8-deprecated \
flake8-docstrings \
flake8-import-order \
flake8-quotes \
git+https://github.com/lark-parser/lark.git@0.7d \
pytest-repeat \
pytest-rerunfailures \
pytest \
pytest-cov \
pytest-runner \
setuptools
sudo apt install --no-install-recommends -y \
libasio-dev \
libtinyxml2-dev
ROS 2 패키지 설치
export CHOOSE_ROS_DISTRO=crystal # or bouncy or ardent
sudo apt update
sudo apt install ros-$CHOOSE_ROS_DISTRO-desktop
sudo apt install ros-$CHOOSE_ROS_DISTRO-ros-base
그리고 ROS2 실행 환경을 만들려면
source /opt/ros/$CHOOSE_ROS_DISTRO/setup.bash
와 같은 명령어를 실행하면 되며, .bashrc 등에 위 명령어를 추가할 수도 있습니다.
OpenSplice 및 RTI Connext 설치
옵션입니다. ROS2는 기본적으로 fast-rtps를 사용하기 때문에 OpenSplice나 RTI Connext는 추가적으로 설치할 필요는 없습니다. 하지만 경고 메시지 등이 거슬려서 설치를 할 경우에는 아래와 같은 명령어를 이용해서 설치할 수 있습니다.
sudo apt update
sudo apt install ros-$ROS_DISTRO-rmw-opensplice-cpp # for OpenSplice
sudo apt install ros-$ROS_DISTRO-rmw-connext-cpp # for RTI Connext (requires license agreement)
15 Feb 2019
|
Android
drawable/tab_focused.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="10dp"
android:shape="rectangle">
<gradient
android:angle="-90"
android:endColor="#ffcc00"
android:startColor="#ffcc00"/>
</shape>
drawable/tab_pressed.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#FFcccccc"/>
</shape>
</item>
<item
android:bottom="0dp"
android:left="-3dp"
android:right="-3dp"
android:top="-3dp">
<shape
android:shape="rectangle">
<padding
android:bottom="15dp"
android:left="10dp"
android:right="10dp"
android:top="15dp"/>
<stroke
android:color="#FF00ccff"
android:width="2dp"/>
<solid android:color="#00000000"/>
</shape>
</item>
</layer-list>
drawable/tab_selected.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#FFefefef"/>
</shape>
</item>
<item
android:bottom="0dp"
android:left="-3dp"
android:right="-3dp"
android:top="-3dp">
<shape
android:shape="rectangle">
<padding
android:bottom="15dp"
android:left="10dp"
android:right="10dp"
android:top="15dp"/>
<stroke
android:color="#FF00ccff"
android:width="2dp"/>
<solid android:color="#00000000"/>
</shape>
</item>
</layer-list>
drawable/tab_unselected.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#FFefefef"/>
</shape>
</item>
<item
android:bottom="0dp"
android:left="-3dp"
android:right="-3dp"
android:top="-3dp">
<shape
android:shape="rectangle">
<padding
android:bottom="15dp"
android:left="10dp"
android:right="10dp"
android:top="15dp"/>
<stroke
android:color="#FF00ccff"
android:width="2dp"/>
<solid android:color="#00000000"/>
</shape>
</item>
</layer-list>
drawable/tab_indicator.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Non focused states -->
<item android:drawable="@drawable/tab_unselected" android:state_focused="false" android:state_pressed="false" android:state_selected="false"/>
<item android:drawable="@drawable/tab_selected" android:state_focused="false" android:state_pressed="false" android:state_selected="true"/>
<!-- Focused states -->
<item android:drawable="@drawable/tab_focused" android:state_focused="true" android:state_pressed="false" android:state_selected="false"/>
<item android:drawable="@drawable/tab_focused" android:state_focused="true" android:state_pressed="false" android:state_selected="true"/>
<!-- Pressed -->
<item android:drawable="@drawable/tab_pressed" android:state_pressed="true" android:state_selected="true"/>
<item android:drawable="@drawable/tab_pressed" android:state_pressed="true"/>
</selector>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/tab_indicator"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"
android:textSize="12sp"/>
</LinearLayout>
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<< xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TabHost
android:id="@+id/tab_host"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/MenuTabStyle"/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/tab1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="@+id/clearBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Clear"/>
</LinearLayout>
<LinearLayout
android:id="@+id/tab2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="@+id/addRectBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add Rect"/>
</LinearLayout>
<LinearLayout
android:id="@+id/tab3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="@+id/addLineBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add Line"/>
</LinearLayout>
</FrameLayout>
</LinearLayout>
</TabHost>
</LinearLayout>
<FrameLayout
android:id="@+id/canvas_view"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="5"/>
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TabHost tabHost = (TabHost) findViewById(R.id.tab_host);
tabHost.setup();
setNewTab(tabHost, "Normal", R.id.tab1);
setNewTab(tabHost, "Rect", R.id.tab2);
setNewTab(tabHost, "Line", R.id.tab3);
tabHost.setOnTabChangedListener(new OnTabChangeListener() {
@Override
public void onTabChanged(String tabId) {
//TODO
}
});
}
private void setNewTab(TabHost host, String title, int contentID) {
TabHost.TabSpec tabSpec = host.newTabSpec(title);
tabSpec.setIndicator(getTabIndicator(title));
tabSpec.setContent(contentID);
host.addTab(tabSpec);
}
private View getTabIndicator(String title) {
View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.tab_menu, null);
TextView tv = view.findViewById(R.id.textView);
tv.setText(title);
return view;
}
}
13 Feb 2019
|
Android
Reflection을 이용하면 Runtime 환경에서 Java의 Class와 메소드, 파라메터 등의 정보를 얻을 수 있습니다.
파라메터의 경우 데이터 타입과 이름을 얻을 수 있지만, 파라메터의 이름의 경우에는 실제로 선언한 변수명이 아니라
arg1, arg2 등과 같은 변형된 변수명으로 얻게 되어 있습니다. 이는 컴파일되는 도중 컴파일러가 적당한 이름으로 변수명을 변경해버리기 때문인데, Java 버전을 바꾸거나 컴파일 옵션을 수정해서 개발자가 지정한 변수명을 얻을 수는 있습니다.
하지만 기본적으로는 arg1 과 같이 사람이 알아보기 힘든 이름이 되어 버리는데 Annotation을 적절하게 이용하면 이 문제를 조금은 더 수월(?)하게 해결할 수 있습니다.
ParamName1.java
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamName1 {
String name();
}
ParamName2.java
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamName2 {
String name();
}
## Annotation 적용 예제
public class SpeakText extends Action {
String text;
@ParamName1(name="text")
public SpeakText(String text) {
super("SampleClass(" + text + ")");
this.text = text;
}
@ParamName1(name="name")
@ParamName2(name="text")
public SpeakText(String name, String text) {
super(name);
this.text = text;
}
}
## Annotation 정보를 획득하는 예제
Class c = actionClassMap.get(key);
Constructor[] cons = c.getDeclaredConstructors();
for (int i = 0; i < cons.length; i++) {
Log(cons[i].getName() + ", " + cons[i].toString());
Annotation[] anns = cons[i].getAnnotations();
try {
ParamName1 p = (ParamName1) cons[i].getAnnotation(ParamName1.class);
if (p != null) {
Log(" -- Anno : " + p.name());
}
} catch (Exception e) {
e.printStackTrace();
}
try {
ParamName2 p = (ParamName2) cons[i].getAnnotation(ParamName2.class);
if (p != null) {
Log(" -- Anno : " + p.name());
}
} catch (Exception e) {
e.printStackTrace();
}
13 Feb 2019
|
Android
SnowService.java
package com.snowdeer.local_service;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class SnowService extends Service {
int num = 0;
public int getNumber() {
num++;
return num;
}
public class LocalBinder extends Binder {
SnowService getService() {
return SnowService.this;
}
}
final Binder binder = new LocalBinder();
@Override
public IBinder onBind(Intent intent) {
Log.i("snowdeer", "[snowdeer] SnowService - onBind()");
return binder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i("snowdeer", "[snowdeer] SnowService - onUnbind()");
return super.onUnbind(intent);
}
}
MainActivity.java
package com.snowdeer.local_service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.snowdeer.local_service.SnowService.LocalBinder;
public class MainActivity extends AppCompatActivity {
SnowService snowService = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("snowdeer", "[snowdeer] onCreate");
Intent i = new Intent(MainActivity.this, SnowService.class);
startService(i);
bindService(i, mConnection, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
Log.i("snowdeer", "[snowdeer] onDestroy");
}
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("snowdeer", "[snowdeer] onServiceConnected");
snowService = ((LocalBinder)service).getService();
Log.i("snowdeer", "[snowdeer] num: " + snowService.getNumber());
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("snowdeer", "[snowdeer] onServiceDisconnected");
}
};
}