레이블이 java인 게시물을 표시합니다. 모든 게시물 표시

날짜를 선택에 활용되는 DatePickerDialog 예제를 기록하려고 합니다. 해당 예제는 위 그림과 같이 시작 날짜 ~ 끝 날짜를 설정하는 내용을 담고 있습니다.             1. DatePickerDialog (kotlin) class ...

날짜를 선택에 활용되는 DatePickerDialog 예제를 기록하려고 합니다.

해당 예제는 위 그림과 같이 시작 날짜 ~ 끝 날짜를 설정하는 내용을 담고 있습니다.


 

 

 

 

 

 

1. DatePickerDialog (kotlin)

class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding

private var startCalendar = Calendar.getInstance()
private var endCalendar = Calendar.getInstance()
private val dateFormat = SimpleDateFormat("yyyy-MM-dd")

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

startCalendar.add(Calendar.MONTH, -1) // startCalendar 한달 전으로 설정

binding.btnStartDate.text = dateFormat.format(startCalendar.time)
binding.btnEndDate.text = dateFormat.format(endCalendar.time)

binding.btnStartDate.setOnClickListener {
// 날짜 선택 리스너 정의
val onDateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, day ->
startCalendar.set(Calendar.YEAR, year)
startCalendar.set(Calendar.MONTH, month)
startCalendar.set(Calendar.DAY_OF_MONTH, day)

binding.btnStartDate.text = dateFormat.format(startCalendar.time)
}

// DatePickerDialog 생성, 날짜 선택 리스너 등록 및 날짜 설정
val datePickerDialog = DatePickerDialog(
this,
onDateSetListener,
startCalendar.get(Calendar.YEAR),
startCalendar.get(Calendar.MONTH),
startCalendar.get(Calendar.DAY_OF_MONTH)
)

// DatePickerDialog Show
datePickerDialog.show()
}

binding.btnEndDate.setOnClickListener {
// 날짜 선택 리스너 정의
val onDateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, day ->
endCalendar.set(Calendar.YEAR, year)
endCalendar.set(Calendar.MONTH, month)
endCalendar.set(Calendar.DAY_OF_MONTH, day)

binding.btnEndDate.text = dateFormat.format(endCalendar.time)
}

// DatePickerDialog 생성, 날짜 선택 리스너 등록 및 날짜 설정
val datePickerDialog = DatePickerDialog(
this,
onDateSetListener,
endCalendar.get(Calendar.YEAR),
endCalendar.get(Calendar.MONTH),
endCalendar.get(Calendar.DAY_OF_MONTH)
)

// DatePickerDialog Show
datePickerDialog.show()
}
}
}

 

 

 

 

 

 

 

2. DatePickerDialog (java)

public class MainActivity extends AppCompatActivity {

private Calendar startCalendar = Calendar.getInstance();
private Calendar endCalendar = Calendar.getInstance();
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

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

Button btnStartDate = findViewById(R.id.btnStartDate);
Button btnEndDate = findViewById(R.id.btnStartDate);

startCalendar.add(Calendar.MONTH, -1); // startCalendar 한달 전으로 설정

btnStartDate.setText(dateFormat.format(startCalendar.getTime()));
btnEndDate.setText(dateFormat.format(endCalendar.getTime()));

btnStartDate.setOnClickListener(view -> {
// 날짜 선택 리스너 정의
DatePickerDialog.OnDateSetListener onDateSetListener = (v, year, month, day) -> {
startCalendar.set(Calendar.YEAR, year);
startCalendar.set(Calendar.MONTH, month);
startCalendar.set(Calendar.DAY_OF_MONTH, day);

btnStartDate.setText(dateFormat.format(startCalendar.getTime()));
};

// DatePickerDialog 생성, 날짜 선택 리스너 등록 및 날짜 설정
DatePickerDialog datePickerDialog = new DatePickerDialog(
this,
onDateSetListener,
startCalendar.get(Calendar.YEAR),
startCalendar.get(Calendar.MONTH),
startCalendar.get(Calendar.DAY_OF_MONTH)
);

// DatePickerDialog Show
datePickerDialog.show();
});

btnEndDate.setOnClickListener(view -> {
// 날짜 선택 리스너 정의
DatePickerDialog.OnDateSetListener onDateSetListener = (v, year, month, day) -> {
endCalendar.set(Calendar.YEAR, year);
endCalendar.set(Calendar.MONTH, month);
endCalendar.set(Calendar.DAY_OF_MONTH, day);

btnEndDate.setText(dateFormat.format(endCalendar.getTime()));
};

// DatePickerDialog 생성, 날짜 선택 리스너 등록 및 날짜 설정
DatePickerDialog datePickerDialog = new DatePickerDialog(
this,
onDateSetListener,
endCalendar.get(Calendar.YEAR),
endCalendar.get(Calendar.MONTH),
endCalendar.get(Calendar.DAY_OF_MONTH)
);

// DatePickerDialog Show
datePickerDialog.show();
});
}
}

 

 

 

 

