πŸ’» 개발/Android

[Android] λ°±κ·ΈλΌμš΄λ“œμ—μ„œ μ†ŒμΌ“ ν†΅μ‹ μœΌλ‘œ 이벀트 μˆ˜μ‹  ν›„ μ•Œλ¦Ό

2022. 6. 8. 01:48
λͺ©μ°¨
  1. κ΅¬ν˜„ 문제
  2. ν•΄κ²° 방법
  3. μ½”λ“œ
  4. κ²°κ³Ό
  5. λŠλ‚€ 점

κ΅¬ν˜„ 문제

μ‘Έμ—…ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ©΄μ„œ μ„œλ²„μ—μ„œ νŠΉμ •ν•œ 이벀트λ₯Ό μˆ˜μ‹ ν•˜λ©΄ 이벀트 μ’…λ₯˜μ— 따라 μ„œλ‘œ λ‹€λ₯Έ 2개의 μ•Œλ¦Όμ„ λ„μ–΄μ£ΌλŠ” κΈ°λŠ₯을 κ΅¬ν˜„ν•΄μ•Ό ν–ˆλ‹€. μ†ŒμΌ“ ν†΅μ‹ μœΌλ‘œ 이벀트λ₯Ό μˆ˜μ‹ ν•˜λŠ”λ° Activity μ΄λ™μ΄λ‚˜ Fragment 이동에 관계 없이 μ„œλ²„μ™€ μ—°κ²° κ°€λŠ₯ν•œ μ†ŒμΌ“ 톡신이 ν•„μš”ν–ˆλ‹€.

ν•΄κ²° 방법

MVVMκ³Ό 단일 Activityλ₯Ό μ‚¬μš©ν–ˆκΈ°μ— ActivityλŠ” MainActivity ν•œ 개 λΏμ΄μ—ˆκ³  MainActivity μ—μ„œ μ†ŒμΌ“ 톡신을 κ΅¬ν˜„ν•˜λ©΄ λ˜λŠ” λ¬Έμ œμ˜€λ‹€. ν•˜μ§€λ§Œ 앱을 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μƒν™©μ—μ„œλ„ μ•Œλ¦Όμ„ μˆ˜μ‹ ν•΄μ•Ό ν•  ν•„μš”κ°€ μžˆμ—ˆκ³  이λ₯Ό μœ„ν•΄ Serviceλ₯Ό μ‚¬μš©ν–ˆλ‹€. λ¬Όλ‘  MainActivity μ•ˆμ— ν•΄λ‹Ή κΈ°λŠ₯을 κ΅¬ν˜„ν•  수 μžˆλ‹€. ν•˜μ§€λ§Œ μ†ŒμΌ“ 톡신이 MainActivity μžμ²΄μ— μ’…μ†λ˜λŠ” 상황이 λ°œμƒν•˜κΈ°μ— Service λ₯Ό μ‚¬μš©ν•΄μ„œ λ‘œμ§μ„ λΆ„λ¦¬ν–ˆλ‹€.

μ½”λ“œ

- MainActivity

μš°μ„  MainActivity λΆ€ν„° μ‚΄νŽ΄λ³΄μž. κΈ°λŠ₯κ³Ό κ΄€λ ¨ μ—†λŠ” μ½”λ“œλ“€μ€ μ§€μ›Œλ²„λ Έλ‹€.

class MainActivity(override val ACTIVITY_TAG: String = "MAIN_ACTIVITY") :
    BaseActivity<ActivityMainBinding>(R.layout.activity_main) {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        initViews()
    }

    override fun onDestroy() {
        super.onDestroy()
        val intent = Intent(this@MainActivity, ReceiverService::class.java)
        baseContext.stopService(intent)
    }

    private fun initViews() {
        val intent = Intent(this@MainActivity, ReceiverService::class.java)
        baseContext.startService(intent)
    }
}

MainActivityκ°€ onCreate 됐을 λ•Œ Serviceλ₯Ό μ‹€ν–‰μ‹œν‚¨λ‹€. onDestory 됐을 λ•ŒλŠ” Serviceλ₯Ό μ€‘μ§€ν•˜μ—¬ λ©”λͺ¨λ¦¬λ¦­μ„ λ°©μ§€ν•œλ‹€.

- ReceiverService

