Skip to content

Latest commit

ย 

History

History
552 lines (333 loc) ยท 28 KB

gistfile1.md

File metadata and controls

552 lines (333 loc) ยท 28 KB

์•ˆ๋“œ๋กœ์ด๋“œ ๋กค๋ฆฌํŒ ๊ฐœ๋ฐœ ๋”ฐ๋ผ์žก๊ธฐ

์•ˆ๋“œ๋กœ์ด๋“œ ๋กค๋ฆฌํŒ(5.0) ๋ฒ„์ „์€ ๊ตฌ๊ธ€์ด ์•ˆ๋“œ๋กœ์ด๋“œ๋ฅผ ๋ฐœํ‘œํ•œ ์ดํ›„๋กœ ๊ฐ€์žฅ ํฐ ๋ณ€ํ™”๋ฅผ ์ค€ ์šด์˜์ฒด์ œ๋‹ค. ๊ตฌ๊ธ€์€ ํ—ˆ๋‹ˆ์ปด ์ดํ›„ ๊ณ„์† ์œ ์ง€ํ–ˆ๋˜ ๋””์ž์ธ ์–ธ์–ด 'ํ™€๋กœ(Holo)'๋ฅผ ๋ฒ„๋ฆฌ๊ณ  ์ƒˆ๋กœ์šด ๋””์ž์ธ ์–ธ์–ด์ธ ๋จธํ„ฐ๋ฆฌ์–ผ ๋””์ž์ธ์œผ๋กœ ์•ˆ๋“œ๋กœ์ด๋“œ ์™ธ๊ด€์„ ๋Œ€๋Œ€์ ์œผ๋กœ ๋ณ€๊ฒฝํ–ˆ๋‹ค. ์ด ๋ณ€ํ™”๋Š” ๋‹จ์ˆœํžˆ ๊ฒ‰๋ชจ์Šต์—๋งŒ ๊ทธ์น˜์ง€ ์•Š์•˜๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ๋„ 5000๊ฐœ ์ด์ƒ์˜ API๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ƒ๋‹นํ•œ ์–‘์˜ API๋ฅผ ํ๊ธฐ(deprecated)ํ–ˆ๋‹ค. ART์™€ ํ”„๋กœ์ ํŠธ ๋ณผํƒ€(Project Volta)๋“ฑ์˜ ๊ตฌ์กฐ์ ์ธ ํ˜์‹ ๋„ ๋’ค๋”ฐ๋ž๋‹ค. ์•ˆ๋“œ๋กœ์ด๋“œ ๋กค๋ฆฌํŒ์˜ ๋ชจ๋“  ๋ณ€ํ™”๋ฅผ ํ•œ ๋ฒˆ์˜ ๊ธ€๋กœ ์ „๋ถ€ ๋‹ค๋ฃฐ ์ˆœ ์—†๊ฒ ์ง€๋งŒ, ๊ฐœ๋ฐœ์ž ์ž…์žฅ์—์„œ ๋„์›€์ด ๋  ๋งŒํ•œ ์ฃผ์š” ๋ณ€ํ™”๋“ค์„ ๋ชจ์•„ ์†Œ๊ฐœํ•˜๊ณ ์ž ํ•œ๋‹ค.

๊น€์šฉ์šฑ [email protected] | GDG Korea Android ์˜ค๊ฑฐ๋‚˜์ด์ €. ์˜ํ™”๋ฅผ ๊ด‘์ ์œผ๋กœ ์ข‹์•„ํ•˜๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ์ž๋กœ ์ตœ๊ทผ์—๋Š” Reactive Programming์— ๋น ์ ธ RxJava, RxAndroid์— ๋งค์ง„ํ•˜๊ณ  ์žˆ๋‹ค.

<๊ทธ๋ฆผ 1> ์•ˆ๋“œ๋กœ์ด๋“œ ๋กค๋ฆฌํŒ(5.0)

๋ฐฐํ„ฐ๋ฆฌ ํšจ์œจ

๊ตฌ๊ธ€์€ ์ ค๋ฆฌ๋นˆ(4.1) ์ดํ›„ ์•ˆ๋“œ๋กœ์ด๋“œ์˜ ์ฃผ์š” ์—…๋ฐ์ดํŠธ ๋•Œ๋งˆ๋‹ค ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋‚˜์”ฉ ์ง„ํ–‰ํ–ˆ๋‹ค. ์ ค๋ฆฌ๋นˆ์€ ํ”„๋กœ์ ํŠธ ๋ฒ„ํ„ฐ(Project Butter)๋ฅผ ํ†ตํ•ด ์พŒ์ ํ•œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์–ป์—ˆ๊ณ , ํ‚ท์บฃ(4.4)์€ ํ”„๋กœ์ ํŠธ ์Šค๋ฒจํŠธ(Project Svelte)๋ฅผ ํ†ตํ•ด 512MiB(Mebibyte) ๋ฉ”๋ชจ๋ฆฌ ํ™˜๊ฒฝ์—์„œ๋„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋‚ ๋ ตํ•œ ๋ชธ์„ ๊ฐ–๊ฒŒ ๋๋‹ค. ์ตœ์‹  ๋ฒ„์ „ ๋กค๋ฆฌํŒ(5.0)์€ ํ”„๋กœ์ ํŠธ ๋ณผํƒ€(Project Volta)๋ฅผ ํ†ตํ•ด ์กฐ๊ธˆ ๋” ์ ์€ ์ „๋ ฅ์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํšจ์œจ์„ ๋†’์ด๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ๊ณ ์•ˆํ–ˆ๋‹ค.

JobScheduler

์ƒํ™ฉ์— ๋Œ€ํ•œ ๊ณ ๋ ค๊ฐ€ ์—†๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์€ ๋ฐฐํ„ฐ๋ฆฌ ์‚ฌ์šฉ์— ๋ถ€์ •์ ์ด๋‹ค. ๋„คํŠธ์›Œํฌ๊ฐ€ ์•ˆ์ •์ ์ด์ง€ ์•Š์€ ์ƒํ™ฉ ์†์— ์‚ฌ์šฉ์ž๊ฐ€ ์ดฌ์˜ํ•ด ๋‘” ์‚ฌ์ง„์„ ์„œ๋ฒ„๋กœ ๋ฐฑ์—…ํ•˜๋ฉด ํœด๋Œ€ํฐ์˜ ๋ฐฐํ„ฐ๋ฆฌ๊ฐ€ ๊ธˆ๋ฐฉ ๋ฐ”๋‹ฅ์ด ๋‚  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ๋•Œ๋ฌธ์— ๋„คํŠธ์›Œํฌ๊ฐ€ ์•ˆ์ •์ ์ผ ๋•Œ๋‚˜ ์ถฉ์ „ ์ค‘์— ์‚ฌ์ง„์„ ์—…๋กœ๋“œํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ํšจ์œจ์ ์ด๋‹ค. ๋กค๋ฆฌํŒ์€ JobScheduler API๋ฅผ ๋„์ž…ํ•ด ๋ฐฐํ„ฐ๋ฆฌ์™€ ๋„คํŠธ์›Œํฌ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ์ž‘์—… ๊ณ„ํš์„ ์žก์„ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

JobScheduler API๋Š” ์‚ฌ์šฉ์ž ์ˆ˜์ค€์˜ ํด๋ž˜์Šค์™€ ์•ˆ๋“œ๋กœ์ด๋“œ ์„œ๋น„์Šค๋กœ ๊ตฌ์„ฑ๋ผ ์žˆ๋‹ค. ๋กค๋ฆฌํŒ ์žฅ๋น„๊ฐ€ ์—ฐ๊ฒฐ๋œ PC์—์„œ <๋ฆฌ์ŠคํŠธ 1>์˜ ์ปค๋งจ๋“œ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด JobScheduler์˜ ์•ˆ๋“œ๋กœ์ด๋“œ ์„œ๋น„์Šค๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

$ adb shell service list | grep jobscheduler
25  jobscheduler: [android.app.job.IJobScheduler]

<๋ฆฌ์ŠคํŠธ 1> ์•ˆ๋“œ๋กœ์ด๋“œ ์„œ๋น„์Šค ๋ฆฌ์ŠคํŠธ์—์„œ jobscheduler ์ถ”๊ฐ€๋ฅผ ํ™•์ธ