3. layout 구성

<layout xmlns:android="http://schemas.android.com/apk/res/android">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:gravity="center"
android:orientation="horizontal">

<Button
android:id="@+id/btnStartDate"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="17dp" />

<TextView
android:layout_width="20dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="~"
android:textSize="17dp" />

<Button
android:id="@+id/btnEndDate"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="17dp" />

</LinearLayout>
</LinearLayout>
</layout>

 

 

 

 

일반적으로 안드로이드를 사용하다 보면 화면을 내리고 싶을 때 홈 버튼을 자주 사용합니다. 이렇게 홈 버튼처럼 앱 화면을 백그라운드로 내리려는 동작을 예제로 작성해보려고 합니다.     1. Home 버튼 (코틀린) class MainActivity :...



일반적으로 안드로이드를 사용하다 보면 화면을 내리고 싶을 때 홈 버튼을 자주 사용합니다.

이렇게 홈 버튼처럼 앱 화면을 백그라운드로 내리려는 동작을 예제로 작성해보려고 합니다.





 

 

1. Home 버튼 (코틀린)

class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.btnHome.setOnClickListener {
homeAction()
}
}

private fun homeAction() {
val intent = Intent(Intent.ACTION_MAIN)
intent.addCategory(Intent.CATEGORY_HOME)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}
}








2. Home 버튼 (자바)

public class MainActivity extends AppCompatActivity {

private ActivityMainBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.btnHome.setOnClickListener(v -> {
homeAction();
});
}

void homeAction() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}

 

 

 

 

 

 

 

3. CATEGORY_HOME

마지막으로 CATEGORY_HOME에 대해서 알아보고 마무리하려고 합니다.

작성된 예제를 보면 Intent를 통해 CATEGORY_HOME에 대한 Activity를 호출하는 형태인데요,

안드로이드 공식 문서를 보면..

CATEGORY_HOME는 부팅 됐을 때의 첫번 째 Home Activity를 나타낸다고 합니다.

해당 Home Activity를 호출하기 때문에 Home 버튼과 같은 동작이 되는것으로 보면 될 것 같습니다.

 

 

 

 

 

 

[Reference]

Android Developer (CATEGORY_HOME)

 

 

 

 

 

ByteArray를 HexString으로, HexString를 ByteArray로 변환하는 방법에 대해서 Java / Kotlin으로 작성하고 간략하게 테스트해 보았습니다.               1. ByteArray to HexString 변환 ...

ByteArray를 HexString으로, HexString를 ByteArray로 변환하는 방법에 대해서

Java / Kotlin으로 작성하고 간략하게 테스트해 보았습니다.

 

 

 

 

 

 

 

1. ByteArray to HexString 변환

ByteArray를 HexString으로 변환하는 방법으로 아래와 같이 작성하였습니다.

문자열로 변환하는 부분에서 %02X의 경우 대문자(ex 1A5F), %02x의 경우 소문자(ex 1a5f)

원하시는 출력 방법을 선택 해주시면 될 것 같습니다.



[Kotlin]

fun toHexString(bytes: ByteArray): String {
val stringBuilder = StringBuilder(bytes.size * 2)
for (byte in bytes) stringBuilder.append(String.format("%02X", byte))
return stringBuilder.toString()
}



[Java]

public String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 2);
for (byte b : bytes) sb.append(String.format("%02X", b));
return sb.toString();
}

 

 

 

 

 

 

 

2. HexString to ByteArray 변환

HexString를 ByteArray으로 변환하는 방법으로 아래와 같이 작성하였습니다.

한 가지 고민해야 하는 부분이 있는데요,

인자로 들어오는 문자열이 hexString이라는 보장이 없기 때문에 

변환하기 전에 hexString 유효성을 확인하는 것이 고려되어야 합니다.