λ‹€μŒμ€ Service λ₯Ό μ‚΄νŽ΄λ³΄μž. Service λ₯Ό μƒμ†ν•˜λŠ” ReceiverService λ₯Ό κ΅¬ν˜„ν•˜μ˜€κ³  이 λ•Œ onBind λ₯Ό μ˜€λ²„λΌμ΄λ”© ν•΄μ•Ό ν•œλ‹€. μ°Ύμ•„λ³΄λ‹ˆ onBind 의 경우 λ‹€λ₯Έ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜κ³Ό μ—°κ²°ν•  λ•Œ μ‚¬μš©ν•œλ‹€κ³  ν•œλ‹€. 이 ν”„λ‘œμ νŠΈμ—μ„œλŠ” μ‚¬μš©ν•˜μ§€ μ•Šμ„ λ“― μ‹Άλ‹€. μ•ˆλ“œλ‘œμ΄λ“œ 26 (Android Oreo) μ΄μƒλΆ€ν„°λŠ” λ°±κ·ΈλΌμš΄λ“œμ—μ„œ 앱을 μ‹€ν–‰ν•  경우 μ‚¬μš©μžμ—κ²Œ λ°±κ·ΈλΌμš΄λ“œμ—μ„œ μ•Œλ¦Όμ„ λ„μ–΄μ€˜μ•Ό ν•œλ‹€. 

class ReceiverService : Service() {
    override fun onBind(intent: Intent?): IBinder? {
        TODO("Not yet implemented")
    }

    override fun onCreate() {
        super.onCreate()

        receiveEvent()
    }

    // 이벀트 μˆ˜μ‹ μ„ μœ„ν•΄ λ°±κ·ΈλΌμš΄λ“œμ—μ„œ μž‘λ™
    private fun receiveEvent() {
        val builder = NotificationCompat.Builder(this@ReceiverService, NOTIFICATION_CHANNEL[0])
            .setSmallIcon(R.drawable.ic_baseline_poop_solid_icon)
            .setContentTitle("이벀트 μˆ˜μ‹  쀑")
            .setContentText("이벀트 μˆ˜μ‹ μ„ μœ„ν•΄ λ°±κ·ΈλΌμš΄λ“œμ—μ„œ μž‘λ™ μ€‘μž…λ‹ˆλ‹€.")
            .setPriority(NotificationCompat.FOREGROUND_SERVICE_DEFAULT)

        // Android 26 μ΄μƒλΆ€ν„°λŠ” NotificationChannel 등둝 ν•„μš”
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel =
                NotificationChannel(
                    NOTIFICATION_CHANNEL[0],
                    "λ°±κ·ΈλΌμš΄λ“œμ—μ„œ μ‹€ν–‰",
                    NotificationManager.IMPORTANCE_DEFAULT
                )
            val manager =
                applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }

        startForeground(NOTIFICATION_RECEIVE_MODE, builder.build())
    }
}​

결과적으둜 λ°±κ·ΈλΌμš΄λ“œμ—μ„œ μž‘λ™ν•˜μ§€λ§Œ μ‚¬μš©μžμ—κ²Œ 이λ₯Ό μ•Œλ € ν¬κ·ΈλΌμš΄λ“œλ‘œ μ‹€ν–‰ν•˜λŠ” λŠλ‚Œμ΄λ‹€. λ˜ν•œ μ•Œλ¦Όμ„ κ΅¬ν˜„ν•  λ•Œ μ•Œλ¦Ό 채널을 λ“±λ‘ν•΄μ•Όν•œλ‹€.

μ•Œλ¦Ό 채널

μ•Œλ¦Ό 채널을 λ“±λ‘ν•˜λ©΄ μœ„ μ‚¬μ§„μ²˜λŸΌ μ•± μ„€μ •μ—μ„œ 채널 이름을 확인할 수 μžˆλ‹€.

 