JobScheduler API๋Š” JobInfo์™€ JobService 2๊ฐœ ๊ฐ์ฒด๋กœ ๊ตฌ์„ฑ๋ผ ์žˆ๋‹ค.

  • JobInfo - ์ž‘์—…์ด ์ˆ˜ํ–‰๋ผ์•ผ ํ•˜๋Š” ์ œ์•ฝ ์ƒํ™ฉ์„ ๊ธฐ์ˆ ํ•œ๋‹ค(๋„คํŠธ์›Œํฌ, ์ถฉ์ „, ์ฃผ๊ธฐ ๋“ฑ).
  • JobService - ๊ณ„ํš๋œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์„œ๋น„์Šค ๊ฐ์ฒด

์ง์ ‘ ์ž‘์—…์„ ์ •์˜ํ•˜๊ณ  ์ˆ˜ํ–‰ํ•ด๋ณด์ž. <๋ฆฌ์ŠคํŠธ 2>๋Š” ์™€์ดํŒŒ์ด ๋„คํŠธ์›Œํฌ๊ฐ€ ์—ฐ๊ฒฐ๋ผ ์žˆ์œผ๋ฉด์„œ ์ถฉ์ „์ด ์ง„ํ–‰๋˜๋Š” ์•ˆ์ „ํ•œ ํ™˜๊ฒฝ์—์„œ๋งŒ MicrosoftwareService ์„œ๋น„์Šค๋ฅผ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•œ ์ฝ”๋“œ๋‹ค. ์ ์ ˆํ•œ ์ฃผ๊ธฐ์™€ ๋ฐ๋“œ๋ผ์ธ๋„ ์„ค์ •ํ–ˆ๋‹ค.

JobInfo job = new JobInfo.Builder(JOB_ID, new ComponentName(this, MicroSoftwareService.class))
        .setRequiredNetworksCapabilities(JobInfo.NETWORK_TYPE_UNMETERED)
        .setPeriodic(15 * DateUtils.HOURS_IN_MILLIS)
        .setRequiresCharging(true)
        .setOverrideDeadline(3600000)
        .build();

JobService mJobService = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
mJobService.scheduleJob(job);

<๋ฆฌ์ŠคํŠธ 2> JobScheduler API ์‚ฌ์šฉ