저 같은 경우는 2 Step 단위로 돌아가는 loop 특성상 문자열을 짝수로 맞춰 주는 정도만 추가하였고

try catch를 통해 문제가 생긴다면 유효하지 않은 hexString이라고 판단하고 null 을 반환하도록 하였습니다.



[Kotlin]

fun hexStringToBytes(hex: String): ByteArray? {
// Check valid : Hex String
val hexString =
if (hex.length % 2 == 0) hex
else "0$hex"

val length = hexString.length
return try {
val data = ByteArray(length / 2)
var i = 0
while (i < length) {
val s = hexString.substring(i, i + 2)
data[i / 2] = BigInteger(s, 16).toByte()
i += 2
}
data
} catch (e: Exception) {
e.printStackTrace()
null
}
}



[Java]

public byte[] hexStringToBytes(String hex) {
// Check valid : Hex String
if (hex.length() % 2 != 0) {
hex = "0" + hex;
}

int length = hex.length();
try {
int size = (length / 2);
byte[] data = new byte[size];
for (int i = 0; i < length; i += 2) {
String s = hex.substring(i, i + 2);
data[i / 2] = new BigInteger(s, 16).byteValue();
}
return data;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

 

 

 

 

 

 

 

3. 테스트

아래와 같이 테스트 결과를 확인 할 수 있었습니다.

val bytes = byteArrayOf(1, 5, 10, 100)
Log.d("TEST", "bytes ${bytes.contentToString()}")

// Use Kotlin Function
val hexString = UtilKotlin.toHexString(bytes)
val result = UtilKotlin.hexStringToBytes(hexString)
Log.d("TEST", "hexString $hexString")
Log.d("TEST", "result ${result.contentToString()}")

 

TEST/D  bytes [1, 5, 10, 100]
TEST/D  [ByteArray to HexString] hexString 01050A64
TEST/D  [HexString to ByteArray] result [1, 5, 10, 100]

 


val bytes = byteArrayOf(1, 5, 10, 100)
Log.d("TEST", "bytes ${bytes.contentToString()}")

// Use Java Function
val hexString = UtilJava.toHexString(bytes)
val result = UtilJava.hexStringToBytes(hexString)
Log.d("TEST", "[ByteArray to HexString] hexString $hexString")
Log.d("TEST", "[HexString to ByteArray] result ${result.contentToString()}")


TEST/D  bytes [1, 5, 10, 100]
TEST/D  [ByteArray to HexString] hexString 01050A64
TEST/D  [HexString to ByteArray] result [1, 5, 10, 100]

 

 

 

 

 

 

  IllegalThreadStateException 이 발생하고 앱이 죽는 경우가 생겼습니다. 원인과 해결방법에 대해서 정리합니다.         1. 원인 Thread 객체가 요청된 작업에 대해 적절하지 않은 경우 발생한다고 정의되어있습니다. 대표...

 

IllegalThreadStateException 이 발생하고 앱이 죽는 경우가 생겼습니다.

원인과 해결방법에 대해서 정리합니다.

 

 

 

 

1. 원인

Thread 객체가 요청된 작업에 대해 적절하지 않은 경우 발생한다고 정의되어있습니다.

대표적인 예로 아래와 같이 정의된 Thread 객체를 두 번 호출하는 경우 입니다.

Thread thread = new Thread(() -> {
Log.d("Thread", "thread start!");
});

thread.start();
thread.start();

 

 

 

2. 해결 방법

동일한 Thread 객체로 호출하지 않으면 됩니다.

new Thread(() -> {
Log.d("Thread", "thread run!");
}).start();

new Thread(() -> {
Log.d("Thread", "thread run!");
}).start();

new Thread(() -> {
Log.d("Thread", "thread run!");
}).start();

 

그런데 만약 Thread  동작이 내용도 동일하고 복잡하다고 한다면, 

사용할 때마다 위와 같은 방법은 비효율적입니다.

그렇기 때문에 전역변수를 정의해주고 호출할 때마다 안전하게 thread 실행시키는 함수를 사용하는 방법도 있습니다.

Thread thread = null;
public void startTestThread() {
if (thread != null) {
thread.interrupt();
thread = null;
}

thread = new Thread(() -> {
Log.d("Thread", "thread run!");
});
thread.start();
}
startTestThread();
startTestThread();
startTestThread();

 

 

 

[참고자료]

android developer : IllegalThreadStateException