μ‚¬μš©μžμ—κ²Œ λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€κ°€ μ‹€ν–‰λ˜κ³  μžˆλŠ” 것을 μ•Œλ ΈμœΌλ‹ˆ 이제 λ°±κ·ΈλΌμš΄λ“œμ—μ„œ μ†ŒμΌ“ 톡신을 μ§„ν–‰ν•˜λ©΄ λœλ‹€. μ•žμ„œ λ§ν•œ κ²ƒμ²˜λŸΌ μ†ŒμΌ“ 톡신을 톡해 μ„œλ²„λ‘œλΆ€ν„° 이벀트λ₯Ό μˆ˜μ‹ ν•˜κ³  이벀트의 μ’…λ₯˜μ— 따라 각기 λ‹€λ₯Έ μ•Œλ¦Όμ„ λ„μ›Œμ•Όν–ˆλ‹€. μš°μ„  κ°„λ‹¨ν•˜κ²Œ μ„œλ²„μ—μ„œ 1을 μ „μ†‘ν•˜λ©΄ 이벀트 λ°œμƒ μ•Œλ¦Ό, 2λ₯Ό μ „μ†‘ν•˜λ©΄ 이미지 μ„ νƒμ΄λΌλŠ” μ•Œλ¦Όμ„ λ„μ›Œμ£Όλ„λ‘ κ΅¬ν˜„ν–ˆλ‹€.

    private fun connectSocket() {
        var socket: Socket? = null
        var inputStream: InputStream?

        CoroutineScope(Dispatchers.IO).launch {
            try {
                socket = Socket(IP_ADDRESS, PORT_NUMBER)
                do {
                    inputStream = socket?.getInputStream()
                    inputStream?.read().let { data ->
                        when (data) {
                            1 -> occurEventNotification()
                            2 -> selectImageNotification()
                        }
                    }
                    delay(DELAY_TIME)
                } while (true)
            } catch (e: Exception) {
                e.printStackTrace()
            } finally {
                socket?.close()
            }
        }
    }

μš”μ²­μ— λ”°λ₯Έ μž‘μ—…μ„ μ§„ν–‰ν•˜κ³  delay λ₯Ό 톡해 일정 μ‹œκ°„ λŒ€κΈ°ν•œλ‹€.

 

이벀트 λ°œμƒ μ•Œλ¦Όκ³Ό 이미지 선택에 λŒ€ν•œ λ©”μ†Œλ“œλŠ” μ•„λž˜μ™€ κ°™λ‹€. 전체적인 μ½”λ“œλŠ” μœ„μ—μ„œ 봀던 λ°±κ·ΈλΌμš΄λ“œ 싀행을 μœ„ν•΄ μ•Œλ¦Όμ„ λ„μ–΄μ£ΌλŠ” 것과 μœ μ‚¬ν•˜λ‹€. bulider 둜 μ•Œλ¦Όμ— λŒ€ν•œ μ˜΅μ…˜μ„ μ„€μ •ν•˜κ³  μ•Œλ¦Ό 채널을 λ“±λ‘ν•œλ‹€.

	// 이벀트λ₯Ό μˆ˜μ‹ ν–ˆμ„ 경우 μ‚¬μš©μžμ—κ²Œ μ•Œλ¦Ό 전솑
    private fun occurEventNotification() {
        val bitmap = BitmapFactory.decodeStream(URL(IMAGE_URL).openConnection().getInputStream())
        val intent = Intent(this@ReceiverService, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
            putExtra("Fragment", "eventDetailFragment")
        }

        val pendingIntent: PendingIntent =
            PendingIntent.getActivity(this@ReceiverService, 0, intent, 0)

        val builder = NotificationCompat.Builder(this@ReceiverService, NOTIFICATION_CHANNEL[1])
            .setSmallIcon(R.drawable.ic_baseline_poop_solid_icon)
            .setContentTitle("λ°°λ³€ 이벀트 μˆ˜μ‹ ")
            .setContentText("Device 1μ—μ„œ λ°°λ³€ μ΄λ²€νŠΈκ°€ μˆ˜μ‹ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.")
            .setLargeIcon(bitmap)
            .setStyle(
                NotificationCompat.BigPictureStyle()
                    .bigPicture(bitmap)
                    .bigLargeIcon(null)
            )
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)

        // Android 26 μ΄μƒλΆ€ν„°λŠ” NotificationChannel 등둝 ν•„μš”
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel =
                NotificationChannel(
                    NOTIFICATION_CHANNEL[1],
                    "이벀트 λ°œμƒ",
                    NotificationManager.IMPORTANCE_HIGH
                )
            val manager =
                applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }

        NotificationManagerCompat.from(this@ReceiverService)
            .notify(NOTIFICATION_OCCUR_EVENT, builder.build())

        wakeUp()
    }

    private fun selectImageNotification() {
        val intent = Intent(this@ReceiverService, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
            putExtra("Fragment", "deviceDetailFragment")
        }

        val pendingIntent: PendingIntent =
            PendingIntent.getActivity(this@ReceiverService, 1, intent, 0)

        val builder = NotificationCompat.Builder(this@ReceiverService, NOTIFICATION_CHANNEL[2])
            .setSmallIcon(R.drawable.ic_baseline_image_search_24)
            .setContentTitle("ν•™μŠ΅μš© 이미지 선택")
            .setContentText("λͺ¨λΈ 정확도 ν–₯상을 μœ„ν•΄ ν•™μŠ΅μš© 이미지λ₯Ό μ„ νƒν•΄μ£Όμ„Έμš”.")
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)

        // Android 26 μ΄μƒλΆ€ν„°λŠ” NotificationChannel 등둝 ν•„μš”
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel =
                NotificationChannel(
                    NOTIFICATION_CHANNEL[2],
                    "ν•™μŠ΅μš© 이미지 선택",
                    NotificationManager.IMPORTANCE_HIGH
                )
            val manager =
                applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }

        NotificationManagerCompat.from(this@ReceiverService)
            .notify(NOTIFICATION_SELECT_IMAGE, builder.build())

        wakeUp()
    }

 