๋” ์ƒ์„ธํ•œ JobInfo ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์•Œ๊ณ  ์‹ถ์œผ๋ฉด JobInfo.Builder (https://developer.android.com/reference/android/app/job/JobInfo.Builder.html)๋ฅผ ์ฐธ๊ณ ํ•˜์ž.

JobService ํ™•์žฅํ•˜๊ธฐ

JobService ๊ฐ์ฒด์˜ ๊ฒฝ์šฐ ์ผ๋ฐ˜์ ์ธ ์ž‘์—… ์ˆ˜ํ–‰์—๋Š” ์ถฉ๋ถ„ํ•˜์ง€๋งŒ ๋‹ค์–‘ํ•œ ์‘์šฉ ๊ฐœ๋ฐœ ๊ณผ์ •์— ํ™•์žฅ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค. JobService๋Š” ์˜ค๋ฒ„๋ผ์ด๋”ฉ ๊ฐ€๋Šฅํ•œ ๋ฉ”์„œ๋“œ onStartJob๊ณผ onStopJob์„ ๊ฐ€์ง€๋ฉฐ, ์ด๋ฅผ ์ˆ˜์ •ํ•ด ์กฐ๊ธˆ ๋” ์„ธ๋ฐ€ํ•œ ์ž‘์—…์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ์กฐ์œจํ•œ๋‹ค.

JobService์˜ ํ™•์žฅ์„ ์œ„ํ•ด์„œ <๋ฆฌ์ŠคํŠธ 3>๊ณผ ๊ฐ™์ด ๋จผ์ € AndroidManifest.xml์— ์ƒˆ๋กœ์šด ์„œ๋น„์Šค๋ฅผ ๋“ฑ๋กํ•ด์•ผ ํ•œ๋‹ค.

 <service
 android:name="kr.co.imaso.MasoJobService"
 android:permission="android.permission.BIND_JOB_SERVICE"
 android:exported="true" />

<๋ฆฌ์ŠคํŠธ 3> AndroidManifest.xml ๋“ฑ๋ก

<๋ฆฌ์ŠคํŠธ 4>์˜ onStartJob์€ ์ž‘์—…์ด ์‹œ์ž‘๋  ๋•Œ ํ˜ธ์ถœ๋˜๋ฉฐ ๋ณ„๋„๋กœ ์ˆ˜ํ–‰ํ•  ์ž‘์—…์ด ๋“ฑ๋ก๋˜๋Š” ๊ณณ์ด๋‹ค. onStopJob์€ ์ž‘์—…์ด ๋๋‚  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ๊ณณ์ด๋‹ค. ๋ฐ˜ํ™˜ ๊ฐ’ true๋Š” ์˜ค๋ฒ„๋ผ์ด๋”ฉ์ด ๋๊ณ  ์ปค์Šคํ„ฐ๋งˆ์ด์ง•๋œ ์ž‘์—…์ด ์ˆ˜ํ–‰๋์Œ์„ ์˜๋ฏธํ•œ๋‹ค. onStartJob์ด ๋ฆฌํ„ด๋˜๊ธฐ ์ „์— ์ถ”๊ฐ€์ ์œผ๋กœ ํ•ด์•ผํ•  ์ผ์„ ์ˆ˜ํ–‰ํ•˜์ž.

public class MasoJobService extends JobService {

    @Override
    public boolean onStartJob(JobParameters jobParameters) {
        // FIXME: ์ž‘์—…
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        return false;
    }
}

<๋ฆฌ์ŠคํŠธ 4> ํ™•์žฅ๋œ JobService, MasoJobService

๋ฐฐํ„ฐ๋ฆฌ ์ƒํƒœ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ˆ˜ํ–‰๋œ ํ›„ ๋ฐฐํ„ฐ๋ฆฌ์˜ ์ƒํ™ฉ์€ ๊ณ„์† ๋ณ€ํ™”ํ•œ๋‹ค. ์•ˆ๋“œ๋กœ์ด๋“œ ๋กค๋ฆฌํŒ์€ ๋ฐฐํ„ฐ๋ฆฌ ์ƒํ™ฉ ๊ฐœ๊ด„์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๋ช…๋ น dumpsys batterystats๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

$ adb shell dumpsys batterystats โ€”charged kr.co.imaso.MasoActivity

<๋ฆฌ์ŠคํŠธ 5> kr.co.imaso.MasoActivity ํŒจํ‚ค์ง€ ๋ฐฐํ„ฐ๋ฆฌ ์ƒํ™ฉ ํ™•์ธ

์กฐ๊ธˆ ๋” ์ƒ์„ธํ•œ ๋ฐฐํ„ฐ๋ฆฌ ์†Œ๋ชจ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋ฒ„๊ทธ๋ฆฌํฌํŠธ๋ฅผ ์ถœ๋ ฅํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๋ฒ„๊ทธ๋ฆฌํฌํŠธ๋ฅผ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” <๋ฆฌ์ŠคํŠธ 6>๊ณผ ๊ฐ™์€ ๋ช‡ ๊ฐ€์ง€ ์„ค์ • ์ ˆ์ฐจ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

$ adb shell dumpsys batterystats --enable full-wake-history
Enabled: full-wake-history

$ adb shell dumpsys batterystats --reset
Battery stats reset.

<๋ฆฌ์ŠคํŠธ 6> ์ „์ฒด ์›จ์ดํฌ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๊ธฐ๋กํ•˜๋„๋ก ํ™˜๊ฒฝ ์„ค์ •

๋ถ„์„ํ•˜๊ณ  ์‹ถ์€ ์•ฑ์„ ์‚ฌ์šฉํ•œ ํ›„ <๋ฆฌ์ŠคํŠธ 7>์˜ ์ปค๋งจ๋“œ๋ฅผ ์ž…๋ ฅํ•ด ๋ฒ„๊ทธ๋ฆฌํฌํŠธ๋ฅผ ์ถ”์ถœํ•œ๋‹ค.

$ adb bugreport > bugreport.txt

<๋ฆฌ์ŠคํŠธ 7> ๋ฒ„๊ทธ๋ฆฌํฌํŠธ๋ฅผ ํ†ตํ•ด ์›จ์ดํฌ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ์ถ”์ถœ

์ถ”์ถœ๋œ ๋ฒ„๊ทธ๋ฆฌํฌํŠธ์˜ ๋ถ„์„์„ ์œ„ํ•ด ๊ตฌ๊ธ€์ด ๊ณต๊ฐœํ•œ 'Battery Historian(https://github.com/google/battery-historian)'์„ ์‚ฌ์šฉํ•œ๋‹ค. ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—์„œ historian.py๋ฅผ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์•„ ์ ์ ˆํ•œ ๊ณณ์— ์„ค์น˜ํ•œ ํ›„ <๋ฆฌ์ŠคํŠธ 8>์˜ ์ปค๋งจ๋“œ๋ฅผ ์ž…๋ ฅํ•œ๋‹ค.

python historian.py bugreport.txt > bugreport.html 

<๋ฆฌ์ŠคํŠธ 8> Battery Historian์„ ์‚ฌ์šฉํ•˜์—ฌ HTML ๋ฆฌํฌํŠธ๋ฅผ ์ƒ์„ฑ

<๊ทธ๋ฆผ 2> ํžˆ์Šคํ† ๋ฆฌ์–ธ HTML ๋ฆฌํฌํŠธ

๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜

๋กค๋ฆฌํŒ์˜ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜(Notification)์€ ์กฐ๊ธˆ ๋” ์„ธ์‹ฌํ•˜๊ณ  ๊ฐ•๋ ฅํ•˜๊ณ  ๊นŒํƒˆ์Šค๋Ÿฌ์›Œ์กŒ๋‹ค. ํœด๋Œ€ํฐ์„ ์ž ๊ธˆ ์ƒํƒœ๋กœ ํ•ด๋†จ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋ฏผ๊ฐํ•œ ๋ฉ”์‹ ์ € ์ฑ„ํŒ…์ด ์•Œ๋ฆผ์„ ํ†ตํ•ด ๋…ธ์ถœ๋ผ ๋‚œ๊ฐํ–ˆ๋˜ ์‚ฌ๋žŒ๋“ค์—๊ฒ ํฌ์†Œ์‹์ด๋‹ค. ๋Œ€์‹  ์•Œ๋ก๋‹ฌ๋กํ•œ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์€ ์ด์ œ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์—†๊ฒŒ ๋๋‹ค. RemoteControlClient๋ฅผ ์ด์šฉํ•ด ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜๋Š” ๊ฑธ ์ฆ๊ฒผ๋˜ ์‚ฌ๋žŒ๋“ค์€ ์ด์ œ ๊ทธ ๋งŒํผ์˜ ์ž์œ ๋ฅผ ๋งŒ๋ฝํ•˜๊ธฐ ์–ด๋ ค์šธ ๊ฒƒ์ด๋‹ค.

<๊ทธ๋ฆผ 3> ํ—ค์ฆˆ์—… ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜. ์šฐ์„  ์ˆœ์œ„๊ฐ€ ๋†’์€ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์„ ์ž‘์€ ์ฐฝ์œผ๋กœ ํ‘œ์‹œํ•œ๋‹ค.

๋ฝ์Šคํฌ๋ฆฐ์˜ ํ”„๋ผ์ด๋ฒ„์‹œ

์ž ๊ธˆ ์ƒํƒœ์—์„œ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜ ๊ฐ€์‹œ์„ฑ์€ 3๋‹จ๊ณ„๋กœ ๋‚˜๋‰œ๋‹ค.

  • VISIBILITY_PRIVATE - ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜ ์•„์ด์ฝ˜๊ณผ ๊ฐ™์€ ๊ธฐ๋ณธ์ ์ธ ์ •๋ณด๋งŒ ํ‘œ์ถœ๋˜๋ฉฐ ์ƒ์„ธํ•œ ๋‚ด์šฉ์€ ๊ฐ์ถ˜๋‹ค.
  • VISIBILITY_PUBLIC - ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์˜ ์ปจํ…์ธ ๊ฐ€ ๋ณด์ธ๋‹ค.
  • VISIBILITY_SECRET - ์•„์ด์ฝ˜์„ ํฌํ•จํ•ด ์•„๋ฌด ๊ฒƒ๋„ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค.

์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฏผ๊ฐํ•œ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์€ Notification.builder.setVisibility(VISIBILITY_PRIVATE)๋‚˜ VISIBILITY_SECRET์œผ๋กœ ๋ถ„๋ฅ˜ํ•ด ํ”„๋ผ์ด๋ฒ„์‹œ๋ฅผ ๊ฐ•ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐ•ํ™”๋œ ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ

๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์˜ ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋” ์„ธ๋ฐ€ํ•˜๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋๋‹ค. ๊ทธ ๋•๋ถ„์— ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ์— ๋งž์ถฐ ์šด์˜์ฒด์ œ๊ฐ€ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์„ ์ •๋ฆฌํ•ด ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค.

  • setCategory() - ์šด์˜์ฒด์ œ๊ฐ€ ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€ ํžŒํŠธ๋ฅผ ์ค„ ์ˆ˜ ์žˆ๋‹ค(๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์ด ์ „ํ™”, ๋ฉ”์‹œ์ง€, ์•Œ๋žŒ๊ณผ ๊ด€๋ จ์ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค).
  • setPriority() - ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์˜ ์šฐ์„  ์ˆœ์œ„๋ฅผ ๋ณ€๊ฒฝํ•ด ์ค‘์š”๋„์— ๋”ฐ๋ผ ์ •๋ณด๋ฅผ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. PRIORITY_MAX์™€ PRIORITY_HIGH์˜ ๊ฒฝ์šฐ ์ž‘๊ฒŒ ๋–  ์žˆ๋Š” ํ™”๋ฉด์œผ๋กœ ๋‚˜ํƒ€๋‚˜๋ฉฐ ๋™์‹œ์— ์†Œ๋ฆฌ๋ฅผ ๋‚ด๊ฑฐ๋‚˜ ์ง„๋™์„ ์šธ๋ฆฌ๊ฒŒ ๋œ๋‹ค.
  • addPerson() - ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์˜ ๋Œ€์ƒ์„ ํ•œ ์‚ฌ๋žŒ ์ด์ƒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ํŠน์ • ์‚ฌ๋žŒ, ๋˜๋Š” ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์—๊ฒŒ ์ค‘์š”ํ•œ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ์™€ ์šฐ์„ ์ˆœ์œ„์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ Notification ํ•ญ๋ชฉ(http://developer.android.com/reference/android/app/Notification.html)์„ ์ฐธ๊ณ ํ•˜์ž.

๋‹จ์•„ํ•œ ์•„์ด์ฝ˜

๋กค๋ฆฌํŒ์—์„œ๋Š” ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜ ์•„์ด์ฝ˜์˜ ์ •์ฑ…๋„ ๋ณ€๊ฒฝ๋๋‹ค. ์Šค๋ชฐ ์•„์ด์ฝ˜์˜ ์ƒ‰์ƒ์„ ํฐ์ƒ‰๊ณผ ํˆฌ๋ช…์ƒ‰๋งŒ ์“ธ ์ˆ˜ ์žˆ๋Š” ์ œ์•ฝ์ด ์ƒ๊ฒผ๋‹ค. ํ˜„์žฌ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํƒ€๊ฒŸ ๋ฒ„์ „๊ณผ ๋‹จ๋ง๊ธฐ์˜ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ๋ณด์ด์ง€๋งŒ ๋กค๋ฆฌํŒ ์ดํ›„์˜ ํ™˜๊ฒฝ์„ ๊ณ ๋ คํ•  ๋•Œ ์Šค๋ชฐ ์•„์ด์ฝ˜์€ ํฐ์ƒ‰๊ณผ ํˆฌ๋ช…์ƒ‰์œผ๋กœ๋งŒ ๋””์ž์ธ ํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•˜๋‹ค. ๋กค๋ฆฌํŒ์˜ ์Šค๋ชฐ ์•„์ด์ฝ˜์€ setColor๋ฅผ ํ˜ธ์ถœํ•ด ๋ฐฐ๊ฒฝ ์ƒ‰์ƒ์„ ์ •ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ๋‹จ์ƒ‰ ์•„์ด์ฝ˜๊ณผ ๋ฐฐ๊ฒฝ ์ƒ‰์ƒ์˜ ์กฐํ™”๋ฅผ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค(<๋ฆฌ์ŠคํŠธ 9> ์ฐธ๊ณ ).

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
int color = getResources().getColor(R.color.imaso);
builder.setColor(color);
Notification notif = builder.build();

<๋ฆฌ์ŠคํŠธ 9> ๋ฐฐ๊ฒฝ ์ƒ‰์ƒ์ด ๋“ฑ๋ก๋œ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜

NotificationCompat์€ ๊ตฌ ๋ฒ„์ „ ๋‹จ๋ง์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ˜ธํ™˜์„ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ถ”๊ฐ€๋œ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜ ๊ฐ์ฒด์ด๋‹ค. ํ˜ธํ™˜์„ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” build.gralde ํŒŒ์ผ์— <๋ฆฌ์ŠคํŠธ 10>์— ๊ธฐ์ˆ ๋œ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.

dependencies {
  compile 'com.android.support:appcompat-v7:21.0.3'
}

<๋ฆฌ์ŠคํŠธ 10> appcompat ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜์กด์„ฑ ๋“ฑ๋ก

RemoteControlClient์˜ ํ๊ธฐ

RemoteControlClient๊ฐ€ ํ๊ธฐ๋จ์— ๋”ฐ๋ผ ์Œ์•… ์žฌ์ƒ ์•ฑ ๋“ฑ์€ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜ ๋ณ€๊ฒฝ์ด ์š”๊ตฌ๋œ๋‹ค. <๋ฆฌ์ŠคํŠธ 11>์ฒ˜๋Ÿผ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜ ์Šคํƒ€์ผ Notification.MediaStyle์„ ์ƒ์„ฑํ•˜๊ณ  Notification.Builder์˜ ์Šคํƒ€์ผ๋กœ ๋“ฑ๋กํ•ด ์ด์šฉํ•œ๋‹ค.

Notification.Builder builder = new Notification.Builder(this)
    .setSmallIcon(R.drawable.ic_launcher)
    .setContentTitle("๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ์›จ์–ด")
    .setContentText("์•ˆ๋“œ๋กœ์ด๋“œ ๋กค๋ฆฌํŒ")
    .setDeleteIntent(pendingIntent)
    .setStyle(new Notification.MediaStyle());

<๋ฆฌ์ŠคํŠธ 11> MediaStyle ํ˜•์‹์˜ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜

<๋ฆฌ์ŠคํŠธ 12>๊ณผ ๊ฐ™์ด MediaSessionManager ์„œ๋น„์Šค๋ฅผ ์–ป์€ ํ›„ ์„ธ์…˜์„ ๋งŒ๋“ค๊ณ , ๊ทธ ์„ธ์…˜์œผ๋กœ๋ถ€ํ„ฐ ํ† ํฐ์„ ๋ฐ›์•„์™€ ๋ฏธ๋””์–ด ์ปจํŠธ๋กค์— ์„ค์ •ํ•œ๋‹ค.

mManager = (MediaSessionManager) getSystemService(Context.MEDIA_SESSION_SERVICE);
mSession = mManager.createSession("microsoftware session");
mController = MediaController.fromToken(mSession.getSessionToken());

<๋ฆฌ์ŠคํŠธ 12> MediaController ํ™˜๊ฒฝ ์„ค์ •

์„ธ์…˜์˜ TransportControlsCallback์„ ๋“ฑ๋กํ•˜๊ณ , ๊ฐ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์„ ์ƒ์„ฑํ•˜๋„๋ก onPlay, onPause ๋“ฑ์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•œ๋‹ค. <๋ฆฌ์ŠคํŠธ 13>์€ ์ฝœ๋ฐฑ์„ ๋“ฑ๋กํ•˜๋Š” ๊ณผ์ •๊ณผ ์Šค์ผˆ๋ ˆํ†ค์„ ๋Œ€๋žต์ ์œผ๋กœ ๋ณด์—ฌ์ค€๋‹ค. ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•  ๋ฉ”์†Œ๋“œ๋งˆ๋‹ค ๊ฐœ๋ณ„์ ์œผ๋กœ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์„ ์„ค์ •ํ•˜๊ณ  ๋„์›Œ์•ผ ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด onPlay ๋ฉ”์†Œ๋“œ๋Š” ์žฌ์ƒ๊ณผ ๊ด€๋ จ๋œ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์„ ๋„์›Œ์•ผ ํ•œ๋‹ค.

mSession.addTransportControlsCallback(new MediaSession.TransportControlsCallback() {
    @Override
    public void onPlay() {}

    @Override
    public void onPause() {}
    ...
}

<๋ฆฌ์ŠคํŠธ 13> TransportControlsCallback์˜ ๊ฐœ๊ด„๊ณผ ๋“ฑ๋ก ๊ณผ์ •

๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์˜ ์•ก์…˜์„ ๋‹ค๋ฅธ ์„œ๋น„์Šค๋กœ ์—ฐ๊ฒฐ์‹œํ‚ค๊ณ  ํ•ด๋‹น ์„œ๋น„์Šค์—์„œ mController.getTransportControls().play() ๋“ฑ์„ ํ˜ธ์ถœํ•œ๋‹ค.

์˜ค๋ฒ„๋ทฐ

์ตœ๊ทผ ํ™”๋ฉด(recents screen)์ด ์˜ค๋ฒ„๋ทฐ(overview)๋กœ ๋ณ€๊ฒฝ๋๋‹ค. ์ตœ๊ทผ ์ž‘์—…๋“ค์€ 3D๋กœ ๊ฐœ์„ฑ์žˆ๊ฒŒ ๋ Œ๋”๋ง๋˜๋ฉฐ ์—ฌ๋Ÿฌ ๋ฌธ์„œ์™€ ํƒญ์„ ์‰ฝ๊ฒŒ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋„๋ก AppTask๋ฅผ ๋ชจ๋‘ ํ‘œ์ถœํ•œ๋‹ค. ์›น๋ธŒ๋ผ์šฐ์ €์˜ ํƒญ๋“ค์€ ์˜ค๋ฒ„๋ทฐ๋ฅผ ํ†ตํ•ด ์ด๋™ํ•  ์ˆ˜ ์žˆ๊ณ  ๊ตฌ๊ธ€ ๋…์Šค์˜ ์—ฌ๋Ÿฌ ๋ฌธ์„œ๋ฅผ ์˜ค๋ฒ„๋ทฐ ์Šคํฌ๋ฆฐ์—์„œ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋‹ค.

<๊ทธ๋ฆผ 4> ์˜ค๋ฒ„๋ทฐ(overview), ์ตœ๊ทผ ๋ฌธ์„œ(์ž‘์—…, ํƒญ)๋ฅผ 3D ๋ฐ•์Šค๋กœ ํ‘œํ˜„ํ•œ๋‹ค.

์ƒˆ๋กœ์šด ๋„ํ๋จผํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” <๋ฆฌ์ŠคํŠธ 14> ์ฒ˜๋Ÿผ android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT ํ”Œ๋ž˜๊ทธ๋ฅผ ํฌํ•จํ•œ ์•กํ‹ฐ๋น„ํ‹ฐ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

Intent intent = new Intent(this, MicroSoftware.class);
intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
startActivity(intent);

<๋ฆฌ์ŠคํŠธ 14> ๋„ํ๋จผํŠธ๋ฅผ ์˜ค๋ฒ„๋ทฐ์— ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด FLAG_ACTIVITY_NEW_DOCUMENT ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉ

์›น์‚ฌ์ดํŠธ ๋ฌธ์„œ๋„ ์˜ค๋ฒ„๋ทฐ์— ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ์›น ๋ฌธ์„œ์— <๋ฆฌ์ŠคํŠธ 15>์™€ ๊ฐ™์ด ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ theme-color๋ฅผ ์„ค์ •ํ•˜๋ฉด ์˜ค๋ฒ„๋ทฐ ๋ฌธ์„œ ์†์„ฑ์œผ๋กœ ํ…Œ๋งˆ ์ƒ‰์ด ๋“ฑ๋ก๋œ๋‹ค.

<meta name="theme-color" content="#3FFFB5">

<๋ฆฌ์ŠคํŠธ 15> ์˜ค๋ฒ„๋ทฐ๋ฅผ ์œ„ํ•œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ ์šฉ ์›นํŽ˜์ด์ง€

๋Ÿฐํƒ€์ž„ ์—”์ง„ ART

์ดˆ๊ธฐ ์•ˆ๋“œ๋กœ์ด๋“œ์— ํƒ‘์žฌ๋œ ๊ฐ€์ƒ ๋จธ์‹  ๋‹ฌ๋น…(Dalvik)์€ ๋ชจ๋ฐ”์ผ ํ™˜๊ฒฝ์„ ๊ณ ๋ คํ•ด ์ ์€ ๋ฉ”๋ชจ๋ฆฌ, ์ตœ์ ํ™”๋œ ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ, ์ตœ์†Œํ™” ์˜ค๋ฒ„ํ—ค๋“œ ๋“ฑ์ด ๋ชฉํ‘œ์˜€๋‹ค. ์ž์ฃผ ์ˆ˜ํ–‰๋˜๋Š” ๊ตฌ๊ฐ„(ํŠธ๋ ˆ์ด์Šค, trace)์„ ๊ธฐ๊ณ„์–ด ์ฝ”๋“œ๋กœ ๋ฐ”๊พธ๋Š” JIT(Just-in-time) ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋กœ์š”(2.2) ๋ฒ„์ „์—์„œ์•ผ ๋„์ž…๋๋‹ค. ๋‹ฌ๋น…์˜ ๊ธฐ๋ณธ ์ „๋žต์€ ๋‹ฌ๋น… ๋ฐ”์ดํŠธ์ฝ”๋“œ(Dalvik bytecode)๋กœ ๋œ ์ฝ”๋“œ๋ฅผ ํ•œ ์ค„์”ฉ ํ•ด์„ํ•˜๊ณ  ๋ฐ˜๋ณต ์ˆ˜ํ–‰๋˜๋Š” ๊ตฌ๊ฐ„์„ ๊ธฐ๊ณ„์–ด ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ํ•ด ํšจ์œจ์„ ๋†’์ด๋Š” ๊ฒƒ์ด์—ˆ๋‹ค. ํŠธ๋ ˆ์ด์Šค๋ผ ๋ถˆ๋ฆฌ๋Š” ํŠน์ • ๊ตฌ๊ฐ„์„ ๋ฒˆ์—ญํ•˜๋Š” ์ž‘์—…์€ ๋ฉ”์†Œ๋“œ ๋‹จ์œ„๋กœ ๊ธฐ๊ณ„์–ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์‹œ๊ฐ„์ด ์งง๊ฒŒ ์†Œ์š”๋๋‹ค. ๋˜ ๋ณ€ํ™˜๋œ ๊ธฐ๊ณ„์–ด ์ฝ”๋“œ์˜ ์šฉ๋Ÿ‰์ด ์ž‘์•„ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ ๊ณ  CPU ํŒŒ์›Œ๊ฐ€ ๋‚ฎ์€ ์ƒํ™ฉ์— ์ ํ•ฉํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฒฝ๋Ÿ‰ ๊ฐ€์ƒ ๋จธ์‹ ์—์„œ ์‹œ์ž‘ํ•œ ๋‹ฌ๋น…์€ ๊ณ ์„ฑ๋Šฅ๊ณผ ๊ณ ๊ธฐ๋Šฅ์—์„œ ๊ตฌ์กฐ์  ํ•œ๊ณ„๋ฅผ ๋“œ๋Ÿฌ๋ƒˆ๋‹ค.

๊ตฌ๊ธ€์€ ์•ˆ๋“œ๋กœ์ด๋“œ ํ‚ท์บฃ๋ถ€ํ„ฐ ART(Android Runtime)๋ฅผ ์ค€๋น„ํ–ˆ๊ณ  ๋กค๋ฆฌํŒ๋ถ€ํ„ฐ๋Š” ๊ฐ•์ œ ์‚ฌํ•ญ์ด ๋๋‹ค. ART๋Š” AOT(ahead-of-time) ๋ฐฉ์‹์˜ ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์ด๋‹ค. ART์˜ ๋‚ด์žฅ๋œ dex2oat ์œ ํ‹ธ๋ฆฌํ‹ฐ๋Š” ๋‹ฌ๋น…์—์„œ ์“ฐ์ด๋˜ ๋‹ฌ๋น… ๋ฐ”์ดํŠธ์ฝ”๋“œ์™€ ๋ฆฌ์†Œ์Šค ํŒŒ์ผ์ด ํ†ตํ•ฉ๋œ .dex ํŒŒ์ผ์„ ๋ฆฌ๋ˆ…์Šค์—์„œ ๋„๋ฆฌ ์“ฐ์ด๋Š” ์‹คํ–‰ํŒŒ์ผ ํ˜•ํƒœ ELF(Executable and Linkable Format)๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค. dex2oat๋Š” ์•ฑ์˜ ์ดˆ๊ธฐ ์ˆ˜ํ–‰ ์‹œ ํ˜ธ์ถœ๋˜๋ฉฐ ART์˜ AOT๋Š” ์•ฑ์˜ ์ตœ์ดˆ ์ˆ˜ํ–‰ ๊ณผ์ •์— dex2oat ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์ด์šฉ, ์‹คํ–‰ ํŒŒ์ผ์„ ์–ป์–ด๋‚ด๋Š” ๊ธฐ์ˆ ์ธ ์…ˆ์ด๋‹ค. ์ด๋กœ ์ธํ•ด ๋กค๋ฆฌํŒ์€ ์ˆ˜ํ–‰ ์„ฑ๋Šฅ, ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜(GC : Garbage collection)์˜ ์„ฑ๋Šฅ, ํ”„๋กœํŒŒ์ผ๋ง, ๋””๋ฒ„๊น… ๋“ฑ์—์„œ ์ด์ ์„ ์–ป์—ˆ๋‹ค.

<๊ทธ๋ฆผ 5> ๋‹ฌ๋น…๊ณผ ART์˜ ์ฐจ์ด. ๋‹ฌ๋น…์€ DEX ํŒŒ์ผ์—์„œ ์ตœ์ ํ™”๋œ Odex๋ฅผ ์–ป๊ณ  ART๋Š” ์‹คํ–‰ํŒŒ์ผ ELF๋ฅผ ์–ป๋Š”๋‹ค.

์ƒˆ๋กœ์šด ๋ฐฉ์‹์ด ์ ์šฉ๋๊ธฐ ๋•Œ๋ฌธ์— ์•ฑ์— ๋”ฐ๋ผ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. AOT์™€ ๊ณผ๋ จํ•ด์„œ๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ํ”Œ๋žซํผ๊ณผ ๊ด€๋ จ๋œ ์ด์Šˆ๊ฐ€ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ์•ˆ๋“œ๋กœ์ด๋“œ ์ด์Šˆ ๋ฆฌ์ŠคํŠธ(https://code.google.com/p/android/issues/list)๋ฅผ ์ฐธ์กฐํ•˜๋ฉฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ž.

์„ฑ๊ธ‰ํ•œ GC ์ตœ์ ํ™”

GC์˜ ๊ตฌ์กฐ๊ฐ€ ๋ณ€๊ฒฝ๋๊ธฐ ๋•Œ๋ฌธ์— GC_FOR_ALLOC ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋นˆ๋„๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด ๋ช…์‹œ์ ์œผ๋กœ System.gc()๋ฅผ ํ˜ธ์ถœํ•  ํ•„์š”๊ฐ€ ์—†์–ด์กŒ๋‹ค. ํ˜„์žฌ ํ™˜๊ฒฝ์ด ๋‹ฌ๋น…์ด ์•„๋‹Œ ART์ธ ๊ฒƒ์„ ํ™˜์˜ํ•˜๊ธฐ ์œ„ํ•ด <๋ฆฌ์ŠคํŠธ 16>์˜ ์ปค๋งจ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ๋ฒ„์ „ ์ •๋ณด๋ฅผ ์–ป๋Š”๋‹ค.

System.getProperty("java.vm.version")

<๋ฆฌ์ŠคํŠธ 16> ART ํ™˜๊ฒฝ ํ™•์ธ

๋ฒ„์ „ ์ •๋ณด๊ฐ€ 2.0.0 ์ด์ƒ์ธ ๊ฒฝ์šฐ ๋ช…์‹œ์ ์ธ GC ํ˜ธ์ถœ์˜ ํ•„์š”๊ฐ€ ์ค„์–ด๋“ค์—ˆ๋‹ค. ๋ฒ„์ „ ์ •๋ณด์— ๋”ฐ๋ผ GC ํ˜ธ์ถœ์„ ์ œ์™ธํ•˜์ž.

JNI ๋””๋ฒ„๊น…

ART์˜ ์ฑ„ํƒ์— ๋”ฐ๋ผ ๊ธฐ์กด์— ์ž˜ ๋™์ž‘ํ•˜๋˜ JNI ์•ฑ์˜ ๋™์ž‘์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค. JNI์˜ ๋™์ž‘์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์•ˆ๋“œ๋กœ์ด๋“œ์— ํฌํ•จ๋œ CheckJNI ํˆด์ด ๋„์›€์ด ๋œ๋‹ค.

$ adb shell setprop debug.checkjni 1

<๋ฆฌ์ŠคํŠธ 17> JNI ๋””๋ฒ„๊น… ๋ชจ๋“œ ํ™œ์„ฑํ™”

ํ™˜๊ฒฝ์ด ์„ค์ •๋œ ํ›„ JNI ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋œ ์•ฑ์„ ์ˆ˜ํ–‰ํ•  ๋•Œ ์‹œ์Šคํ…œ์€ ์ข…์ข… <๋ฆฌ์ŠคํŠธ 18>๊ณผ ๊ฐ™์ด ๊ฒฝ๊ณ ๋‚˜ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

W JNI WARNING: method declared to return 'Ljava/lang/String;' returned '[B'
W              failed in LJniTest;.exampleJniBug
I "main" prio=5 tid=1 RUNNABLE
I   | group="main" sCount=0 dsCount=0 obj=0x40246f60 self=0x10538
I   | sysTid=15295 nice=0 sched=0/0 cgrp=default handle=-2145061784
I   | schedstat=( 398335000 1493000 253 ) utm=25 stm=14 core=0
I   at JniTest.exampleJniBug(Native Method)
I   at JniTest.main(JniTest.java:11)
I   at dalvik.system.NativeStart.main(Native Method)
I
E VM aborting

<๋ฆฌ์ŠคํŠธ 18> ํ–ฅ์ƒ๋œ ๋””๋ฒ„๊น… ๋ฉ”์‹œ์ง€

ํ–ฅ์ƒ๋œ ๋””๋ฒ„๊ทธ ๋ชจ๋“œ๋ฅผ ์ด์šฉํ•ด ์˜ˆ์ƒ๋˜๋Š” JNI ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ž.

Compacting GC

๊ธฐ์กด ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ๋Š” ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์˜ ์ฃผ์†Œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ๋Š” ์—†์—ˆ๋‹ค. ๋ฐ˜๋ฉด์— ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์˜ ํšจ์œจ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ์•ˆ๋“œ๋กœ์ด๋“œ ART๋Š” ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ์ •๋ฆฌํ•˜๋Š” Compacting GC๋ฅผ ๋„์ž…ํ•˜๊ณ  ์žˆ๋‹ค. Compacting GC๋Š” ๋ฉ”๋ชจ๋ฆฌ์˜ ์—ฐ์†์ ์ธ ๋ฐฐ์น˜๋ฅผ ํ†ตํ•ด ํšจ์œจ์„ฑ์„ ๋†’์ด๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋‹ค. ์—ฐ์†๋œ ๋ฐฐ์น˜๋ฅผ ์œ„ํ•œ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์˜ ์ด๋™์€ ๊ธฐ ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์˜ ์ฃผ์†Œ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค. Get<type>ArrayElements๋ฅผ ํ˜ธ์ถœํ•ด ์ฃผ์†Œ๋ฅผ ์–ป์€ ๊ฒฝ์šฐ ์ ์ ˆํžˆ Release<type>ArrayElements()๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ART ์ƒ์˜ ์ฃผ์†Œ ๊ฐ’์€ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๊ฒƒ์ด๋ผ๋Š” ๊ฑธ ์œ ์˜ํ•˜์ž.

Object ๋ชจ๋ธ ๋ณ€๊ฒฝ

Object ํด๋ž˜์Šค์˜ ํ•„๋“œ ์†์„ฑ์ด private์œผ๋กœ ๋ณ€๊ฒฝ๋๋‹ค. Object ํ•„๋“œ๋ฅผ Reflection์œผ๋กœ ์ ‘๊ทผํ•˜๋Š” ๊ฒฝ์šฐ์— ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.

์ค‘๋ณต๋œ ์ปค์Šคํ…€ ํผ๋ฏธ์…˜ ์„ ์–ธ ๋ฌธ์ œ

<permission android:name= "com.example.gcm.permission.C2D_MESSAGE"
  android:protectionLevel="signature" />

<๋ฆฌ์ŠคํŠธ 19> ์ปค์Šคํ…€ ํผ๋ฏธ์…˜์˜ ๋ณด์•ˆ ๋ ˆ๋ฒจ์€ ์ธ์ฆํ‚ค๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ•œ๋‹ค.

์•ˆ๋“œ๋กœ์ด๋“œ ๋กค๋ฆฌํŒ๋ถ€ํ„ฐ ์ปค์Šคํ…€ ํผ๋ฏธ์…˜์€ ๋™์ผํ•œ ์‚ฌ์ธํ‚ค๋ฅผ ๊ฐ€์ง„ ์•ฑ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณ€๊ฒฝ๋๋‹ค. ์ปค์Šคํ…€ ํผ๋ฏธ์…˜์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” <๋ฆฌ์ŠคํŠธ 19>์™€ ๊ฐ™์ด android:protectionLevel="signature" ๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.

๋งŒ์ผ ๊ฐ™์€ ํผ๋ฏธ์…˜์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ์•ฑ์ด ๋‹ค๋ฅธ ์‚ฌ์ธํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด INSTALL_FAILED_DUPLICATE_PERMISSION ์—๋Ÿฌ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์„ค์น˜๊ฐ€ ๊ฑฐ๋ถ€๋œ๋‹ค. ์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ์•ฑ์˜ targetSDK ๋ฒ„์ „๊ณผ๋Š” ๋ฌด๊ด€ํ•˜๋ฉฐ ๋กค๋ฆฌํŒ ๋””๋ฐ”์ด์Šค์—์„œ๋Š” ๊ฐ•์ œ๋กœ ์ ์šฉ๋˜๋Š” ์‚ฌํ•ญ์ด๋‹ค.

๊ธฐ๋ณธ ํผ๋ฏธ์…˜์œผ๋กœ ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ๊ฐ€๋Šฅํ•œ ์ปค์Šคํ…€ ํผ๋ฏธ์…˜์„ ์“ฐ์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ปค์Šคํ…€ ํผ๋ฏธ์…˜์„ ๋ฐ˜๋“œ์‹œ ์จ์•ผ ํ•œ๋‹ค๋ฉด ํŒจํ‚ค์ง€๋ช…์„ ๋ถ™์—ฌ ๋‹ค๋ฅธ ์ปค์Šคํ…€ ํผ๋ฏธ์…˜๊ณผ ์ถฉ๋Œํ•˜์ง€ ์•Š๋„๋ก ํ•˜๊ณ  ์—ฌ๋Ÿฌ ์•ฑ์—์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์‚ฌ์ธํ‚ค๋ฅผ ์ž˜ ๊ด€๋ฆฌํ•ด์•ผ ํ•œ๋‹ค.

๋ช…์‹œ์ ์ธ ์„œ๋น„์Šค ๋ฐ”์ธ๋“œ

์„œ๋น„์Šค ๋ฐ”์ธ๋“œ๋ฅผ ํ•  ๋•Œ ๋ช…์‹œ์ ์ธ ์ธํ…ํŠธ๋งŒ ๊ฐ€๋Šฅํ•˜๋„๋ก ๋ฐ”๋€Œ์—ˆ๋‹ค. <๋ฆฌ์ŠคํŠธ 20>๊ณผ ๊ฐ™์ด ์•”๋ฌต์ ์ธ ๋ฐ”์ธ๋“œ๋ฅผ ์š”์ฒญํ•  ๊ฒฝ์šฐ์—๋Š” ์‹คํ–‰์‹œ๊ฐ„ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

Intent intent = new Intent(MICROSOFTWARE_BINDING);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

<๋ฆฌ์ŠคํŠธ 20> ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์•”๋ฌต์  ์„œ๋น„์Šค ๋ฐ”์ธ๋”ฉ

๋กค๋ฆฌํŒ์—์„œ ์ œ๋Œ€๋กœ ๋œ ๋ฐ”์ธ๋“œ๋Š” <๋ฆฌ์ŠคํŠธ 21>๊ณผ ๊ฐ™๋‹ค.

Intent intent = new Intent(this, MicroSoftwareService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

<๋ฆฌ์ŠคํŠธ 21> ๋กค๋ฆฌํŒ์—์„œ ๊ถŒ์žฅํ•˜๋Š” ๋ช…์‹œ์  ์„œ๋น„์Šค ๋ฐ”์ธ๋”ฉ

๋จธํ„ฐ๋ฆฌ์–ผ ๋””์ž์ธ

<๊ทธ๋ฆผ 6> ๋จธํ„ฐ๋ฆฌ์–ผ ๋””์ž์ธ

๊ตฌ๊ธ€์˜ ํ†ตํ•ฉ ๋””์ž์ธ ์–ธ์–ด ๋จธํ„ฐ๋ฆฌ์–ผ ๋””์ž์ธ์ด ์•ˆ๋“œ๋กœ์ด๋“œ์— ํ†ตํ•ฉ๋๋‹ค. ์ž‰ํฌ์™€ ์ข…์ด๋ฅผ ์ปจ์…‰์œผ๋กœ ํ•œ ๋‹ค์–‘ํ•œ UX ์ปจ์…‰์ด ๋„์ž…๋๊ณ , ๊ทธ์— ๋”ฐ๋ผ ๋ณ€ํ™”๋œ ๋ถ€๋ถ„๋„ ๋งŽ์ด ์กด์žฌํ•œ๋‹ค. appcompat ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ๊ธฐ์กด ์•ˆ๋“œ๋กœ์ด๋“œ ๋ฒ„์ „์—์„œ๋„ ๋จธํ„ฐ๋ฆฌ์–ผ ๋””์ž์ธ์„ ๋ถ€๋ถ„์ ์œผ๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์€ ๋กค๋ฆฌํŒ ๋””๋ฐ”์ด์Šค์—์„œ๋งŒ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ๋กค๋ฆฌํŒ ๋ฒ„์ „์— ๋ Œ๋”๋ง ์Šค๋ ˆ๋“œ๊ฐ€ ์ถ”๊ฐ€๋๋‹ค. ๋ Œ๋”๋ง ์Šค๋ ˆ๋“œ๋Š” ๋ฉ”์ธ ์Šค๋ ˆ๋“œ(ํ˜น์€ UI ์Šค๋ ˆ๋“œ)์™€ ๋ถ„๋ฆฌ๋œ ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋‹ค๋ฃฌ๋‹ค. ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์“ฐ๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์€ ์พŒ์ ํ•œ ๋ฐ˜๋ฉด์— ์„ธ๋ฐ€ํ•œ ์กฐ์ž‘์ด ์–ด๋ ต๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. ๋กค๋ฆฌํŒ์—์„œ ์ถ”๊ฐ€๋œ ์• ๋‹ˆ๋ฉ”์ด์…˜๋“ค๋„ ๋Œ€๋ถ€๋ถ„ ์ž‘๋™ ์ค‘์— ์กฐ์ž‘์ด ์–ด๋ ค์šด ์›์ƒท ์• ๋‹ˆ๋ฉ”์ด์…˜์ด๋‹ค. ์ด๋ ‡๊ฒŒ ๋กค๋ฆฌํŒ์— ์ถ”๊ฐ€๋œ ์• ๋‹ˆ๋ฉ”์ด์…˜๋“ค์€ ๋ Œ๋”๋ง ์Šค๋ ˆ๋“œ์— ์˜์กด์ ์ธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•„ ๊ตฌํ˜• ๋‹จ๋ง์„ ์œ„ํ•œ ๋ฐฑ ํฌํŒ…์ด ์–ด๋ ต๋‹ค.

๋จธํ„ฐ๋ฆฌ์–ผ ๋””์ž์ธ์„ ์ ์šฉํ•  ๋•Œ๋Š” ์‹œ๊ฐ์ ์ธ ๋ถ€๋ถ„๊ณผ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ถ€๋ถ„์„ ๋ถ„๋ฆฌํ•ด ์•ˆ๋“œ๋กœ์ด๋“œ ๋ฒ„์ „๋ณ„๋กœ ์–ด๋–ป๊ฒŒ ๋Œ€์‘ํ•  ๊ฒƒ์ธ์ง€ ๊ณ ๋ฏผํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

๋จธํ„ฐ๋ฆฌ์–ผ ํ…Œ๋งˆ

๋‹ค์–‘ํ•œ ์•ˆ๋“œ๋กœ์ด๋“œ ๋ฒ„์ „์—์„œ ๋จธํ„ฐ๋ฆฌ์–ผ ๋””์ž์ธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก Theme.AppCompat๋ฅผ ํ™•์žฅํ•œ ๊ฒฝ์šฐ colorPrimary, colorPrimaryDark, colorAccent ๋“ฑ์˜ ์ƒ‰์ƒ์„ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค. Theme.AppCompat๋ฅผ ์œ„ํ•œ ์ƒ‰์ƒ ์„ค์ •์—๋Š” android: ์ ‘๋‘์–ด๊ฐ€ ๋ถ™์ง€ ์•Š๋Š”๋‹ค.

<style name="Theme.MyTheme" parent="Theme.AppCompat.Light">
    <item name="colorPrimary">@color/material_blue_500</item>
    <item name="colorPrimaryDark">@color/material_blue_700</item>
    <item name="colorAccent">@color/material_green_A200</item>
</style>

<๋ฆฌ์ŠคํŠธ 22> ๋‹ค์–‘ํ•œ ์•ˆ๋“œ๋กœ์ด๋“œ ๋ฒ„์ „์„ ์œ„ํ•œ ํ…Œ๋งˆ Theme.AppCompat์˜ ํ™•์žฅ

์•ก์…˜๋ฐ”์˜ ํ๊ธฐ

<๊ทธ๋ฆผ 7> ํˆด๋ฐ”. ์•ก์…˜๋ฐ”๋ฅผ ๋Œ€์ฒดํ•˜๋Š” ์œ ์—ฐํ•œ ์•ฑ ๋ฐ” ์ปดํฌ๋„ŒํŠธ

์•ˆ๋“œ๋กœ์ด๋“œ ํ—ˆ๋‹ˆ์ฝค(3.0)๋ถ€ํ„ฐ ์ ์šฉ๋๋˜ ์•ก์…˜๋ฐ”๊ฐ€ ํ๊ธฐ๋๋‹ค. ์•ก์…˜๋ฐ”๋Š” ๊ตฌ๊ธ€์ด ํ—ˆ๋‹ˆ์ฝค ์ดํ›„ ์ •์ฐฉ์‹œํ‚ค๋ ค๊ณ  ํ–ˆ๋˜ ๊ฐ€์ด๋“œ๋ผ์ธ์˜ ํ•ต์‹ฌ์ด์—ˆ๋‹ค. ๊ทธ ๋•Œ๋ฌธ์— ๊ฐ€์ด๋“œ๋ผ์ธ์„ ๊ฐ•์ œํ•˜๊ธฐ ์œ„ํ•ด ์ปค์Šคํ„ฐ๋งˆ์ด์ง•์ด ์–ด๋ ต๊ฒŒ ๋ผ ์žˆ์—ˆ๋‹ค. ์•ก์…˜๋ฐ”๊ฐ€ ํ๊ธฐ๋˜๊ณ  ํˆด๋ฐ”๊ฐ€ ๋“ค์–ด์˜จ ๊ฒƒ์€ ๋จธํ„ฐ๋ฆฌ์–ผ ๋””์ž์ธ์—์„œ ์กฐ๊ธˆ ๋” ๋‹ค์–‘ํ•œ ์‹œ๋„๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฌธ์„ ์—ด์–ด์ค€ ๊ฒƒ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

ํˆด๋ฐ”๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋จผ์ € appcompat ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ‘œํ•จ๋ผ์•ผ ํ•œ๋‹ค.

dependencies {
    compile "com.android.support:appcompat-v7:21.0.3"
}

<๋ฆฌ์ŠคํŠธ 23> appcompat ๋ผ์ด๋ธŒ๋Ÿฌ์˜ ์˜์กด์„ฑ ์ถ”๊ฐ€

ํˆด๋ฐ”๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋จผ์ € ์•กํ‹ฐ๋น„ํ‹ฐ๋Š” ActionBarActivity๋ฅผ ์ƒ์†๋ฐ›๊ณ  ํ…Œ๋งˆ๋Š” Theme.AppCompat๋ฅผ ์ƒ์†๋ฐ›์•„์•ผ ํ•œ๋‹ค.

ActionBarActivity์˜ ๋ ˆ์ด์•„์›ƒ์— Toolbar๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

<android.support.v7.widget.Toolbar
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary" />

<๋ฆฌ์ŠคํŠธ 24> ์•ก์…˜๋ฐ”์™€ ๋‹ฌ๋ฆฌ ๋ ˆ์ด์•„์›ƒ ์š”์†Œ์˜ ํ•˜๋‚˜์ธ ํˆด๋ฐ”

๋ ˆ์ด์•„์›ƒ์— Toolbar๋ฅผ ์ถ”๊ฐ€ํ•œ ํ›„ ์•กํ‹ฐ๋น„ํ‹ฐ์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

  1. ์•ก์…˜๋ฐ”์ฒ˜๋Ÿผ ์—ฐ๊ฒฐํ•˜๊ธฐ
  2. ๊ทธ๋ƒฅ ์—ฐ๊ฒฐํ•˜๊ธฐ

์•ก์…˜๋ฐ”์ฒ˜๋Ÿผ ํˆด๋ฐ”๋ฅผ ์—ฐ๊ฒฐํ•  ๋•Œ๋Š” setSupportActionBar ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•œ๋‹ค.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.microsoftware_layout);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
}

<๋ฆฌ์ŠคํŠธ 25> setSupportActionBar๋ฅผ ์ด์šฉํ•œ ํˆด๋ฐ”์˜ ์‚ฌ์šฉ

ํˆด๋ฐ”๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ํˆด๋ฐ”์˜ setOnMenuItemClickListener์™€ inflateMenu๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.microsoftware_layout);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

    // Set an OnMenuItemClickListener to handle menu item clicks
    toolbar.setOnMenuItemClickListener(
            new Toolbar.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {
                    // Handle the menu item
                    return true;
                }
    });

    // Inflate a menu to be displayed in the toolbar
    toolbar.inflateMenu(R.menu.microsoftware_menu);
}