μ„œλ²„λŠ” Python 을 μ‚¬μš©ν–ˆλ‹€. μ‹€μ œλ‘œ μ„œλ²„μ—μ„œ νŒŒμ΄μ¬μ„ μ‚¬μš©ν•˜κ³  μžˆμ–΄μ„œ λ‘œμ»¬μ—μ„œ ν…ŒμŠ€νŠΈλ₯Ό μ§„ν–‰ν•˜κΈ° μœ„ν–” μ„œλ²„ μ—­μ‹œ Python 으둜 κ΅¬ν˜„ν–ˆλ‹€. ν•΄λ‹Ή μ½”λ“œλŠ” λ‹€λ₯Έ λΈ”λ‘œκ·Έμ— μžˆλŠ” μ½”λ“œλ₯Ό μ°Έκ³ ν–ˆλ‹€.

 

[Python] μ†ŒμΌ“ ν†΅μ‹ ν•˜μ—¬ μ±„νŒ… ν•˜κΈ°

μ•ˆλ…•ν•˜μ„Έμš”! μ˜€λŠ˜μ€ μ„œλ²„μ™€ μ†ŒμΌ“ 톡신 ν•˜μ—¬ ν΄λΌμ΄μ–ΈνŠΈ κ°„ μ±„νŒ…μ„ κ΅¬ν˜„ν•΄λ³΄λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€. ν…ŒμŠ€νŠΈ ν™˜κ²½ - Ubuntu 18.04.5 LTS - Python 3.6.9 1. μ†ŒμΌ“(Socket)μ΄λž€?  μ†ŒμΌ“(Socket)μ΄λž€ λ„€νŠΈμ›Œν¬μƒμ—μ„œ λ™μž‘ν•˜

stickode.tistory.com

import socket
from _thread import *

client_sockets = []  # μ„œλ²„μ— μ ‘μ†ν•œ ν΄λΌμ΄μ–ΈνŠΈ λͺ©λ‘


# μ“°λ ˆλ“œμ—μ„œ μ‹€ν–‰λ˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€.
# μ ‘μ†ν•œ ν΄λΌμ΄μ–ΈνŠΈλ§ˆλ‹€ μƒˆλ‘œμš΄ μ“°λ ˆλ“œκ°€ μƒμ„±λ˜μ–΄ 톡신을 ν•˜κ²Œ λ©λ‹ˆλ‹€.
def threaded(client_socket, addr):
    print('>> Connected by :', addr[0], ':', addr[1])

    # ν΄λΌμ΄μ–ΈνŠΈκ°€ 접속을 λŠμ„ λ•Œ κΉŒμ§€ λ°˜λ³΅ν•©λ‹ˆλ‹€.
    try:
        while True:
            print("1 : 이벀트 λ°œμƒ\n2 : 이미지 μˆ˜μ‹ ")
            command = int(input()).to_bytes(1, byteorder="little", signed=True)
            client_socket.send(command)

    except EOFError:
        print(">> λͺ…령을 μ’…λ£Œν•©λ‹ˆλ‹€.")

    client_socket.close()


# μ„œλ²„ IP 및 열어쀄 포트
HOST = '127.0.0.1'
PORT = 9999

# μ„œλ²„ μ†ŒμΌ“ 생성
print('>> Server Start')
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen()

# ν΄λΌμ΄μ–ΈνŠΈκ°€ μ ‘μ†ν•˜λ©΄ accept ν•¨μˆ˜μ—μ„œ μƒˆλ‘œμš΄ μ†ŒμΌ“μ„ λ¦¬ν„΄ν•©λ‹ˆλ‹€.

# μƒˆλ‘œμš΄ μ“°λ ˆλ“œμ—μ„œ ν•΄λ‹Ή μ†ŒμΌ“μ„ μ‚¬μš©ν•˜μ—¬ 톡신을 ν•˜κ²Œ λ©λ‹ˆλ‹€.

try:
    while True:
        print('>> Wait')
        client_socket, addr = server_socket.accept()
        client_sockets.append(client_socket)
        start_new_thread(threaded, (client_socket, addr))
        print("μ°Έκ°€μž 수 : ", len(client_sockets))
except Exception as e:
    print('μ—λŸ¬λŠ”? : ', e)

finally:
    server_socket.close()

κ²°κ³Ό

이벀트 μ’…λ₯˜μ— 따라 μ„œλ‘œ λ‹€λ₯Έ μ•Œλ¦Όμ„ 띄움

μ •μƒμ μœΌλ‘œ μž‘λ™ν•˜λŠ” 것을 λ³Ό 수 μžˆλ‹€.

λŠλ‚€ 점

μ •μƒμ μœΌλ‘œ μž‘λ™ν•˜κΈ΄ ν•˜μ§€λ§Œ μ—„λ°€νžˆ λ”°μ§€λ©΄ μ™„λ²½ν•œ κ΅¬ν˜„μ€ μ•„λ‹ˆλ‹€. μΉ΄μΉ΄μ˜€ν†‘μ΄λ‚˜ λ‹€λ₯Έ μ–΄ν”Œμ²˜λŸΌ 앱이 μ‹€ν–‰λ˜κ³  μžˆμ§€ μ•Šμ€ μƒν™©μ—μ„œλ„ μ•Œλ¦Όμ„ μˆ˜μ‹ ν•΄μ•Όν•˜μ§€λ§Œ μ§€κΈˆμ€ 앱이 μ‹€ν–‰λ˜κ³  μžˆλŠ” μƒνƒœ(onDestoryλ₯Ό μ œμ™Έν•œ μƒνƒœ)μ—μ„œλ§Œ μ•Œλ¦Όμ΄ λ°œμƒν•œλ‹€. FCM을 μ‚¬μš©ν•˜κ±°λ‚˜ onDestoryμ—μ„œ Serviceλ₯Ό ν•΄μ œν•˜μ§€ μ•ŠλŠ” 방법도 μžˆμ§€λ§Œ λ‚΄κ°€ μ›ν•˜λŠ” 방법이 μ•„λ‹ˆλ‹€. μ°Ύμ•„λ³΄λ‹ˆ WorkManagerλ₯Ό μ‚¬μš©ν•˜λ©΄ κ΅¬ν˜„μ΄ κ°€λŠ₯ν•  λ“― μ‹Άλ‹€. 일단은 μ΄λ ‡κ²Œ κ΅¬ν˜„ν•΄λ‘κ³  λ‚˜μ€‘μ— Migration ν•΄μ•Όκ² λ‹€.

 

λ°±κ·ΈλΌμš΄λ“œ 처리 κ°€μ΄λ“œ  |  Android 개발자  |  Android Developers

λ°±κ·ΈλΌμš΄λ“œ 처리 κ°€μ΄λ“œ λ°±κ·ΈλΌμš΄λ“œ 데이터 μ²˜λ¦¬λŠ” μ‚¬μš©μžμ˜ κΈ°λŒ€μ— λΆ€μ‘ν•˜κ³  μ‚¬μš©μžμ—κ²Œ 도움이 λ˜λŠ” Android μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κ°œλ°œν•˜λŠ” 데 μžˆμ–΄ μ€‘μš”ν•œ λΆ€λΆ„μž…λ‹ˆλ‹€. 이 κ°€μ΄λ“œμ—μ„œλŠ” 백그라운

developer.android.com

 

μ €μž‘μžν‘œμ‹œ λΉ„μ˜λ¦¬ λ³€κ²½κΈˆμ§€ (μƒˆμ°½μ—΄λ¦Ό)

'πŸ’» 개발 > Android' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[Android] μ•Œλ¦Ό ν΄λ¦­μ‹œ Activity, Fragment둜 이동  (0) 2022.06.08
[Android] MVVM νŒ¨ν„΄ 적용기 - 2  (0) 2022.05.14
[Android] MVVM νŒ¨ν„΄ 적용기 - 1  (0) 2022.04.11
[Android] 카메라 λ˜λŠ” κ°€λŸ¬λ¦¬μ—μ„œ 이미지 κ°€μ Έμ˜€κΈ°  (0) 2022.02.06
[Android] λ‹€κ΅­μ–΄ 지원  (0) 2022.01.13
  1. κ΅¬ν˜„ 문제
  2. ν•΄κ²° 방법
  3. μ½”λ“œ
  4. κ²°κ³Ό
  5. λŠλ‚€ 점