<๋ฆฌ์ŠคํŠธ 26> ์•ก์…˜๋ฐ”์™€ ์ƒ๊ด€์—†๋Š” ๋…์ž์ ์ธ ํˆด๋ฐ”์˜ ์‚ฌ์šฉ

๋„ค๋น„๊ฒŒ์ด์…˜ ๋“œ๋กœ์–ด ๋ณ€๊ฒฝํ•˜๊ธฐ

<๊ทธ๋ฆผ 8> ๋จธํ„ฐ๋ฆฌ์–ผ ๋””์ž์ธ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋“œ๋กœ์–ด

๋กค๋ฆฌํŒ์˜ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋“œ๋กœ์–ด๋Š” ํ™”๋ฉด ์ „์ฒด๋ฅผ ๊ฐ€๋ฆฌ๋Š” ํ˜•ํƒœ๋‹ค. ์ด๋ ‡๊ฒŒ ๋“œ๋กœ์–ด๊ฐ€ ํ™”๋ฉด ์ „์ฒด๋ฅผ ๊ฐ€๋ฆฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” <๋ฆฌ์ŠคํŠธ 27>๊ณผ ๊ฐ™์ด ๋ ˆ์ด์•„์›ƒ์—์„œ DrawLayout์ด ํฌํ•จ๋˜๋„๋ก ๋ฐ”๊ฟ”์•ผ ํ•œ๋‹ค.

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="?attr/actionBarSize" />

        <!-- ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ UI -->

    </LinearLayout>

    <View
        android:id="@+id/drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#3F51B5"
        android:fitsSystemWindows="true" />