'πŸ’» 개발/Android' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€
  • [Android] μ•Œλ¦Ό ν΄λ¦­μ‹œ Activity, Fragment둜 이동
  • [Android] MVVM νŒ¨ν„΄ 적용기 - 2
  • [Android] MVVM νŒ¨ν„΄ 적용기 - 1
  • [Android] 카메라 λ˜λŠ” κ°€λŸ¬λ¦¬μ—μ„œ 이미지 κ°€μ Έμ˜€κΈ°
kodo_o
kodo_o
iOS κΏ€μžΌ!
kodo_o
🍎🍏
kodo_o
전체
였늘
μ–΄μ œ
  • λΆ„λ₯˜ 전체보기 (149)
    • πŸ”¨ ν”„λ‘œμ νŠΈ (0)
      • TP 1 (0)
      • WhiteHCCTV (0)
      • FootPrint (0)
    • πŸ’» 개발 (63)
      • iOS (30)
      • Android (6)
      • Kotlin (4)
      • Flutter (9)
      • Node.js (5)
      • Architecture (1)
      • 였늘의 μ‚½μ§ˆ (7)
      • μ—λŸ¬μ™€μ˜ 동침 (1)
    • ✏️ μ•Œκ³ λ¦¬μ¦˜ (6)
      • Graph (6)
      • String (0)
      • Sort (0)
    • ✍️ μ½”ν…Œ μ€€λΉ„ (44)
      • Math (1)
      • Implementation (3)
      • String (3)
      • Brute Force (5)
      • Back Tracking (7)
      • Greedy (0)
      • Dynamic Programming (13)
      • Binary Search (1)
      • DFS, BFS (5)
      • Shortest Path (2)
      • Two Pointer (4)
      • MST (0)
    • πŸ“š CS (6)
      • Operating System (6)
    • ⛹️ 라이프 (30)
      • 2020 κ²¨μšΈλ°©ν•™ λͺ¨κ°μ½”(개인) (12)
      • 2021 여름방학 λͺ¨κ°μ½”(개인) (6)
      • μ½”λ”© ν…ŒμŠ€νŠΈ (1)
      • 회고 (10)

λΈ”λ‘œκ·Έ 메뉴

  • ν™ˆ
  • κΉƒν—ˆλΈŒ

인기 κΈ€

졜근 κΈ€

졜근 λŒ“κΈ€

hELLO Β· Designed By μ •μƒμš°.
kodo_o
[Android] λ°±κ·ΈλΌμš΄λ“œμ—μ„œ μ†ŒμΌ“ ν†΅μ‹ μœΌλ‘œ 이벀트 μˆ˜μ‹  ν›„ μ•Œλ¦Ό
μƒλ‹¨μœΌλ‘œ

ν‹°μŠ€ν† λ¦¬νˆ΄λ°”

단좕킀

λ‚΄ λΈ”λ‘œκ·Έ

λ‚΄ λΈ”λ‘œκ·Έ - κ΄€λ¦¬μž ν™ˆ μ „ν™˜
Q
Q
μƒˆ κΈ€ μ“°κΈ°
W
W

λΈ”λ‘œκ·Έ κ²Œμ‹œκΈ€

κΈ€ μˆ˜μ • (κΆŒν•œ μžˆλŠ” 경우)
E
E
λŒ“κΈ€ μ˜μ—­μœΌλ‘œ 이동
C
C

λͺ¨λ“  μ˜μ—­

이 νŽ˜μ΄μ§€μ˜ URL 볡사
S
S
맨 μœ„λ‘œ 이동
T
T
ν‹°μŠ€ν† λ¦¬ ν™ˆ 이동
H
H
단좕킀 μ•ˆλ‚΄
Shift + /
⇧ + /

* λ‹¨μΆ•ν‚€λŠ” ν•œκΈ€/영문 λŒ€μ†Œλ¬Έμžλ‘œ 이용 κ°€λŠ₯ν•˜λ©°, ν‹°μŠ€ν† λ¦¬ κΈ°λ³Έ λ„λ©”μΈμ—μ„œλ§Œ λ™μž‘ν•©λ‹ˆλ‹€.