</android.support.v4.widget.DrawerLayout>

<๋ฆฌ์ŠคํŠธ 27> ๋จธํ„ฐ๋ฆฌ์–ผ ๋””์ž์ธ์— ๋งž์ถฐ ๋ณ€๊ฒฝ๋œ ๋“œ๋กœ์–ด ๋ ˆ์ด์•„์›ƒ

DrawerLayout์„ ๋ฃจํŠธ ๋ ˆ์ด์•„์›ƒ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  Toolbar์™€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ UI๋ฅผ ์†์— ๋‚ดํฌํ•˜๋Š” ํ˜•ํƒœ๋กœ ๋ ˆ์ด์•„์›ƒ์„ ๋ณ€๊ฒฝํ•œ๋‹ค.

ํ›คํžˆ ๋ณด์ด๋Š” ๊ณ ์ƒ๊ธธ, ๊ทธ๋Ÿผ์—๋„ ๊ธฐ๋Œ€ํ•˜๋Š” ์ƒˆ๋กœ์šด ํฌ๋ง

๋กค๋ฆฌํŒ์—์„œ ๋ณ€ํ™”๋œ ๋งŽ์€ ๋ถ€๋ถ„์„ ํ•œ ์ž๋ฆฌ์—์„œ ์„ค๋ช…ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๋งค์šฐ ์–ด๋ ค์šด ์ผ์ด๋‹ค. ๋˜ ์ด ๊ธ€์—์„œ ์„ค๋ช…ํ•˜์ง€ ์•Š์€ ๋ณ€ํ™”๋“ค์ด ์•ž์œผ๋กœ์˜ ์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ์— ๋งŽ์€ ์˜ํ–ฅ์„ ๋ผ์น  ๊ฒƒ์ด๋‹ค. ๊ฐœ๋ฐœ์— ์žˆ์–ด ์žฅ์• ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๊ฒ ์ง€๋งŒ, ๋‹ค๋ฅธ ์ธก๋ฉด์—์„œ ๋ณธ๋‹ค๋ฉด ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ๊ณผ ๋””์ž์ธ์— ์˜ํ•œ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๊ธ์ •์ ์ธ ๋ณ€ํ™”๋„ ๊ธฐ๋Œ€ํ•ด ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์•ˆ๋“œ๋กœ์ด๋“œ ๋กค๋ฆฌํŒ์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ๊ฒฝํ—˜์„ ์„œ๋กœ ๊ณต์œ ํ•˜๋ฉฐ ์กฐ๊ธˆ ๋” ๋‹ฌ์ฝคํ•œ ์•ˆ๋“œ๋กœ์ด๋“œ๋ฅผ ๋งŒ๋‚˜๋ดค์œผ๋ฉด ํ•˜๋Š” ๋ฐ”๋žŒ์ด๋‹ค. ๋‹ค์Œ์€ ๋กค๋ฆฌํŒ์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๊ณต์œ ๋˜๋Š” ์‚ฌ์ดํŠธ๋“ค์ด๋‹ค.