<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발자를 위한 레시피</title>
    <link>https://recipes4dev.tistory.com/</link>
    <description>Recipes for Developer.</description>
    <language>ko</language>
    <pubDate>Wed, 15 Jul 2026 03:11:23 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>뽀따</managingEditor>
    <item>
      <title>뭘 할까요...?</title>
      <link>https://recipes4dev.tistory.com/178</link>
      <description>&lt;div class=&quot;ppotta-body&quot;&gt;
&lt;h3&gt;고민 중.&lt;/h3&gt;

&lt;p&gt;.END.&lt;/p&gt;
&lt;/div&gt;</description>
      <category>개발 이야기/주저리주저리</category>
      <author>뽀따</author>
      <guid isPermaLink="true">https://recipes4dev.tistory.com/178</guid>
      <comments>https://recipes4dev.tistory.com/178#entry178comment</comments>
      <pubDate>Mon, 2 Dec 2024 22:41:40 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 cat 명령어 사용법. (Linux cat command) - 리눅스 파일 내용 출력.</title>
      <link>https://recipes4dev.tistory.com/177</link>
      <description>&lt;br /&gt;
&lt;div class=&quot;ppotta-body&quot;&gt;

&lt;h3&gt;1. 리눅스 파일 출력.&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;linux_cmd_cat_cat.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PIyPf/btrmxGZ1TfR/lPRzPCvp8sLEKzfH9KG7Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PIyPf/btrmxGZ1TfR/lPRzPCvp8sLEKzfH9KG7Xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PIyPf/btrmxGZ1TfR/lPRzPCvp8sLEKzfH9KG7Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPIyPf%2FbtrmxGZ1TfR%2FlPRzPCvp8sLEKzfH9KG7Xk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;리눅스 cat 명령&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;126&quot; data-filename=&quot;linux_cmd_cat_cat.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;리눅스에서, &lt;strong&gt;텍스트 파일(File)의 내용을 화면에 출력&lt;/strong&gt;하는 방법 중 가장 쉽고 간단한 방법을 선택하라고 한다면, 어떤 명령를 가장 먼저 떠올리게 될까요? 아마 십중팔구 &lt;strong&gt;cat&lt;/strong&gt;을 생각할 것입니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;linux_cmd_cat_print_file.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tn8Wp/btrmjIFmEqe/sbDFaJXu3duokKYTGUTnZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tn8Wp/btrmjIFmEqe/sbDFaJXu3duokKYTGUTnZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tn8Wp/btrmjIFmEqe/sbDFaJXu3duokKYTGUTnZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftn8Wp%2FbtrmjIFmEqe%2FsbDFaJXu3duokKYTGUTnZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;리눅스 파일 내용 출력.&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;126&quot; data-filename=&quot;linux_cmd_cat_print_file.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;cat&lt;/strong&gt; 명령을 사용하면, 명령 뒤에 파일명을 적는 것만으로 파일의 모든 내용을 표준 출력(standard output)에 출력할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;1.1 cat 명령의 동작.&lt;/h4&gt;
&lt;p&gt;&amp;quot;파일의 내용을 출력&amp;quot;하기 위해 사용하는 cat 명령에 대한 정의를 조금 더 형식적인 문장으로 서술해보면, &amp;quot;&lt;strong&gt;cat 명령은 파일(들)을 순서대로 읽고 그 내용을 읽은 순서대로 표준 출력(standard output)에 쓰는 명령&lt;/strong&gt;&amp;quot;이라고 정의할 수 있습니다. 그리고 cat 명령의 설명에서, cat 명령의 동작을 가장 명료하게 나타내는 단어는 &lt;strong&gt;&amp;quot;파일(들)&amp;quot;&lt;/strong&gt; 이라는 것과 &lt;strong&gt;&amp;quot;순서&amp;quot;&lt;/strong&gt;입니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;cat&lt;/strong&gt; 명령의 이름은, &amp;quot;연결 시키다&amp;quot;, &amp;quot;연관시키다&amp;quot; 등의 뜻을 가지고 있는 영단어 &amp;quot;con&lt;strong&gt;cat&lt;/strong&gt;enate&amp;quot;에서 유래되었습니다. 보통 파일 내용을 출력할 때 cat 명령을 사용하는 걸 생각해보면, 연결이라는 뜻을 가진 &amp;quot;concatenate&amp;quot;라는 단어로부터 유래된 이유가 의아할 수도 있을텐데요.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;cat 명령을 가장 많이 사용하는 경우가 파일 내용을 출력할 때이긴 하지만 cat 명령의 진가는 &lt;strong&gt;여러 파일을 입력으로 사용&lt;/strong&gt;하거나, &lt;strong&gt;&amp;quot;|&amp;quot;(pipe) 또는 &amp;quot;&amp;gt;&amp;quot;(redirection)과 결합하여 다른 파일과 프로그램을 &amp;quot;연결&amp;quot;&lt;/strong&gt;할 때 발휘됩니다. 즉, cat 명령은 파일의 내용을 화면에 출력하는 게 목적이 아니라, 하나 이상의 파일을 다른 여러 종류의 파일 또는 프로그램으로 &lt;strong&gt;연결&lt;/strong&gt;시키기 위해 사용한다고 할 수 있습니다. &lt;strong&gt;&amp;quot;concatenate&amp;quot;&lt;/strong&gt; 라는 단어가 가진 뜻대로 말이죠. 결국 파일을 읽어 화면에 출력한다는 것도 파일(FILE)과 표준 출력(stdout)을 연결시키는 것이니, cat이 concatenate로부터 유래된 이유가 마냥 어색하게만 느껴지지는 않을 것입니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그리고 cat 명령은 입력된 순서대로 그 내용을 출력합니다. 만약 여러 파일을 입력으로 사용(&amp;quot;cat FILE1 FILE2 ...&amp;quot;)한다면, 명령줄에 기록된 순서 그대로 출력하게 된다는 것이죠. cat 명령에는 입력에 대한 순서 변경, 필터링, 조작(행 또는 공백 구분과 관련된 일부 기능은 제공)을 위한 옵션이 제공되지 않기 때문에, 좀 더 확장된 기능을 사용하고자 할 때 아쉬움이 느껴질 수도 있을텐데요. 하지만 이러한 단순함이 cat 명령을 리눅스에서 가장 많이 사용되고, 기본이 되는 명령으로 만들어주게 되었다 할 수 있습니다. &amp;quot;concatenate&amp;quot; 라는 단어의 의미처럼, 조금 더 복잡하고 확장이 요구되는 기능은 다른 명령어로 손쉽게 연결(concatenate)시켜서 처리하면 되니까요!&lt;/p&gt;
&lt;h3&gt;2. cat 명령 옵션&lt;/h3&gt;
&lt;p&gt;cat 명령은 아래와 같은 사용 형식 및 옵션을 제공합니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;usage&quot;&gt;
&lt;pre&gt;
    &lt;b&gt;cat [OPTION]... [FILE]...&lt;/b&gt;
      OPTION
        -n        : 모든 라인 앞에 라인 번호 출력. (빈 라인도 번호 출력)
        -b        : 비어 있지 않은 라인에만 번호 출력.
        -E        : 라인의 마지막에 $ 기호 출력. (빈 라인도 $ 기호 출력)
        -T        : 탭 문자를 ^I로 바꿔서 출력.
        -s        : 두 번 이상 연속된 빈 라인(empty line) 출력 안함.
        -v        : 탭(TAB)과 줄바꿈(LFD)을 제외한 nonprinting 문자를 ^, M-를 사용하여 표시.
        -e        : -vE와 결과 같음. 줄바꿈(LFD)을 포함한 nonprinting 문자 표시.
        -t        : -vT와 결과 같음. 탭(TAB)을 포함한 nonprinting 문자 표시.
        -A        : -vET와 같음. 탭(TAB), 줄바꿈(LFD)을 포함한 nonprinting 문자 표시.
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;

&lt;p&gt;cat 명령 뒤에 어떠한 옵션도 사용하지 않고 파일 이름만 입력하면, 파일의 내용을 그대로 화면에 출력합니다. 이는 파일이 두 개 이상인 경우도 마찬가지인데요. cat 명령 뒤에 파일 이름을 나열하면, 나열된 순서대로 파일의 내용이 출력됩니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat FILE              # FILE의 내용을 출력.
$ cat FILE1 FILE2       # FILE1 다음 FILE2 내용을 출력.&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;

&lt;p&gt;만약 파일 이름 대신 &amp;quot;-&amp;quot; 문자를 사용하면, 표준 입력(standard input)을 통해 입력된 내용을 출력할 수 있습니다. (표준 입력으로부터 입력을 완료하기 위해서는 Ctrl + d 키를 입력하면 됩니다.)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat FILE1 - FILE2     # FILE1 출력한 다음 표준 입력(-)으로 입력받은 내용 출력 후 FILE2 내용 출력.&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;

&lt;p&gt;조금 더 자세한 사용법은 아래 예제들을 통해 알아보도록 하겠습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3&gt;3. cat 명령 사용 예&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;cat  사용 예&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;cat 명령 옵션&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#3-1&quot;&gt;파일 내용 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;command&quot;&gt; cat FILE &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#3-2&quot;&gt;파일 생성&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;command&quot;&gt; cat &gt; FILE &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#3-3&quot;&gt;라인마다 번호 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;command&quot;&gt; cat -n FILE &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#3-4&quot;&gt;라인 끝에 $ 문자 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;command&quot;&gt; cat -E FILE &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#3-5&quot;&gt;탭을 ^I 로 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;command&quot;&gt; cat -T FILE &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#3-6&quot;&gt;반복된 공백 라인 무시&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;command&quot;&gt; cat -s FILE &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#3-7&quot;&gt;파일 복사, 합치기, 추가&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;command&quot;&gt; cat FILE &gt; OUT &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#3-8&quot;&gt;파일 사이에 내용 추가&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;command&quot;&gt; cat FILE1 - FILE2 &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#3-9&quot;&gt;파일 내용을 페이지 단위로 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;command&quot;&gt; cat FILE | more &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#3-10&quot;&gt;파일 내용 필터링&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;command&quot;&gt; cat FILE | grep &quot;STR&quot; &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#3-11&quot;&gt;모든 파일 내용 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;command&quot;&gt; cat * &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#3-12&quot;&gt;특정 확장자를 가진 파일 내용 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;command&quot;&gt; cat *.txt &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h4&gt;3.1 파일의 내용을 화면(표준 출력)에 출력. &lt;a id=&quot;3-1&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;cat 명령 뒤에 파일 이름을 나열하면 하나의 파일 또는 여러 파일의 내용을 출력할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat FILE1
This is FILE1.

$ cat FILE2
This is FILE2.

$ cat FILE1 FILE2
This is FILE1.
This is FILE2.&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.2 표준 입력(standard input)으로 입력받은 내용을 파일에 쓰기. &lt;a id=&quot;3-2&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;cat 명령에 파일 이름을 나열하지 않으면 표준 입력으로 입력된 내용을 표준 출력으로 출력하게 됩니다. 이 때 리다이렉션(redirection, &amp;gt; or &amp;gt;&amp;gt;)을 사용하여 표준 입력으로 입력된 내용을 파일에 쓸 수 있습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;실행 순서는 아래와 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1) &amp;quot;cat &amp;gt; NEWFILE&amp;quot; 명령 실행.&lt;/li&gt;
&lt;li&gt;2) 내용 입력.&lt;/li&gt;
&lt;li&gt;3) Ctrl + D 키(EOF, End Of File) 입력.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat &amp;gt; NEWFILE
This is the contents of NEWFILE.
(Ctrl + D)

$ cat NEWFILE
This is the contents of NEWFILE.&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.3 파일 내용 중에서 각 라인 앞에 번호 출력. &lt;a id=&quot;3-3&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;cat 명령에 &amp;quot;-n&amp;quot; 옵션을 사용하여, 줄바꿈(LFD)으로 구분되는 각 라인의 시작 부분에 라인 번호를 출력할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat A.txt
the first line.
the second line.
the third line.

the fifth line.
$ cat -n A.txt
     1  the first line.
     2  the second line.
     3  the third line.
     4
     5  the fifth line.&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;

&lt;p&gt;&amp;quot;-b&amp;quot; 옵션을 사용하면, 비어있는 라인에는 번호를 출력하지 않도록 만들 수 있습니다. (위 -n 출력 결과와 비교해 보세요.)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat -b A.txt
     1  the first line.
     2  the second line.
     3  the third line.

     4  the fifth line.&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.4 라인 마지막에 구분 문자($) 표시. &lt;a id=&quot;3-4&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&amp;quot;-E&amp;quot; 옵션을 사용하면, 각 라인의 가장 마지막에 &amp;quot;$&amp;quot;로 표시되는 구분 문자를 출력할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat A.txt
the first line.
the second line.
the third line.

the fifth line.
$ cat -E A.txt
the first line.$
the second line.$
the third line.$
$
the fifth line.$&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.5 탭(TAB) 문자 대신 &amp;quot;^I&amp;quot; 대신 출력. &lt;a id=&quot;3-5&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;파일의 내용에 탭(TAB) 문자가 포함된 경우, 탭을 그대로 출력하는 대신 &amp;quot;^I&amp;quot;를 출력되게 만들 수 있습니다. 탭(TAB)의 경우 화면에 그대로 출력하게 되면 스페이스(SPACE)와의 구분이 쉽지 않을 수 있기 때문에 &amp;quot;^I&amp;quot;로 대신 출력하여 탭 문자를 쉽게 구분되게 만들 수 있습니다. 이 때 &amp;quot;-T&amp;quot; 옵션을 사용합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat FILE.txt
sequence: 1 tab 2 tab 3
1        2       3

$ cat -T FILE.txt
sequence: 1 tab 2 tab 3
1 ^I 2 ^I 3&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.6 두 번 이상 연속된 빈 라인(empty line) 출력 안함. &lt;a id=&quot;3-6&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;빈 라인(empty line)이 두 번 이상 연속될 때, 하나의 빈 라인만 출력되게 만들기 위해 &amp;quot;-s&amp;quot; 옵션을 사용합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat B.txt
the first line.
the second line.
the third line.



the seventh line.
$ cat -s B.txt
the first line.
the second line.
the third line.

the seventh line.&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.7 파일 복사, 합치기, 추가. &lt;a id=&quot;3-7&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;출력 리다이렉션(redirection)을 사용해 cp 명령처럼 파일을 복사할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat FILE
This is FILE.
$ cat FILE &amp;gt; COPIED
$ cat COPIED
This is FILE.&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;

&lt;p&gt;여러 개의 파일을 입력으로 사용하여 하나의 파일로 합칠 수도 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat A.txt
This is A.
$ cat B.txt
This is B.
$ cat A.txt B.txt &amp;gt; C.txt
$ cat C.txt
This is A.
This is B.&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;

&lt;p&gt;출력 어펜드(append)를 사용하면 파일의 내용을 다른 파일 뒤에 추가할 수 있습니다. 아래 예제는 위 파일 합치기 예제와 똑같은 동작을 수행합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat A.txt
This is A.
$ cat B.txt
This is B.
$ cat A.txt &amp;gt; C.txt
$ cat B.txt &amp;gt;&amp;gt; C.txt
$ cat C.txt
This is A.
This is B.&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.8 파일 사이에 내용 추가하기. &lt;a id=&quot;3-8&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;앞서 &amp;quot;2. cat 명령&amp;quot;에서, cat 명령 다음에 파일 이름 대신 &amp;quot;-&amp;quot; 를 사용하면 표준 입력을 통해 입력받은 내용을 출력할 수 있다고 설명했었습니다. 이 기능을 사용하면, 여러 파일을 합칠 때 파일 사이에 사용자가 원하는 임의의 내용을 추가할 수 있습니다. (사용자 입력을 완료할 때, Ctrl + D (EOF)키를 사용한다는 것을 기억하세요.)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat A.txt
This is A.
$ cat B.txt
This is B.
$ cat A.txt - B.txt &amp;gt; C.txt
==========
$ cat C.txt
This is A.
==========
This is B.&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.9 화면에 표시 가능한 영역을 넘어가는 내용을 페이지 단위로 보기. &lt;a id=&quot;3-9&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;cat 으로 출력하고자 하는 내용이 화면 영역보다 많은 경우, cat 명령 결과를 보기 위해 스크롤을 사용해야 하는데요. 이 때, more 명령을 파이프(|)와 결합해서 사용하면, 화면 페이지 단위로 내용을 확인할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat /etc/services | more
# Network services, Internet style
#
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, officially ports have two entries
# even if the protocol doesn&amp;#39;t support UDP operations.
...
...
tacacs          49/udp
--More--&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;

&lt;p&gt;페이지 마지막에 &amp;quot;--More--&amp;quot;라고 표시되어 있는 상태가, cat 명령에 의한 출력을 more 명령에서 페이지 단위로 표시하고 있다는 것을 나타냅니다. 이 상태에서 엔터(ENTER)를 입력하면 한 라인을 추가로 출력하고, 스페이스(SPACE)를 입력하면 다음 페이지를 출력합니다. 모든 내용이 출력되면 자동으로 실행이 종료되며, more 실행 중간에 빠져나오려면 &amp;quot;--More--&amp;quot;가 표시된 상태에서 &amp;quot;q&amp;quot;를 입력하면 됩니다.&lt;/p&gt;
&lt;h4&gt;3.10 파일 내용 중 특정 문자열이 포함된 라인만 출력. &lt;a id=&quot;3-10&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;앞서 cat 명령에는 문자열 검색(필터링) 기능을 위한 옵션이 없다고 말씀드렸는데요. 파이프(|)를 사용해 grep 명령을 조합하여, 파일의 내용 중 특정 문자열이 포함된 라인을 출력할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat A.txt
the first line.
the second line.
the third line.

the fifth line.

$ cat A.txt | grep &amp;quot;first&amp;quot;
the first line.&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.11 모든 파일 내용 출력. &lt;a id=&quot;3-11&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;cat 명령 다음에 특정 파일 이름 대신 *문자를 사용하여 현재 디렉토리에 있는 모든 파일의 내용을 출력할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat FILE1
This is FILE1.
$ cat FILE2
This is FILE2.
$ cat *
This is FILE1.
This is FILE2.&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.12 특정 확장자를 가진 파일 내용만 출력. &lt;a id=&quot;3-12&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;* 문자와 특정 문자열을 조합하여 문자열 필터링된 파일 이름을 가진 파일의 내용만 출력할 수 있습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STR* : STR로 시작하는 모든 파일 내용 출력.&lt;/li&gt;
&lt;li&gt;*STR* : STR이 포함된 모든 파일 내용 출력.&lt;/li&gt;
&lt;li&gt;*STR : STR로 끝나는 모든 파일 내용 출력.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ ls
A.txt    B.txt    FILE

$ cat *.txt
This is A.
This is B.&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. cat 명령 사용 예제 정리.&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cat FILE                          # 파일 내용 출력.

$ cat &amp;gt; FILE                        # 파일 생성.

$ cat -n FILE                       # 라인마다 번호 출력.

$ cat -E FILE                       # 라인 끝에 번호 출력.

$ cat -T FILE                       # 탭(TAB)을 ^I로 출력.

$ cat -s FILE                       # 반복된 공백 라인 무시.

$ cat FILE &amp;gt; OUT                    # 파일 복사, 합치기, 추가.

$ cat FILE1 - FILE2 &amp;gt; OUT           # 파일 사이에 내용 추가.

$ cat FILE | more                   # 파일 내용을 페이지 단위로 출력.

$ cat FILE | grep &amp;quot;STR&amp;quot;             # 파일 내용 필터링.

$ cat *                             # 모든 파일 내용 출력.

$ cat *.txt                         # 특정 확장자를 가진 파일 내용 출력.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. 참고.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Man7 Linux Manual Page - cat&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;http://man7.org/linux/man-pages/man1/cat.1.html&quot; title=&quot;[http://man7.org/linux/man-pages/man1/cat.1.html] 페이지로 이동합니다.&quot;&gt;Man7. man. cat&lt;/a&gt;] 내용을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.END.&lt;/p&gt;
&lt;/div&gt;</description>
      <category>LINUX 시스템/명령어 사용법</category>
      <category>Cat</category>
      <category>cat 명령</category>
      <category>cat 사용법</category>
      <category>cat 예제</category>
      <category>Linux cat</category>
      <category>리눅스 cat</category>
      <category>리눅스 파일 보기</category>
      <category>리눅스 파일 합치기</category>
      <category>파일 내용 출력</category>
      <category>파일 복사</category>
      <author>뽀따</author>
      <guid isPermaLink="true">https://recipes4dev.tistory.com/177</guid>
      <comments>https://recipes4dev.tistory.com/177#entry177comment</comments>
      <pubDate>Mon, 29 Nov 2021 15:57:59 +0900</pubDate>
    </item>
    <item>
      <title>chmod 명령에서 X (대문자 X)가 가지는 의미.</title>
      <link>https://recipes4dev.tistory.com/176</link>
      <description>&lt;br /&gt;
&lt;div class=&quot;ppotta-body&quot;&gt;

&lt;h3&gt;1. 리눅스 파일 사용 권한&lt;/h3&gt;
&lt;p&gt;지난 글, [&lt;a href=&quot;https://recipes4dev.tistory.com/175&quot; title=&quot;[https://recipes4dev.tistory.com/175] 페이지로 이동합니다.&quot;&gt;리눅스 chmod 명령어 사용법. (Linux chmod command) - 리눅스 파일 권한 변경.&lt;/a&gt;]에서, 리눅스 chmod 명령의 기본 사용법에 대해 설명하였습니다. 파일 및 디렉토리의 권한에 대해 설명하고, chmod에 전달되는 MODE 파라미터를 적용하는 방법 및 예제를 소개했는데요.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이번 글에서는 [&lt;a href=&quot;https://recipes4dev.tistory.com/175&quot; title=&quot;[https://recipes4dev.tistory.com/175] 페이지로 이동합니다.&quot;&gt;리눅스 chmod 명령어 사용법. (Linux chmod command) - 리눅스 파일 권한 변경.&lt;/a&gt;]에서 다 소개하지 못한 MODE 파라미터 중, X (대문자 X)에 대한 내용을 살펴보도록 하겠습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;X : &amp;quot;디렉토리&amp;quot; 또는 &amp;quot;실행(x) 권한이 있는 파일&amp;quot;에 실행(x) 권한 적용.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;

&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;linux_cmd_chmod_X_captial_X.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;329&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;chmod X (대문자 X)&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dESJjB/btq1EoAjEGv/E7rSa9kJt3pVbhP4cs0Pj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dESJjB/btq1EoAjEGv/E7rSa9kJt3pVbhP4cs0Pj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dESJjB/btq1EoAjEGv/E7rSa9kJt3pVbhP4cs0Pj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdESJjB%2Fbtq1EoAjEGv%2FE7rSa9kJt3pVbhP4cs0Pj1%2Fimg.png&quot; data-filename=&quot;linux_cmd_chmod_X_captial_X.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;329&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;chmod X (대문자 X)&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;2. X (대문자 X) : &amp;quot;디렉토리&amp;quot; 또는 &amp;quot;실행(x) 권한이 있는 파일&amp;quot;에 실행(x) 권한 적용.&lt;/h3&gt;
&lt;p&gt;chmod 명령의 MODE 파라미터에 사용할 수 있는 X(대문자 X)는 &amp;quot;디렉토리 및 실행(x) 권한이 있는 파일에 실행(x) 권한을 적용&amp;quot;하고자 할 때 사용합니다. 음... 적어놓고도 그 의미가 이상하게 보이네요. 실행(x) 권한이 있는 파일에 실행(x) 권한을 적용한다니... 아무런 의미가 없는 작업인 것 같은데... 뭔가 이상합니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그럼, 살짝 다르게 표현해볼게요.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;X(대문자 X)는 권한 지정 대상이 &amp;quot;실행(x) 권한을 가져도 괜찮은 경우에만 실행 권한을 지정&amp;quot;하고자 할 때 사용합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;br /&gt;

&lt;p&gt;조금은 더 그 의미가 와닿나요? 조금 더 설명해볼게요.&lt;/p&gt;
&lt;h4&gt;2.1 리눅스에서의 실행 가능 파일.&lt;/h4&gt;
&lt;p&gt;리눅스에서, 파일이 실행 가능한지 여부는 확장자 또는 파일 형식에 의해 결정되지 않습니다. 파일이 실행(x) 권한을 가지고 있는지에 따라 결정되죠. 이러한 특징은, 시스템 관리와 사용 측면에서 많은 이점을 가져다주지만, 사용자의 사소한 실수 하나에 큰 위험이 발생할 수 있는 단점 또한 가지고 있습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예를 들어, 아래와 같은 내용을 가진 &amp;quot;test&amp;quot;라는 텍스트 파일이 있을 때,&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &amp;#39;TEST&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;

&lt;p&gt;파일 &amp;quot;test&amp;quot;가 실행(x) 권한을 가지면 쉘에서 &amp;quot;test&amp;quot;를 실행하고 그 결과(echo 명령 실행)를 확인할 수 있습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ ls -l
-rwxr-xr-x 1 ppotta ppotta 11 Mar 31 23:09 test
$ cat test
echo &amp;#39;TEST&amp;#39;
$ ./test
TEST&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;

&lt;p&gt;즉, 텍스트 파일에 실행할 명령을 나열해 두고 실행(x) 권한을 준 다음 파일을 실행하면, 파일에 나열된 명령(예제의 echo 명령)들을 한번에 실행할 수 있는 것이죠. 매우 간편해 보이네요. 한번에 실행할 명령들을 쭉 나열해두고, 실행(x) 권한을 준 다음 실행하면 정말 편하게 사용할 수 있을 것 같습니다. (물론, 리눅스에는 그런 용도를 위한 쉘스크립트(shell script)라는게 있지요.)&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 만약 어떤 파일에 실행 목적이 아닌 기록 목적으로 &amp;quot;rm -rf *&amp;quot;라는 문장을 적어두었는데, 그 파일이 실행 권한을 가지게 되고 실행될 수 있다면 어떻게 될까요? 으.. 생각만 해도 끔찍하네요.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;물론 이런 파일에 실행(x) 권한을 주지 않으면 전혀 문제될 게 없습니다. 일부러 실행(x) 권한을 줄 이유도 없고요. 하지만 시스템을 사용하다보면 의도치 않게 파일의 속성을 변경해버리는 경우가 가끔 생깁니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;음, 하나의 경우를 가정해볼까요? 어느 날 우연히, 어떤 디렉토리 하위의 몇 개의 디렉토리들에 실행(x) 옵션이 빠져 있는 걸 발견했습니다. 파일을 일일이 찾아서 실행(x) 옵션을 추가하려니 번거롭게 느껴지네요. 그래서, 간단하게 &amp;quot;+x&amp;quot;를 적용하여 실행 권한을 추가하기로 결정합니다. 물론 하위 디렉토리를 모두 바꿔야 하니 &amp;quot;-R&amp;quot; 옵션을 적용하겠죠. (chmod -R +x *)&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ ls -l
drw-r--r-- 2 ppotta ppotta 4096 Mar 31 23:59 DIR
-rw-r--r-- 1 ppotta ppotta   12 Mar 31 23:37 test
$ chmod -R +x *
$ ls -l
drwxr-xr-x 2 ppotta ppotta 4096 Mar 31 23:59 DIR
-rwxr-xr-x 1 ppotta ppotta   12 Mar 31 23:37 test&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;

&lt;p&gt;실행 결과를 확인해보면 디렉토리(DIR)에 실행(x) 권한이 정상적으로 적용된 것을 확인할 수 있는데요. 하지만 디렉토리가 아닌, &amp;quot;test&amp;quot; 파일(&amp;quot;rm -rf *&amp;quot;가 기록된)에도 실행(x) 권한이 적용되어 버렸네요. 아주 위험한 파일이 실행(x) 권한을 가지게 되어 버렸습니다.&lt;/p&gt;
&lt;h4&gt;2.2 안전하게 실행(x) 권한 지정.&lt;/h4&gt;
&lt;p&gt;자, 이제 X (대문자 X)의 설명으로 다시 돌아가 볼까요? 이제 그 의미가 이해되실거라 생각되네요.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;chmod에서 X(대문자 X)는 &amp;quot;대상이 실행(x) 권한을 가져도 괜찮은 경우에만 실행 권한을 지정&amp;quot;할 때 사용하며, 이 때 실행(x) 권한을 가져도 괜찮은 대상은 &amp;quot;디렉토리&amp;quot; 또는 &amp;quot;이미 실행(x) 권한을 가진 파일&amp;quot;을 말합니다.&lt;/strong&gt; 즉, 기존에 실행(x) 권한이 없던 파일에는 실행(x) 권한을 주고 싶지 않을 때, x (소문자 x) 대신 X (대문자 X)를 사용하는 것이죠.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ ls -l
drw-r--r-- 2 ppotta ppotta 4096 Mar 31 23:59 DIR
-rw-r--r-- 1 ppotta ppotta   12 Mar 31 23:37 test
$ chmod -R a+X *
$ ls -l
drwxr-xr-x 2 ppotta ppotta 4096 Mar 31 23:59 DIR
-rw-r--r-- 1 ppotta ppotta   12 Mar 31 23:37 test&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2.3 -X&lt;/h4&gt;
&lt;p&gt;X(대문자 X)와 -(제거)를 같이 사용하면, x(소문자 x)를 사용하는 것과 동일한 결과가 나옵니다. 참고로 &amp;quot;-X&amp;quot;는 &amp;quot;a-X&amp;quot;와 동일한 표현입니다. &amp;quot;chmod -R -X *&amp;quot;에서 &amp;quot;-X&amp;quot;를 보고 &amp;quot;-R&amp;quot;처럼 chmod 명령에 사용할 수 있는 OPTION 중 하나라는 오해를 하지는 않길 바랍니다. &amp;quot;chmod -R -X *&amp;quot;는 &amp;quot;chmod -R a-X *&amp;quot;와 같은 의미입니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ ls -l
drwxr-xr-x 2 ppotta ppotta 4096 Mar 31 23:59 DIR
-rwxr-xr-x 1 ppotta ppotta   12 Mar 31 23:37 test
$ chmod -R -X *
$ ls -l
drw-r--r-- 2 ppotta ppotta 4096 Mar 31 23:59 DIR
-rw-r--r-- 1 ppotta ppotta   12 Mar 31 23:37 test&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. chmod 명령 사용 예제.&lt;/h3&gt;
&lt;p&gt;아래 정리한 내용에서 X(대문자 X)를 사용하는 예제를 참고하시기 바랍니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ chmod u+X FILE                    # FILE이 실행 권한을 가진 경우에만 파일 소유 사용자에게 실행 권한 추가.

$ chmod -R a-x,a+X *                # 현재 디렉토리 아래 모든 파일의 실행 권한 제거, 디렉토리 실행 권한 추가.

$ chmod -R a-x+X *                  # 위(chmod -R a-x,a+X *)와 동일.&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 참고.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;개발자를 위한 레시피 - chmod 명령어 사용법.&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/175&quot; title=&quot;[https://recipes4dev.tistory.com/175] 페이지로 이동합니다.&quot;&gt;리눅스 chmod 명령어 사용법. (Linux chmod command) - 리눅스 파일 권한 변경.&lt;/a&gt;] 내용을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Man7 Linux Manual Page - chmod&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;http://man7.org/linux/man-pages/man1/chmod.1.html&quot; title=&quot;[http://man7.org/linux/man-pages/man1/chmod.1.html] 페이지로 이동합니다.&quot;&gt;Man7. man. find&lt;/a&gt;] 내용을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.END.&lt;/p&gt;
&lt;/div&gt;</description>
      <category>LINUX 시스템/명령어 사용법</category>
      <category>capital X</category>
      <category>chmod</category>
      <category>chmod X</category>
      <category>Linux chmod</category>
      <category>X</category>
      <category>대문자 X</category>
      <category>리눅스 chmod</category>
      <author>뽀따</author>
      <guid isPermaLink="true">https://recipes4dev.tistory.com/176</guid>
      <comments>https://recipes4dev.tistory.com/176#entry176comment</comments>
      <pubDate>Fri, 2 Apr 2021 16:04:24 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 chmod 명령어 사용법. (Linux chmod command) - 리눅스 파일 권한 변경.</title>
      <link>https://recipes4dev.tistory.com/175</link>
      <description>&lt;br /&gt;
&lt;div class=&quot;ppotta-body&quot;&gt;

&lt;h3&gt;1. 리눅스 파일 사용 권한&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;linux_cmd_chmod_chmod.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;126&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;리눅스 chmod 명령&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KjOO0/btq1s4Uuctk/bCdquFbSFbNoPi93ftaXU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KjOO0/btq1s4Uuctk/bCdquFbSFbNoPi93ftaXU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KjOO0/btq1s4Uuctk/bCdquFbSFbNoPi93ftaXU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKjOO0%2Fbtq1s4Uuctk%2FbCdquFbSFbNoPi93ftaXU1%2Fimg.png&quot; data-filename=&quot;linux_cmd_chmod_chmod.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;126&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;리눅스 chmod 명령&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;리눅스에서, 파일(File)을 사용해 할 수 있는 작업은 크게 세 가지로 나눌 수 있습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;파일에 저장된 데이터를 읽기. (r = read).&lt;/li&gt;
&lt;li&gt;파일에 데이터를 쓰기. (w = write).&lt;/li&gt;
&lt;li&gt;파일 실행. (x = execute)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그런데 만약 리눅스 시스템의 모든 파일이, 그 종류 또는 쓰임새와 관계없이 읽기, 쓰기, 실행 가능하게 만들어져 있다면 어떻게 될까요? 잘못된 명령어 사용으로 시스템 운영에 중요한 역할을 하는 파일의 내용이 변경되거나, 사용자의 사소한 실수 한번으로 리눅스 시스템의 모든 파일이 삭제되어 버릴 수도 있습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이런 문제가 생기는 경우를 방지하기 위해, 리눅스에서는 각 파일 및 디렉토리에 대해 &lt;strong&gt;&amp;quot;읽기(r)&amp;quot;, &amp;quot;쓰기(w)&amp;quot;, &amp;quot;실행(x)&amp;quot;&lt;/strong&gt; 권한(permission)을 파일 개별적으로 지정할 수 있도록 만들어 놓았습니다. 그리고 이 세 가지 권한을 &lt;strong&gt;&amp;quot;파일을 소유한 사용자(user)&amp;quot;, &amp;quot;특정 그룹(group)에 소속된 사용자&amp;quot;, &amp;quot;그 외 사용자(others)&amp;quot;&lt;/strong&gt;에 대해 각각 지정할 수 있게 만들었습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;linux_cmd_chmod_file_permission.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;249&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;chmod 파일 권한&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHm7H4/btq1qNZYJud/JyMX0Zn6iAHQ0k4E7vq6HK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHm7H4/btq1qNZYJud/JyMX0Zn6iAHQ0k4E7vq6HK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHm7H4/btq1qNZYJud/JyMX0Zn6iAHQ0k4E7vq6HK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHm7H4%2Fbtq1qNZYJud%2FJyMX0Zn6iAHQ0k4E7vq6HK%2Fimg.png&quot; data-filename=&quot;linux_cmd_chmod_file_permission.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;249&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;chmod 파일 권한&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;chmod&lt;/strong&gt; 명령은 바로 이러한 파일의 권한을 변경할 수 있게 만들어주는 명령입니다. &amp;quot;&lt;strong&gt;ch&lt;/strong&gt;ange&amp;quot;와 &amp;quot;&lt;strong&gt;mod&lt;/strong&gt;e&amp;quot;의 앞 글자들을 조합한 이름이죠. (chmod = ch + mod)&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;여기서 &amp;quot;모드(mode)&amp;quot;란, 앞서 소개한 세 가지 권한(읽기, 쓰기, 실행)과 각각의 권한을 지정할 대상(파일 소유자, 그룹, 그외 사용자)을 포함한 파일의 속성을 말합니다. 즉, chmod 명령에서 지정하는 읽기(r), 쓰기(w), 실행(x) 권한 및 소유자(user), 그룹(group), 그 외 사용자(others)에 대한 설정 값을 통틀어 &lt;strong&gt;&amp;quot;모드(mode)&amp;quot;&lt;/strong&gt;라고 지칭합니다. 그러므로 &lt;strong&gt;chmod 명령을 사용하여 파일의 모드(mode)를 변경한다는 것은 파일의 권한을 변경한다는 것과 동일한 의미&lt;/strong&gt;를 가집니다.&lt;/p&gt;
&lt;h3&gt;2. chmod 명령&lt;/h3&gt;
&lt;p&gt;앞서 설명했듯이 chmod 명령은 파일의 모드(mode)를 변경하는 명령입니다. chmod 다음에 &amp;quot;선택 옵션&amp;quot;과 &amp;quot;모드를 나타내는 문자열&amp;quot;, 그리고 &amp;quot;대상 파일(또는 디렉토리)&amp;quot;을 순서대로 입력하여 파일의 모드를 변경할 수 있습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;usage&quot;&gt;&lt;pre&gt;
    &lt;b&gt;chmod [OPTION] [MODE] [FILE]&lt;/b&gt;
      OPTION
        -v        : 모든 파일에 대해 모드가 적용되는 진단(diagnostic) 메시지 출력.
        -f        : 에러 메시지 출력하지 않음.
        -c        : 기존 파일 모드가 변경되는 경우만 진단(diagnostic) 메시지 출력.
        -R        : 지정한 모드를 파일과 디렉토리에 대해 재귀적으로(recursively) 적용.
      MODE
        파일에 적용할 모드(mode) 문자열 조합.
          u,g,o,a : 소유자(u), 그룹(g), 그 외 사용자(o), 모든 사용자(a) 지정.
          +,-,=   : 현재 모드에 권한 추가(+), 현재 모드에서 권한 제거(-), 현재 모드로 권한 지정(=)
          r,w,x   : 읽기 권한(r), 쓰기 권한(w), 실행 권한(x)
          X       : &quot;디렉토리&quot; 또는 &quot;실행 권한(x)이 있는 파일&quot;에 실행 권한(x) 적용.
          s       : 실행 시 사용자 또는 그룹 ID 지정(s). &quot;setuid&quot;, &quot;setgid&quot;.
          t       : 공유모드에서의 제한된 삭제 플래그를 나타내는 sticky(t) bit.
          0~7     : 8진수(octet) 형식 모드 설정 값.
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;

&lt;p&gt;위에서 볼 수 있듯이, chmod에서 제공되는 OPTION의 종류는 그리 많지 않습니다. 지정 디렉토리 하위의 모든 디렉토리와 파일의 모드를 변경하는 &amp;quot;-R&amp;quot; 외에는 거의 사용하지 않기 때문에 크게 신경쓰지 않아도 되는데요. 하지만 MODE로 전달되는 파라미터에는 조금(?) 복잡한 문자열 조합이 적용됩니다. 그리고 MODE에 전달되는 이 문자열 조합이, chmod 명령의 동작을 이해하는 핵심이 되는 내용이죠.&lt;/p&gt;
&lt;h4&gt;2.1 chmod 명령의 MODE 파라미터.&lt;/h4&gt;
&lt;p&gt;언뜻 보기에, MODE 파라미터에 적용되는 문자열이 꽤 복잡해 보일 수 있지만, 사실, 알고보면 매우 직관적입니다. MODE 파라미터로 조합되는 문자 조합을 생각하기 전에, 파일에 지정하고자 하는 권한을 먼저 서술형 문장으로 표현해보면 chmod 명령 작성을 좀 더 쉽게 할 수 있습니다. 한번 문장으로 표현해볼까요?&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;파일을 소유한 &lt;strong&gt;사용자&lt;/strong&gt;에 대해 &lt;strong&gt;읽고 쓸 수&lt;/strong&gt;있는 권한 &lt;strong&gt;지정&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;파일이 속한 &lt;strong&gt;그룹&lt;/strong&gt;이 &lt;strong&gt;실행&lt;/strong&gt;할 수 있는 권한 &lt;strong&gt;추가&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;시스템의 &lt;strong&gt;모든 사용자&lt;/strong&gt;가 &lt;strong&gt;읽을 수&lt;/strong&gt;만 있는 권한 &lt;strong&gt;지정&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;파일을 소유한 &lt;strong&gt;그룹&lt;/strong&gt;과 &lt;strong&gt;그 외 사용자&lt;/strong&gt;의 모든 권한 &lt;strong&gt;제거&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;자, 이제 할 일은, 저 문장에 들어 있는 단어들을 &amp;quot;MODE 파라미터의 문자&amp;quot;들로 바꾸기만 하면 됩니다. 앞서 chmod 명령의 MODE 파라미터에 적어놨지만, 아래 그림을 참고하면 조금 더 직관적으로 이해하실 수 있을거라 생각합니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;linux_cmd_chmod_mode_parameters.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;228&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;chmod 명령 MODE 파라미터 조합&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cg4C9X/btq1nIypDVL/MwUKeJprOtk6qbbbEPkJjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cg4C9X/btq1nIypDVL/MwUKeJprOtk6qbbbEPkJjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cg4C9X/btq1nIypDVL/MwUKeJprOtk6qbbbEPkJjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcg4C9X%2Fbtq1nIypDVL%2FMwUKeJprOtk6qbbbEPkJjK%2Fimg.png&quot; data-filename=&quot;linux_cmd_chmod_mode_parameters.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;228&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;chmod 명령 MODE 파라미터 조합&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;위의 첫 번째 문장을 chmod 명령으로 바꾸면, MODE 파라미터는 아래 그림과 같이 조합될 수 있습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;linux_cmd_chmod_mode_parameter_example.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;466&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;chmod 명령 MODE 파라미터 조합 예제&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKxXah/btq1jkZjWmO/2sWah94UmO18fUdkXzEnM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKxXah/btq1jkZjWmO/2sWah94UmO18fUdkXzEnM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKxXah/btq1jkZjWmO/2sWah94UmO18fUdkXzEnM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKxXah%2Fbtq1jkZjWmO%2F2sWah94UmO18fUdkXzEnM1%2Fimg.png&quot; data-filename=&quot;linux_cmd_chmod_mode_parameter_example.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;466&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;chmod 명령 MODE 파라미터 조합 예제&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이 규칙대로 변환하면 나머지 문장들에 대한 MODE 파라미터 조합도 그리 어렵지 않게 하실 수 있을거라 생각합니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;파일이 속한 &lt;strong&gt;그룹&lt;/strong&gt;이 &lt;strong&gt;실행&lt;/strong&gt;할 수 있는 권한 &lt;strong&gt;추가&lt;/strong&gt;.&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ chmod  g+x  FILE&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;시스템의 &lt;strong&gt;모든 사용자&lt;/strong&gt;가 &lt;strong&gt;읽을 수&lt;/strong&gt;만 있는 권한 &lt;strong&gt;지정&lt;/strong&gt;.&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ chmod  a=r  FILE&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;파일을 소유한 &lt;strong&gt;그룹&lt;/strong&gt;과 &lt;strong&gt;그 외 사용자&lt;/strong&gt;의 모든 권한 &lt;strong&gt;제거&lt;/strong&gt;.&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ chmod  go-rwx  FILE&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그런데 권한 &amp;quot;지정(=)&amp;quot;은 전달된 권한으로 온전히 설정되지만, &amp;quot;추가(+)&amp;quot;와 &amp;quot;제거(-)&amp;quot;는 파일이 기존에 가지고 있던 권한을 기준으로, 새로운 권한이 추가되거나 지정된 권한이 제거됩니다. 그렇다면 파일이 기존에 가지고 있던 권한을 확인할 수 있어야 겠죠? 간단하게 &amp;quot;ls -l&amp;quot; 명령을 사용하면 파일의 현재 권한을 확인할 수 있습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;2.2 파일 또는 디렉토리 권한 확인.&lt;/h4&gt;
&lt;p&gt;리눅스에서 파일 또는 디렉토리에 지정된 권한을 확인하려면 &amp;quot;ls -l&amp;quot; 명령을 사용하면 됩니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ ls -l
-rw-r--r-- 1 ppotta manager 17 Mar 24 03:17 FILE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;quot;ls -l&amp;quot; 명령을 실행하면, 현재 디렉토리 내 파일 리스트(ls=list)가 하나의 파일 단위로 한줄로 길게(-l=long) 표시되는데요. 공백 기준으로 가장 첫 번째 항목(-rw-r--r--)이 파일 소유자 별 권한, 세 번째(ppotta)와 네 번째(manager) 항목이 각각 파일 소유자와 그룹을 나타냅니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;linux_cmd_chmod_ls_cmd_result.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;343&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;파일 또는 디렉토리 권한 확인 (ls -l&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bONSew/btq1m7SGmys/haKesYdhVPmA1KBQ4QpVu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bONSew/btq1m7SGmys/haKesYdhVPmA1KBQ4QpVu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bONSew/btq1m7SGmys/haKesYdhVPmA1KBQ4QpVu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbONSew%2Fbtq1m7SGmys%2FhaKesYdhVPmA1KBQ4QpVu1%2Fimg.png&quot; data-filename=&quot;linux_cmd_chmod_ls_cmd_result.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;343&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;파일 또는 디렉토리 권한 확인 (ls -l&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;앞서 실행한 &amp;quot;ls -l&amp;quot; 명령의 실행 결과를 해석하면, 그 결과는 아래와 같습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-rw-r--r-- 1 ppotta manager 17 Mar 24 03:17 FILE&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;

&lt;ul&gt;
&lt;li&gt;파일 소유 사용자 : ppotta&lt;/li&gt;
&lt;li&gt;파일 소유 그룹 : manager&lt;/li&gt;
&lt;li&gt;파일 소유 사용자(ppotta)의 권한 : &amp;quot;rw-&amp;quot; = 읽기(r), 쓰기(w) 가능.&lt;/li&gt;
&lt;li&gt;파일 소유 그룹(manager)의 권한 : &amp;quot;r--&amp;quot; = 읽기(r) 가능.&lt;/li&gt;
&lt;li&gt;그 외 사용자(others)의 권한 : &amp;quot;r--&amp;quot; = 읽기(r) 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이제 &amp;quot;ls -l&amp;quot; 명령을 사용하여 파일에 설정된 권한을 확인하는 법을 알았으니, 추가(+)와 삭제(-)를 통해 파일에 권한을 추가하거나 제거하는 방법을 쉽게 쓸 수 있겠죠?&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 여기서 한 가지 의문이 생기네요. &amp;quot;파일&amp;quot;에 대한 읽기(r), 쓰기(w), 실행(x)은 그 의미가 명확한데, &amp;quot;디렉토리&amp;quot;에 대한 각각의 권한은 뭘 의미하는 걸까요? 음... 읽기(r)와 쓰기(w)는 어렴풋이 그 의미가 와닿는 것 같은데... 그런데 디렉토리는 &amp;quot;실행&amp;quot;이라는 개념을 적용할 수가 없으니, 애초부터 &amp;quot;실행(x)&amp;quot; 권한은 디렉토리에는 소용없는 걸까요?&lt;/p&gt;
&lt;h4&gt;2.3 디렉토리에 대한 권한.&lt;/h4&gt;
&lt;p&gt;디렉토리는 파일을 분류하기 위해 사용합니다. 그리고 디렉토리 내부에는 다른 파일 또는 디렉토리의 리스트가 존재합니다. 본문의 시작 부분에, 파일로 할 수 있는 세 가지 작업(데이터 읽기, 데이터 쓰기, 파일 실행)에 대해 소개했는데요. 마찬가지로, 디렉토리로 할 수 있는 작업도 크게 세 가지로 나뉩니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;디렉토리에 있는 파일 및 디렉토리 리스트 읽기. (r = read)&lt;/li&gt;
&lt;li&gt;디렉토리에 파일 추가, 이름 변경, 삭제. (w = write)&lt;/li&gt;
&lt;li&gt;디렉토리에 접근. cd 명령으로 working directory 이동. (x = execute)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;먼저, 읽기(r) 권한은 디렉토리에 있는 파일 리스트를 확인할 수 있는 권한을 의미합니다. 즉, &amp;quot;ls&amp;quot; 명령을 통해 디렉토리의 리스트를 확인할 때 &amp;quot;읽기(r)&amp;quot; 권한이 있어야 합니다. 만약 디렉토리에 읽기(r) 권한이 없다면, &amp;quot;ls&amp;quot; 명령을 수행할 때 &amp;quot;permission denied&amp;quot; 에러가 발생합니다. (참고로, 읽기(r) 권한만 있는 경우 &amp;quot;파일 이름&amp;quot;만 확인 가능하고, 파일의 모든 정보를 확인(&amp;quot;ls -l&amp;quot;)하기 위해서는 실행(x) 권한이 있어야 합니다.)&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ ls -l
total 4
d--------- 2 ppotta ppotta 4096 Mar 26 00:50 DIR
$ ls DIR
ls: cannot open directory &amp;#39;DIR&amp;#39;: Permission denied&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;

&lt;p&gt;다음, 쓰기(w) 권한은 디렉토리에 파일을 생성하거나, 복사, 이름 변경, 삭제 등의 작업을 하고자 할 때 필요한 권한입니다. 말 그대로 &amp;quot;디렉토리의 내용을 변경&amp;quot;하기 때문에 &amp;quot;쓰기(w)&amp;quot; 권한이 필요한 것인데요. &lt;strong&gt;한 가지 주의할 점은, 쓰기(r) 권한만 있다고 해서 생성, 복사, 변경, 삭제 등의 작업이 수행되지는 않고, 실행(x) 권한도 같이 지정되어 있어야 원하는 작업이 정상적으로 수행됩니다.&lt;/strong&gt;&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;마지막으로 실행(x) 권한은 디렉토리에 접근하고자 할 때 필요한 권한입니다. cd 명령을 사용해 디렉토리에 접근할 때 필요한 권한인데요. 하지만 단순히 cd 명령으로 working 디렉토리를 변경하는 경우에만 국한 된 것이 아니라, &lt;strong&gt;&amp;quot;접근&amp;quot;&lt;/strong&gt; 권한이라는 이름이 내포하듯이, 디렉토리에 어떤 작업(읽기, 쓰기)을 할 때 디렉토리에 접근하기 위해 이 실행(x) 권한이 필요합니다. 즉, 실행(x) 권한 없이는 읽기(r)와 쓰기(w) 권한을 완전히 사용할 수 없습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;결론적으로, 아래와 같이 정리할 수 있겠네요.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;디렉토리의 내용을 읽기 위해서는 읽기(r) 권한 필요.&lt;/li&gt;
&lt;li&gt;디렉토리의 내용을 변경하기 위해서는 쓰기(w) 권한 필요.&lt;/li&gt;
&lt;li&gt;디렉토리의 접근을 위해 실행(x) 권한 필요하며 가장 기본적인 접근 권한.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2.4 8진수(octal) 형식으로 파일 모드(mode) 지정 방법.&lt;/h4&gt;
&lt;p&gt;지금까지 다소 장황하게 MODE 파라미터 문자열을 조합하여 파일 모드(mode)를 변경하는 방법에 대해 설명했는데요. 앞서 설명한 내용보다 조금 더 간단하게 파일 모드(mode)를 지정하는 방법이 있습니다. 바로, MODE 파라미터에 파일 모드(mode)를 표현하는 8진수 값을 사용하는 것입니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;앞서 &amp;quot;ls -l&amp;quot; 명령을 통해 현재 파일의 권한을 확인하는 방법에 대해 알아보았죠? 출력된 결과의 가장 첫 번째 항목을 통해 &amp;quot;사용자(u)&amp;quot;, &amp;quot;그룹(g)&amp;quot;, &amp;quot;그 외 사용자(o)&amp;quot;에 대한 &amp;quot;읽기(r)&amp;quot;, &amp;quot;쓰기(w)&amp;quot;, &amp;quot;실행(x)&amp;quot; 권한을 확인할 수 있는데요.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;linux_cmd_chmod_ls_permission.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;176&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;ls -l 명령 결과&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DlzIH/btq1jlRsxDL/l9FgQ7D8ujaYDukFKJXfuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DlzIH/btq1jlRsxDL/l9FgQ7D8ujaYDukFKJXfuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DlzIH/btq1jlRsxDL/l9FgQ7D8ujaYDukFKJXfuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDlzIH%2Fbtq1jlRsxDL%2Fl9FgQ7D8ujaYDukFKJXfuK%2Fimg.png&quot; data-filename=&quot;linux_cmd_chmod_ls_permission.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;176&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;ls -l 명령 결과&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;quot;8진수&amp;quot; 값을 사용하는 방법은 각 권한(rwx)을 8진수 형태의 숫자 값으로 변환하여 한번에 지정하는 방법입니다. 즉, 그림의 &amp;quot;rwxrwxrwx&amp;quot; 중 &amp;quot;rwx&amp;quot;를 하나의 8진수 값으로 변환한 다음, 이 값을 연속 세 개(사용자, 그룹, 그 외 사용자)로 나열하여 전달하는 것입니다. 이 때, 권한 없음(-)은 0, 읽기(r)는 4, 쓰기(w)는 2, 그리고 실행(x)은 1에 해당하는 값을 가지며, 이 값들을 모든 더한 값이 하나의 8진수 값으로 변환됩니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;아래 그림을 보면 조금 더 쉽게 이해하실 수 있을거라 생각되네요.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;linux_cmd_chmod_octal_format.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;333&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;chmod 8진수 형식&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjt7Ic/btq1s3VyALa/4kuVzdG04cXjApQp1k62Q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjt7Ic/btq1s3VyALa/4kuVzdG04cXjApQp1k62Q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjt7Ic/btq1s3VyALa/4kuVzdG04cXjApQp1k62Q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbjt7Ic%2Fbtq1s3VyALa%2F4kuVzdG04cXjApQp1k62Q0%2Fimg.png&quot; data-filename=&quot;linux_cmd_chmod_octal_format.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;333&quot; data-ke-mobilestyle=&quot;widthContent&quot; alt=&quot;chmod 8진수 형식&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;어렵지 않죠? 몇 가지 예제를 통해 8진수 형식으로 파일 모드(mode)를 지정하는 방법을 살펴보겠습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;모든 사용자가 읽고 쓰고 실행할 수 없도록 지정.&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ chmod  000  FILE
---------- 1 ppotta manager   23 Mar 26 04:13 FILE&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;모든 사용자가 읽고 쓰고 실행할 수 있는 권한 지정.&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ chmod  777  FILE
-rwxrwxrwx 1 ppotta manager   23 Mar 26 04:13 FILE&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;소유자는 모든 권한, 그룹 및 그 외 사용자는 읽기와 실행만 가능.&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ chmod  755  FILE
-rwxr-xr-x 1 ppotta manager   23 Mar 26 04:13 FILE&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;소유자 및 그룹은 읽기 가능, 그외 사용자는 권한 없음.&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ chmod  440  FILE
-r--r----- 1 ppotta manager   23 Mar 26 04:13 FILE&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;8진수 형식을 이용할 때는 MODE 파라미터로 전달되는 값이 파일의 권한에 그대로 적용되기 때문에 u, g, o, a 또는 =, +, - 등과 같이 사용할 수 없습니다.&lt;/p&gt;
&lt;h3&gt;3. chmod 명령 사용 예제.&lt;/h3&gt;
&lt;p&gt;그럼 이제, 다양한 예제를 통해 chmod 사용 방법을 알아보겠습니다.&lt;br&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ chmod u+x FILE                    # 파일 소유 사용자에게 실행권한 추가.

$ chmod u+w FILE                    # 파일 소유 사용자에게 쓰기 권한 추가.

$ chmod u=rwx FILE                  # 파일 소유 사용자에게 읽기, 쓰기, 실행 권한 지정.

$ chmod u-x FILE                    # 파일 소유 사용자의 실행 권한 제거.

$ chmod g+w FILE                    # 파일 소유 그룹에 쓰기 권한 추가.

$ chmod g-x FILE                    # 파일 소유 그룹의 실행 권한 제거.

$ chmod o=r FILE                    # 파일 소유 사용자 및 그룹을 제외한 사용자는 읽기만 가능.

$ chmod a-x *                       # 현재 디렉토리의 모든 파일에서 모든 사용자의 읽기 권한 제거.

$ chmod a-w FILE                    # 모든 사용자에 대해 쓰기 권한 제거.

$ chmod u=rwx,g=r FILE              # 파일 소유 사용자는 모든 권한, 그룹은 읽기만 가능.

$ chmod ug=rw FILE                  # 파일 소유 사용자와 그룹이 읽기, 쓰기 가능.

$ chmod g=rw,o=r FILE               # 파일 소유 그룹은 읽기, 쓰기 가능, 그 외 사용자는 읽기만 가능.

$ chmod ug=rw,o=r FILE              # 파일 소유 사용자 및 그룹은 일기, 쓰기 가능, 그외 사용자는 읽기만 가능.

$ chmod 000 FILE                    # 모든 사용자의 모든 권한 제거. = ---------

$ chmod 664 FILE                    # 사용자(읽기+쓰기), 그룹(읽기+쓰기), 그외 사용자(읽기) = rw-rw-r--

$ chmod 755 FILE                    # 사용자(읽기+쓰기+실행), 그룹(읽기+실행), 그외 사용자(읽기+실행) = rwxr-xr-x

$ chmod 777 FILE                    # 모든 사용자에 모든 권한 추가.

$ chmod -R g+x DIR                  # DIR 디렉토리 하위 모든 파일 및 디렉토리에 그룹 실행(x) 권한 추가.

$ chmod -R o-wx *                   # 현재 디렉토리의 모든 파일에서 그외 사용자의 쓰기, 실행 권한 제거

$ chmod -R a-x,a+X *                # 현재 디렉토리 기준 모든 파일 읽기 권한 제거, 디렉토리 실행 권한 추가.

$ chmod -R a-x+X *                  # 위(chmod -R a-x,a+X *)와 동일.

$ chmod u=g FILE                    # FILE의 그룹 권한 값을 사용자 권한으로 적용.
    $ ls -l
    -rwxr--r-- 1 ppotta manager   23 Mar 26 04:13 FILE
    $ chmod u=g FILE
    -r--r--r-- 1 ppotta manager   23 Mar 26 04:13 FILE

$ chmod u+g FILE                    # FILE의 사용자 권한에 그룹 권한 값을 추가.
    $ ls -l
    -r-x-w--w- 1 ppotta manager   23 Mar 26 04:13 FILE
    $ chmod u+g FILE
    -rwx-w--w- 1 ppotta manager   23 Mar 26 04:13 FILE&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 추가.&lt;/h3&gt;
&lt;h4&gt;4.1 X (대문자 X) 가 가진 의미.&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/176&quot; title=&quot;[https://recipes4dev.tistory.com/176] 페이지로 이동합니다.&quot;&gt;chmod 명령에서 X (대문자 X)가 가지는 의미.&lt;/a&gt;] 내용을 참고하세요.&lt;/p&gt;
&lt;h3&gt;5. 참고.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;개발자를 위한 레시피 - chmod 명령어 사용법.&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/176&quot; title=&quot;[https://recipes4dev.tistory.com/176] 페이지로 이동합니다.&quot;&gt;chmod 명령에서 X (대문자 X)가 가지는 의미.&lt;/a&gt;] 내용을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Man7 Linux Manual Page - chmod&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;http://man7.org/linux/man-pages/man1/chmod.1.html&quot; title=&quot;[http://man7.org/linux/man-pages/man1/chmod.1.html] 페이지로 이동합니다.&quot;&gt;Man7. man. chmod&lt;/a&gt;] 내용을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.END.&lt;/p&gt;
&lt;/div&gt;</description>
      <category>LINUX 시스템/명령어 사용법</category>
      <category>chmod</category>
      <category>chmod 명령</category>
      <category>chmod 사용법</category>
      <category>chmod 예제</category>
      <category>Linux chmod</category>
      <category>permission</category>
      <category>리눅스 chmod</category>
      <category>리눅스 파일 모드</category>
      <category>파일 권한</category>
      <author>뽀따</author>
      <guid isPermaLink="true">https://recipes4dev.tistory.com/175</guid>
      <comments>https://recipes4dev.tistory.com/175#entry175comment</comments>
      <pubDate>Tue, 30 Mar 2021 19:20:11 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드 AsyncTask. (Android AsyncTask)</title>
      <link>https://recipes4dev.tistory.com/174</link>
      <description>&lt;link rel=&quot;stylesheet&quot; href=&quot;https://tistory1.daumcdn.net/tistory/1573970/skin/images/style_gfm.css&quot; type=&quot;text/css&quot;&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;article class=&quot;madwin-body&quot;&gt;
&lt;h3 id=&quot;1-비동기-작업을-위한-asynctask&quot;&gt;1. 비동기 작업을 위한 AsyncTask.&lt;/h3&gt;
&lt;p&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/category/ANDROID%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/THREAD&quot; title=&quot;[https://recipes4dev.tistory.com/category/ANDROID%20프로그래밍/THREAD] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 프로그래밍. 스레드.&lt;/a&gt;]의 여러 글들을 통해, 안드로이드에서 스레드를 사용해야 하는 이유와 새로운 스레드를 실행하는 방법, 그리고 핸들러를 통한 스레드 간 통신 방법에 대해 알아보았습니다. 스레드에 대한 기초적인 내용부터, &lt;code&gt;Thread&lt;/code&gt;와 &lt;code&gt;Handler&lt;/code&gt;, &lt;code&gt;Message&lt;/code&gt;, &lt;code&gt;Runnable&lt;/code&gt;에 대한 기본 개념과 사용법 등을 설명했었는데요, 이제, 안드로이드 스레드에 대한 기초 지식을 넘어, 앱 개발에 조금 더 실용적으로 적용할 수 있는 내용을 다뤄볼까 합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;바로, &lt;strong&gt;비동기(Asynchronous)&lt;/strong&gt; 작업을 위해 사용하는 &lt;strong&gt;AsyncTask&lt;/strong&gt;에 대한 내용입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;2-스레드-사용의-몇-가지-유형&quot;&gt;2. 스레드 사용의 몇 가지 유형.&lt;/h3&gt;
&lt;p&gt;안드로이드에서 스레드를 사용하는 이유. 기억하시나요?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/150&quot; title=&quot;[https://recipes4dev.tistory.com/150] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드 예제. 스레드로 고민해보기. (Android Thread UseCase)&lt;/a&gt;]에서 예제를 통해 알아보았듯이, 안드로이드의 메인 스레드는 앱 실행에 있어 가장 중요한 역할, 즉, 화면 그리기 및 이벤트 처리 등의 역할을 수행하기 때문에, 절대로 실행이 멈추거나 일정 시간 이상 지연되어서는 안됩니다. 그래서 메인 스레드의 실행에 영향을 줄 수 있는 코드는 별도의 스레드에서 실행해야 한다고 설명했었죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;더불어 [&lt;a href=&quot;https://recipes4dev.tistory.com/category/ANDROID%20프로그래밍/THREAD&quot; title=&quot;[https://recipes4dev.tistory.com/category/ANDROID%20프로그래밍/THREAD] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;ANDROID 프로그래밍. THREAD. &lt;/a&gt;] 카테고리에, 스레드에 대한 기본 개념과 사용법, 스레드 통신에 대한 내용을 다루었습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 실제 프로그램 개발에서 스레드를 만들고 실행할 때, 스레드의 생성 시점과 종료 시점, 그리고 메인 스레드와의 메시지 통신 여부를 따져보면, 스레드 동작 형태를 아래 그림과 같이 몇 가지 유형으로 나눌 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9991A1485F26D54F16&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9991A1485F26D54F16&quot; width=&quot;700&quot; height=&quot;553&quot; alt=&quot;스레드 동작 형태 유형&quot; filename=&quot;asynctask_thread_operation_types.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;위의 그림에서 보여지는 유형들이 객관적 이론에 따라 정립된 개념을 표현한 것은 아닙니다. 개인의 경험에 기반하여 주관적 기준으로 구분된 형태를, 보기 쉬운 그림 형태로 표현한 것일 뿐입니다. 그러므로 동작 유형의 종류와 개념에 너무 큰 의미를 부여할 필요는 없습니다. 그냥, &quot;스레드를 이러한 형태로 사용할 수 있다&quot;라는 정도로만 이해하시면 될 듯 하네요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;여기서 설명할 내용은, 그림에 표현된 스레드 사용 유형 중 가장 마지막에 표현된, 비동기(Asynchronous) 작업을 위한 스레드 사용에 대한 것입니다.&lt;/p&gt;
&lt;h3 id=&quot;3-비동기asynchronous-실행&quot;&gt;3. 비동기(Asynchronous) 실행.&lt;/h3&gt;
&lt;p&gt;다시 한번, 이 글에서 다루고자 하는 내용은 비동기(Asynchronous)로 실행될 필요가 있는 기능을 구현하는 방법에 대한 것입니다. 위의 그림에서 &quot;필요에 따라 만들어진 스레드가 메인스레드와 상호 작용 후 종료&quot;하는 형태로 동작하는 스레드 동작 유형에 해당하죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993A53345F26D54F0F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993A53345F26D54F0F&quot; width=&quot;700&quot; height=&quot;277&quot; alt=&quot;스레드 동작 형태 유형 - AsyncTask&quot; filename=&quot;asynctask_thread_operation_types_asynctask.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 &quot;비동기(Asynchronous) 실행&quot;이라는 것이 의미하는 것이 정확히 무엇일까요? 그리고 일반적인(?) 실행 흐름과 어떤 차이가 있으며, 스레드와는 어떤 관련이 있는 것일까요?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;비동기(Asynchronous) 실행을 정확히 이해하기 위해서는, 그 반대 개념인 &lt;strong&gt;동기(Synchronous) 실행&lt;/strong&gt;에 대한 기본 개념 이해가 선행되어야 합니다. 이를 통해, 비동기(Asynchronous) 실행이 왜 필요한지, 어떤 흐름으로 동작하는지 정확히 이해할 수 있습니다.&lt;/p&gt;
&lt;h4 id=&quot;31-동기synchronous-실행-vs-비동기-asynchronous-실행&quot;&gt;3.1 동기(Synchronous) 실행 vs 비동기 (Asynchronous) 실행.&lt;/h4&gt;
&lt;p&gt;프로그래밍 분야에서, &lt;strong&gt;동기(Synchronous) 실행&lt;/strong&gt;이 의미하는 것은, 프로그램 실행 중 하나의 기능 또는 함수를 실행했을 때, 그것을 실행한 측(Caller)에서 기능이나 함수의 모든 동작이 완료될 때까지 대기하는 방식을 의미합니다. 그리고 &lt;strong&gt;비동기(Asynchronous) 실행&lt;/strong&gt;은, 기능 또는 함수의 동작이 끝나길 기다리지 않고 바로 그 다음 코드를 실행하는 방식을 말하죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998AA03D5F26D54F0C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998AA03D5F26D54F0C&quot; width=&quot;700&quot; height=&quot;275&quot; alt=&quot;동기 vs 비동기. (Synchronous vs Asynchronous)&quot; filename=&quot;asynctask_synchronous_vs_asynchronous.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예를 들어, 앱 실행 시 파일로부터 데이터를 읽는 기능을 가진 메서드를 호출하는 경우를 가정해 보겠습니다. &quot;readFileData()&quot;라는 이름을 가진 이 메서드를 사용하는 코드는, 아래와 같이 간단한 형태로 작성될 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99FA76455F26D54F0D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99FA76455F26D54F0D&quot; width=&quot;700&quot; height=&quot;275&quot; alt=&quot;동기 실행 예제 1. (Synchronous 예제 1)&quot; filename=&quot;asynctask_synchronous_example_1.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;아주 직관적이고 익숙한, 한 눈에 알아볼 수 있는 흐름입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;메인 액티비티의 onCreate() 메서드에서 readFileData() 메서드를 호출하는데요. 이 때 onCreate() 메서드는 readFileData() 메서드를 호출하고 난 뒤 파일의 데이터가 모두 읽히기를 기다립니다. 그리고 readFileData() 메서드의 실행이 완료되면 그 다음 코드인 showFileData()를 실행합니다. 이러한 실행 흐름이 바로 &lt;strong&gt;동기(Synchronous) 실행&lt;/strong&gt; 입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자, 그런데 여기서, 한 가지 좋지 않은 상황을 가정해보겠습니다. 읽고자 하는 파일의 크기가 매우 큰 경우 말이죠. 만약 파일의 크기가 아주 커서 파일의 내용을 읽는데 몇 초, 몇 십초 이상의 시간이 소요된다면, 분명 심각한 문제가 발생할 것입니다. 왜냐하면 readFileData()에서 파일을 읽을 동안 readFileData()를 호출한 메인 스레드가 다른 이벤트들을 처리하지 못하게 될 것이고, 최악의 경우, ANR(Application Not Responding)이 발생하면서 시스템에 의해 앱의 실행이 중지되는 상황이 생길 수도 있습니다. 이는 [&lt;a href=&quot;https://recipes4dev.tistory.com/150&quot; title=&quot;[https://recipes4dev.tistory.com/150] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드 예제. 스레드로 고민해보기. (Android Thread UseCase)&lt;/a&gt;] 주제에서 여러 번 강조한, &quot;안드로이드 앱의 메인 스레드에서는 무한 루프나 실행 시간이 긴 작업, 또는 과도한 대기(sleep) 등의 작업이 실행되어서는 안된다&quot;는 원칙을 명백히 위반하는 것이죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998F0F445F26D54F0E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998F0F445F26D54F0E&quot; width=&quot;700&quot; height=&quot;270&quot; alt=&quot;동기 실행 예제 2. (Synchronous 예제 2)&quot; filename=&quot;asynctask_synchronous_example_2.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이런 경우 개발자가 선택할 수 있는 방법은, 파일을 읽는 코드를 별도의 스레드에서 실행되도록 만들어 메인 스레드의 실행에 영향이 가지 않게 하는 만드는 것입니다. 즉, readFileData() 메서드 내부에서는 파일을 복사하는 새로운 스레드를 실행하기만 하고 바로 리턴되게 만드는 것이죠. 그러면 onCreate()에서 readFileData()를 호출하더라도 메인 스레드가 대기할 필요 없이 바로 다음 코드를 실행할 수 있습니다. 그리고 파일 복사 스레드에서 파일을 다 읽고나면, 메인 스레드에 메시지(Message)를 전달하여 메인 스레드에서 파일의 내용을 화면에 표시하게 만들면 됩니다. 이것이 바로 &lt;strong&gt;비동기(Asynchronous) 실행&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99992C3E5F26D54F0C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99992C3E5F26D54F0C&quot; width=&quot;700&quot; height=&quot;308&quot; alt=&quot;비동기 실행 예제 1. (Asynchronous 예제 1)&quot; filename=&quot;asynctask_asynchronous_example_1.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;단순히 파일을 읽는 경우를 예로 들어 비동기(Asynchronous) 실행을 설명했는데요, 사실, 앱의 기능을 구현하는데 있어 &quot;비동기(Asynchronous) 실행&quot;은 훨씬 다양한 상황에 적용 가능합니다. 크기가 큰 파일 복사, 데이터베이스 쿼리, HTTP 서버 API 요청, FTP 파일 다운로드 등, 비동기(Asynchronou) 실행이 필요한 경우를 찾는 것은 그리 어렵지 않죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;요약하자면, 동기(Synchronous) 실행과 비동기(Asynchronous) 실행은, 어떤 기능을 실행한 다음, 그 기능의 실행이 완료될 때까지 대기할 것인지 여부에 따라 구분됩니다. 실행이 모두 완료될 때까지 기다리면 &quot;동기(Synchronous) 실행&quot;, 실행이 완료되기를 기다리지 않고 바로 다음 코드를 실행하는 것은 &quot;비동기(Asynchronous) 실행&quot; 입니다.&lt;/p&gt;
&lt;h4 id=&quot;32-비동기asynchronous-실행-구현-방법&quot;&gt;3.2 비동기(Asynchronous) 실행 구현 방법.&lt;/h4&gt;
&lt;p&gt;자, &quot;비동기(Asynchronous) 실행&quot;에 대한 개념을 설명했으니, 이제, 실질적인 구현 방법에 대해 알아볼텐데요. 그런데 사실, &quot;비동기(Asynchronous) 실행&quot; 이라고 해서, 앞서 정리한 [&lt;a href=&quot;https://recipes4dev.tistory.com/category/ANDROID%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/THREAD&quot; title=&quot;[https://recipes4dev.tistory.com/category/ANDROID%20프로그래밍/THREAD] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;개발자를 위한 레시피 - THREAD&lt;/a&gt;]를 벗어나는 내용은 없습니다. 오히려, 앞서 다른 글에서 설명한 스레드와 스레드 간 통신에 대한 내용에 정확히 들어 있다고 할 수 있죠. &quot;메인 스레드의 실행에 영향을 줄 수 있는 기능을 새로운 스레드에서 실행하고, 기능이 완료되면 메인 스레드 핸들러로 메시지를 전달한다.&quot;는 것, 명확하지 않습니까?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 안드로이드에서의 &quot;비동기(Asynchronous) 실행&quot;을 위한 스레드 처리 과정을 가만히 살펴보면, 공통된 패턴이 존재하는 것을 발견할 수 있습니다. 바로, 스레드에서 실행되는 작업이 완료되면 더 이상 스레드를 유지하지 않아도 되는 &quot;단발성 실행&quot;이라는 것과 스레드 실행 중간 상태 또는 최종 결과를 &quot;메인 스레드로 전달&quot;한다는 사실입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9901BF3D5F26D54F0B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9901BF3D5F26D54F0B&quot; width=&quot;700&quot; height=&quot;326&quot; alt=&quot;비동기 실행 예제 2. (Asynchronous 예제 2)&quot; filename=&quot;asynctask_asynchronous_example_2.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이를 통해 &quot;비동기(Asynchronous) 실행&quot;의 정형화된 패턴을 나열해본다면, 아래처럼 될 수 있겠네요.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;실행(execute) : 비동기(Asynchronous) 작업 준비 및 시작.&lt;/li&gt;
&lt;li&gt;백그라운드 작업(doInBackground) : 백그라운드 스레드에서 비동기(Asynchronous) 작업 실행.&lt;/li&gt;
&lt;li&gt;진행 상황 업데이트(onProgressUpdate) : 백그라운드 스레드 진행 상황을 메인스레드로 전달.&lt;/li&gt;
&lt;li&gt;비동기 실행 완료 후 처리(onPostExecute) : 백그라운드 스레드 완료 후 메인스레드에 완료 상태 전달.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    execute -&amp;gt; doInBackground -&amp;gt; onProgressUpdate -&amp;gt; onPostExecute
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자 그렇다면, 안드로이드에서 &quot;비동기(Asynchronous) 실행&quot; 패턴은 어떻게 구현할 수 있을까요? 스레드와 관련된 이전 글들을 참고하여 코드를 작성한다면 어떻게 구현할 수 있을까요? 아마도 [&lt;a href=&quot;https://recipes4dev.tistory.com/category/ANDROID%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/THREAD&quot; title=&quot;[https://recipes4dev.tistory.com/category/ANDROID%20프로그래밍/THREAD] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;개발자를 위한 레시피 - THREAD&lt;/a&gt;]의 내용을 충분히 이해했다면, 스레드를 만들고 핸들러를 통해 메시지를 전달하는 과정이 그리 어렵지는 않을 것 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 안드로이드 SDK의 많은 부분이 그러하듯, 조금이라도 반복적인 구현 작업 요소가 포함되거나 작업 절차에 있어 공통적인 패턴이 존재한다면, 이는 개발자가 쉽게 사용할 수 있도록, 새로운 API로 제공됩니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&quot;비동기(Asynchronous) 실행&quot;을 위한 작업도 마찬가지이며, 여기서 설명할 &lt;strong&gt;AsyncTask&lt;/strong&gt; 클래스가 바로 비동기 실행을 위해 제공되는 클래스입니다.&lt;/p&gt;
&lt;h3 id=&quot;4-asynctask&quot;&gt;4. AsyncTask&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;AsyncTask&lt;/strong&gt;는 그 이름에서도 알 수 있듯이, 비동기(&lt;strong&gt;Async&lt;/strong&gt;hronous)적으로 실행될 필요가 있는 작업(&lt;strong&gt;Task&lt;/strong&gt;)을 위해 사용하는 클래스입니다. 특히 Thread, Handler, Message, Runnable 등을 직접 다루지 않아도, 메인 스레드와 별개로 &quot;비동기(Asynchronous) 실행&quot;이 필요한 작업에 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;AsyncTask로 비동기 작업을 구현하기 위해서는 먼저 아래의 몇 가지 사항에 대해 알아두어야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;추상 클래스 : abstract class AsyncTask.&lt;/li&gt;
&lt;li&gt;제네릭 타입 : AsyncTask&amp;lt;Params, Progress, Result&amp;gt;&lt;/li&gt;
&lt;li&gt;가변 인자 : (Params ...), (Progress ...)&lt;/li&gt;
&lt;li&gt;실행 단계 : onPreExecute, doInBackground, onProgressUpdate, onPostExecute&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;41-추상-클래스-abstract-class-asynctask&quot;&gt;4.1 추상 클래스. (abstract class AsyncTask)&lt;/h4&gt;
&lt;p&gt;AsyncTask는 추상 클래스(abstract class)입니다. 이 말은, AsyncTask를 사용하기 위해서는 반드시 AsyncTask를 상속(extends)한 클래스를 생성해야 한다는 것을 의미합니다. &quot;추상 클래스&quot;는 해당 클래스에 대한 인스턴스를 바로 생성할 수 없기 때문이죠.&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;AsyncTask&lt;/span&gt;&amp;lt;Params, Progress, Result&amp;gt; {

}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;좋습니다. &lt;code&gt;abstract&lt;/code&gt; 키워드를 확인했으니, 구현할 때 AsyncTask를 상속한 클래스를 만들면 되겠군요. 그런데 AsyncTask가 제네릭 타입으로 선언된 것을 확인할 수 있는데요, &quot;&amp;lt;Params, Progress, Result&amp;gt;&quot;는 각각 무엇을 의미할까요?&lt;/p&gt;
&lt;h4 id=&quot;42-제네릭-타입-asynctaskltparams-progress-resultgt&quot;&gt;4.2 제네릭 타입. (AsyncTask&amp;lt;Params, Progress, Result&amp;gt;)&lt;/h4&gt;
&lt;p&gt;AsyncTask는 &quot;비동기(Asynchronous) 실행&quot; 작업을 위해 사용하는 클래스입니다. 그리고 일반적으로 &quot;비동기(Asynchronous) 실행&quot; 작업은 &quot;작업 시작&quot;, &quot;작업 실행&quot;, &quot;상태 갱신&quot;, &quot;결과 확인&quot;이라는 공통된 단계를 거치게 됩니다. 이러한 단계들은, 뒤에서 조금 더 자세히 설명하겠지만, 추상 클래스인 AsyncTask를 상속할 때 반드시 오버라이드해야 하는 메서드들에 매핑됩니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 여기서 갑자기 의문이 생기네요. AsyncTask를 통해 구현하고자 하는 기능은 상황에 따라 다를테고 또 관리해야하는 데이터의 종류 또한 제각각일텐데, AsyncTask에서 구현해야 하는 메서드에서는 상황에 따라 변하는 타입의 데이터를 어떻게 전달하고 관리할 수 있을까요? &lt;strong&gt;AsyncTask 실행에 필요한 파라미터&lt;/strong&gt;(예. 파일 경로, URL, DB 파일 경로 등)라던가, &lt;strong&gt;현재 작업 진행 정보를 나타내는 상태 값&lt;/strong&gt;(예. 크기 또는 개수를 나타내는 정수 값, 진행율을 위한 실수 값 등), 그리고 &lt;strong&gt;작업의 실행이 완료된 후의 최종 결과&lt;/strong&gt;(예. 성공 또는 실패, 처리된 내용의 크기 또는 개수 등) 등이 상황에 따라 다르게 정의될 것은 명확한데 말이죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자, 그러면 이러한 상황, 즉, 구현하고자 하는 기능에 따라 클래스 내부에서 다른 타입의 데이터를 적용되게 만들어야 하는 상황에 대처하는 방법을 찾아야 하는데요, 공통된 코드를 다양한 타입에 재사용할 수 있게 만드는 방법, 바로 &lt;strong&gt;제네릭(Generics)&lt;/strong&gt; 입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;AsyncTask는 제네릭(Generics) 클래스로 선언되어, 각 메서드에서 사용할 데이터 타입을 AsyncTask를 상속할 때 결정할 수 있도록 만들어 놓았습니다. Params, Progress, Result가 그것들이죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9954EC4A5F26D54F19&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9954EC4A5F26D54F19&quot; width=&quot;700&quot; height=&quot;83&quot; alt=&quot;AsyncTask 제네릭 파라미터 타입&quot; filename=&quot;asynctask_generic_parameter_types.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;세 개의 제네릭 파라미터 타입은 이름이 가진 의미 그대로 AsyncTask에 전달될 파라미터(Params), 현재 작업 진행 상태 값(Progress), 작업 완료 최종 결과(Result)를 나타냅니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Params : AsyncTask 실행에 필요한 파라미터.&lt;/li&gt;
&lt;li&gt;Progress : 현재 작업 진행 정보를 나타내는 상태 값.&lt;/li&gt;
&lt;li&gt;Result : 작업의 실행이 완료된 후의 최종 결과.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;제네릭 파라미터 타입을 어떻게 사용해야 하는지 선뜻 이해되시나요? 지금 당장 이해가 되지 않는다고해서 너무 걱정하실 필요는 없습니다. 아래 예제 코드를 살펴보시면, 충분히 이해되실 거라 생각합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 여기서 잠깐, 또 한 가지 궁금한 것이 생겼습니다. 제네릭 파라미터 타입을 결정하고나서 데이터를 전달할 때 만약 두 개 이상의 값을 사용하려면 어떻게 해야 할까요? 예를 들어 파일 복사 작업의 현재 진행 상태를 표시할 때, 복사된 파일 개수를 나타내는 Count 값과 복사된 바이트 수를 나타내는 TotalBytes를 Progress를 통해 전달해야 한다면, 두 멤버를 가지는 새로운 클래스를 만들어야 하나요? 아니면 배열 또는 컬렉션(Collections) 객체를 사용해야 하는 건가요?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;아닙니다. 반드시 그렇게 할 필요는 없습니다. 왜냐하면 Params와 Progress는 doInBackground()와 onProgressUpdate() 메서드에서 각각 &lt;b&gt;가변 인자(Varargs)&lt;/b&gt;로 전달되기 때문입니다.&lt;/p&gt;
&lt;h4 id=&quot;43-가변-인자-varargs&quot;&gt;4.3 가변 인자. (Varargs)&lt;/h4&gt;
&lt;p&gt;가변 인자(Varargs)는 이름 그대로, 메서드에 전달되는 파라미터의 개수가 가변적이라는 의미입니다. 메서드에 전달할 파라미터의 개수가 일정하지 않을 때 사용하는 방법인데요. 파라미터의 타입에 &quot;...&quot;를 추가하여 메서드에 전달되는 파라미터가 가변 인자라는 것을 명시할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; Func(&lt;span class=&quot;pl-smi&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;..&lt;/span&gt; vals) ;       &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; String 타입의 가변 인자.&lt;/span&gt;

    &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; 아래와 같이 호출 가능.&lt;/span&gt;
    Func(&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;The first&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;) ;
    Func(&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;The first&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;The second&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;) ;
    Func(&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;The first&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;The second&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;The third&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;) ;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;메서드 내부에서 가변 인자를 통해 전달된 값을 사용하는 방법은 배열을 참조하는 방법과 동일합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; Func(&lt;span class=&quot;pl-smi&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;..&lt;/span&gt; vals) {
        &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; (vals&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;pl-k&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;) &lt;span class=&quot;pl-smi&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;println(vals[&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;]) ;
        &lt;span class=&quot;pl-k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; (vals&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;pl-k&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;2&lt;/span&gt;) &lt;span class=&quot;pl-smi&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;println(vals[&lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;]) ;
        &lt;span class=&quot;pl-k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; (vals&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;pl-k&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;) &lt;span class=&quot;pl-smi&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;println(vals[&lt;span class=&quot;pl-c1&quot;&gt;2&lt;/span&gt;]) ;
    }&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;AsyncTask의 doInBackground()와 onProgressUpdate() 메서드는 위와 같이 Params, Progress 제네릭 타입에 대한 가변 인자를 전달하도록 선언되어 있기 때문에, 다른 객체를 사용하지 않아도 두 개 이상의 값을 전달할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;AsyncTask&lt;/span&gt;&amp;lt;Params, Progress, Result&amp;gt; {

    &lt;span class=&quot;pl-k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Result&lt;/span&gt; &lt;b&gt;&lt;span class=&quot;pl-en&quot;&gt;doInBackground&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;Params&lt;/span&gt;... &lt;span class=&quot;pl-v&quot;&gt;params&lt;/span&gt;&lt;/b&gt;);
    &lt;span class=&quot;pl-k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;b&gt;&lt;span class=&quot;pl-en&quot;&gt;onProgressUpdate&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;Progress&lt;/span&gt;... &lt;span class=&quot;pl-v&quot;&gt;values&lt;/span&gt;)&lt;/b&gt; {}
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;아래 본문의 예제에서 좀 더 구체적인 가변 인자 사용법에 대해 살펴보실 수 있습니다.&lt;/p&gt;
&lt;h4 id=&quot;44-실행-단계-onpreexecute-doinbackground-onprogressupdate-onpostexecute&quot;&gt;4.4 실행 단계. (onPreExecute, doInBackground, onProgressUpdate, onPostExecute)&lt;/h4&gt;
&lt;p&gt;일단 AsyncTask를 통해 &quot;비동기(Asynchronous) 실행&quot;이 시작되면, AsyncTask는 &quot;작업 시작&quot;, &quot;작업 수행&quot;, &quot;상태 갱신&quot;, &quot;결과 확인&quot;의 네 단계를 거쳐 실행됩니다. 그리고 각 단계는 onPreExecute(), doInBackground(), onProgressUpdate(), onPostExecute()라는 메서드로 매핑됩니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9918EE4D5F26D95819&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9918EE4D5F26D95819&quot; width=&quot;700&quot; height=&quot;344&quot; alt=&quot;AsyncTask 실행 흐름&quot; filename=&quot;asynctask_execution_flow.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;onPreExecute()&lt;/strong&gt;. 작업이 실행되기 직전에 UI 스레드에 의해 호출됩니다. 일반적으로 UI 초기화와 같이, &quot;비동기(Asynchronous) 실행&quot; 작업에 대한 초기화 과정을 수행하는 메서드입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;doInBackground(Params...)&lt;/strong&gt;. onPreExecute()가 호출된 뒤, 곧 바로 백그라운드 스레드에서 호출됩니다. AsyncTask가 수행할 실질적인 작업 실행 코드가 작성되는 메서드입니다. AsyncTask의 첫 번째 제네릭 파라미터 타입(Params)이 이 메서드의 파라미터 타입으로 매핑되고, 마지막 제네릭 파라미터 타입(Result)이 doInBackground()의 리턴 타입으로 매핑됩니다.&lt;br /&gt;
그리고 doInBackground() 실행 중 상태 업데이트가 필요한 경우, publishProgress(Progress...) 메서드를 호출하여 메인 스레드에서 onProgressUpdate(Progress...)가 호출되게 만들 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;onProgressUpdate(Progress...)&lt;/strong&gt;. 백그라운드 스레드에서 동작하는 doInBackground()에서 publishProgress(Progress...)를 호출하면, UI 스레드에서 호출되는 메서드입니다. 보통 현재 작업 진행 상태를 화면에 갱신하는 역할을 수행합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;onPostExecute(Result)&lt;/strong&gt;. 백그라운드 스레드의 모든 실행이 완료되면 UI 스레드에서 호출되는 메서드입니다. onPostExecute()의 파라미터(Result)는 doInBackground()에서 리턴되는 값입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;5-asynctask-예제&quot;&gt;5. AsyncTask 예제.&lt;/h3&gt;
&lt;p&gt;그럼 이제 예제를 작성하면서, AsyncTask를 사용하는 방법에 대해 알아보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예제에서 구현하는 기능은 간단합니다. 먼저 앱의 에셋(Assets) 폴더에 파일을 하나 추가합니다. 그리고 화면의 버튼을 클릭하면 애셋(Assets)에 저장된 파일을 앱의 로컬 디렉토리에 복사하도록 만듭니다. 주로, 미리 만들어진 형식의 파일(DB, XML, JSON 등)을 앱 릴리즈 시점에 같이 배포한 다음, 앱의 로컬 디렉토리에서 읽고 쓸 수 있게 만들 때 사용하는 방법이죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예제 화면 구성과 동작도 아주 간단합니다. 프로그레스바(ProgressBar)와 텍스트뷰, 그리고 버튼을 하나씩 화면에 배치한 다음, 버튼을 클릭하면 AsyncTask를 통해 &quot;비동기(Asynchronous) 실행&quot; 작업을 수행하고 작업 진행 과정을 프로그레스바와 텍스트뷰에 표시합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997FBE465F26D54F13&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997FBE465F26D54F13&quot; width=&quot;700&quot; height=&quot;198&quot; alt=&quot;AsyncTask 예제 화면 구성&quot; filename=&quot;asynctask_example_ui_layout.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;단, 파일 복사 과정은 매우 짧은 시간에 끝날 수 있기 때문에, 기능 동작의 식별을 위해 AsyncTask의 doInBackground() 메서드에서 파일을 복사할 때 Thread.sleep()을 사용하여 약간의 지연을 적용하였습니다.&lt;/p&gt;
&lt;h4 id=&quot;51-워크플로우&quot;&gt;5.1 워크플로우&lt;/h4&gt;
&lt;p&gt;AsyncTask 예제를 작성하는 절차는 아래와 같습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99938E4E5F26DB0618&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99938E4E5F26DB0618&quot; width=&quot;700&quot; height=&quot;457&quot; alt=&quot;AsyncTask 예제 구현 절차&quot; filename=&quot;asynctask_example_implementation_sequence.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;참고로, 예제코드는 안드로이드 스튜디오 프로젝트 생성 단계에서 &quot;Basic Activity&quot;를 선택하여 생성된 코드를 기반으로 작성되었습니다.&lt;/p&gt;
&lt;h4 id=&quot;52-asset에-파일-추가&quot;&gt;5.2 Asset에 파일 추가.&lt;/h4&gt;
&lt;p&gt;AsyncTask를 구현하기에 앞서, 하나의 파일을 애셋(Assets) 폴더에 추가합니다. (예제에서는 약 500KB 크기 파일 사용). 파일의 내용은 중요하지 않으므로, 아무 파일이나 1MB 이내 크기의 파일을 사용하시면 무방할 것 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-1] &quot;/assets/intro.mp4&quot; - 애셋(Assets) 폴더에 파일 추가.
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C4A33E5F26D54F08&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C4A33E5F26D54F08&quot; width=&quot;700&quot; height=&quot;286&quot; alt=&quot;애셋(Assets) 폴더에 파일 추가&quot; filename=&quot;asynctask_example_add_file_to_assets.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;참고로, 예제에서는 &quot;mp4&quot; 확장자(&quot;intro.mp4&quot;)를 가진 파일을 애셋에 추가했습니다. 그래서 &lt;code&gt;AssetManager&lt;/code&gt;의 &lt;code&gt;openFd()&lt;/code&gt; API를 이용해 파일을 열 때 별다른 문제가 발생하지 않았는데요. 만약 다른 확장자를 사용하면, 아래와 같이 파일을 열 수 없다는 에러가 발생할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;error&quot;&gt;&lt;code&gt;&lt;b&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed&lt;/span&gt;&lt;/b&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;안드로이드 애셋에 파일을 추가하면 기본적으로 파일의 내용을 압축하여 저장하기 때문에 발생하는 문제인데요. &quot;mp4&quot; 확장자를 비롯하여 &quot;jpg&quot;, &quot;png&quot;, &quot;mp3&quot;, &quot;wav&quot; 등을 포함한 다수의 이미지 또는 미디어 파일들은 압축하지 않은 원본 형태로 저장되지만, 그 외 파일들은 압축되어 저장됩니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;만약, 임의의 확장자를 가진 파일(예. &quot;db&quot;, &quot;sql&quot;)을 압축되지 않은 형태로 애셋에 추가하려면, &quot;build.gradle&quot;(Module:app) 파일에 아래 내용을 명시하면 됩니다.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;android {
    aaptOptions {
        noCompress 'db','sql'
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;만약 애셋에 추가되는 모든 파일을 압축되지 않게 만드려면, 아래와 같이 &quot;noCompress&quot; 옵션에 빈 값을 지정하면 됩니다.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;android {
    aaptOptions {
        noCompress ''
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;안드로이드 애셋(Android Asset)에 대한 기본 사용법은 [&lt;a href=&quot;https://recipes4dev.tistory.com/125&quot; title=&quot;[https://recipes4dev.tistory.com/125] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 애셋(Asset) 사용하기.&lt;/a&gt;]의 내용을 참고하시기 바랍니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;53-메인액티비티-레이아웃-작성&quot;&gt;5.3 메인액티비티 레이아웃 작성.&lt;/h4&gt;
&lt;p&gt;앞서 설계한 화면대로 메인액티비티 레이아웃 리소스 XML을 작성합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-2] &quot;content_main.xml&quot; - 메인액티비티 레이아웃 리소스 XML 작성.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-xml&quot;&gt;&lt;pre&gt;&amp;lt;?&lt;span class=&quot;pl-ent&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt; version&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;1.0&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt; encoding&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;utf-8&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;?&amp;gt;
&amp;lt;&lt;span class=&quot;pl-ent&quot;&gt;androidx&lt;/span&gt;.constraintlayout.widget.ConstraintLayout &lt;span class=&quot;pl-e&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;http://schemas.android.com/apk/res/android&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;http://schemas.android.com/apk/res-auto&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;tools&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;http://schemas.android.com/tools&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_width&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;match_parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_height&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;match_parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_behavior&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@string/appbar_scrolling_view_behavior&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;context&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;.MainActivity&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;showIn&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@layout/activity_main&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;

    &amp;lt;&lt;span class=&quot;pl-ent&quot;&gt;TextView&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_width&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;0dp&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_height&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;wrap_content&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;text&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;Press COPY button to copy DB file.&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@+id/textMessage&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;textSize&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;32sp&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;textColor&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;#FFFFFF&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;background&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;#0000FF&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;gravity&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;center&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintLeft_toLeftOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintTop_toTopOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintRight_toRightOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; /&amp;gt;

    &amp;lt;&lt;span class=&quot;pl-ent&quot;&gt;ProgressBar&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;style&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@android:style/Widget.ProgressBar.Horizontal&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_width&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;0dp&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_height&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;40dp&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@+id/progressCopy&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;progress&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintLeft_toLeftOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintTop_toBottomOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@id/textMessage&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintRight_toRightOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_margin&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;20dp&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; /&amp;gt;

    &amp;lt;&lt;span class=&quot;pl-ent&quot;&gt;Button&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_width&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;wrap_content&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_height&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;wrap_content&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@+id/buttonCopy&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;text&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;Copy&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintLeft_toLeftOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintTop_toBottomOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@id/progressCopy&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintRight_toRightOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_margin&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;20dp&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; /&amp;gt;

&amp;lt;/&lt;span class=&quot;pl-ent&quot;&gt;androidx&lt;/span&gt;.constraintlayout.widget.ConstraintLayout&amp;gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;54-화면-구성-뷰에-대한-참조-획득&quot;&gt;5.4 화면 구성 뷰에 대한 참조 획득.&lt;/h4&gt;
&lt;p&gt;화면에 배치한 뷰에 파일 복사 과정을 업데이트하기 위해, 메인액티비티의 onCreate() 메서드에서 텍스트뷰(id:textMessage)와 프로그레스바(id:progressCopy)의 참조를 획득하는 코드를 작성합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-3] &quot;MainActivity.java&quot; - 화면에 배치된 뷰에 대한 참조 획득.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;MainActivity&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;AppCompatActivity&lt;/span&gt; {
    &lt;span class=&quot;pl-k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;ProgressBar&lt;/span&gt; mProgressCopy &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt; ;
    &lt;span class=&quot;pl-k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;TextView&lt;/span&gt; mTextMessage &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt; ;

    &lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onCreate&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;Bundle&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;savedInstanceState&lt;/span&gt;) {
        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt;/ ... 코드 계속&lt;/span&gt;

        mProgressCopy &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; findViewById(&lt;span class=&quot;pl-smi&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;progressCopy) ;
        mTextMessage &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; findViewById(&lt;span class=&quot;pl-smi&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;textMessage) ;

        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt;/ 코드 계속 ...&lt;/span&gt;
    }
}&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;55-asynctask-클래스-상속&quot;&gt;5.5 AsyncTask 클래스 상속.&lt;/h4&gt;
&lt;p&gt;이제, 애셋 폴더의 파일을 앱 로컬 디렉토리로 복사하는 작업을 구현하기 위해 AsyncTask를 상속한 클래스를 추가합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-4] &quot;MainActivity.java&quot; - AsyncTask를 상속한 클래스 추가.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;MainActivity&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;AppCompatActivity&lt;/span&gt; {
    &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt;/ 코드 계속 ...&lt;/span&gt;

    &lt;span class=&quot;pl-k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;CopyDatabaseAsyncTask&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;AsyncTask&amp;lt;&lt;span class=&quot;pl-smi&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;pl-smi&quot;&gt;Long&lt;/span&gt;, &lt;span class=&quot;pl-smi&quot;&gt;Boolean&lt;/span&gt;&amp;gt;&lt;/span&gt; {
        &lt;span class=&quot;pl-k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Context&lt;/span&gt; mContext &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt; ;

        &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;CopyDatabaseAsyncTask&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;Context&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;context&lt;/span&gt;) {
            mContext &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; context ;
        }
        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; TODO : override onPreExecute(), doInBackground(), onProgressUpdate(), onPostExecute().&lt;/span&gt;
    }
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;AsyncTask를 상속한 CopyDatabaseAsyncTask에서는 Params, Progress, Result를 각각 String, Integer, Integer 타입으로 지정합니다. Params에는 애셋(Assets)에서 복사할 파일 이름이 전달되므로 String 타입을, Progress와 Result에는 현재 복사 중인 파일의 크기와 최종적으로 복사된 파일 크기가 전달되기 때문에 Integer 타입을 지정합니다.&lt;/p&gt;
&lt;h4 id=&quot;56-onpreexecute-메서드-오버라이드&quot;&gt;5.6 onPreExecute() 메서드 오버라이드.&lt;/h4&gt;
&lt;p&gt;AsyncTask 기능 구현의 첫 번째 단계는 onPreExecute() 메서드를 오버라이드하는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;앞서 설명했듯이, onPreExecute() 메서드는 AsyncTask의 백그라운드 스레드가 실행되기 전, 메인 스레드에 의해 호출되는 메서드입니다. 주로 UI 초기화 작업이 이루어지는 메서드죠. 예제에서도 화면 각 요소 값의 초기화를 onPreExecute()에서 수행합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-5] &quot;MainActivity.java&quot; - onPreExecute() 메서드 오버라이드.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;pl-k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;CopyDatabaseAsyncTask&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;AsyncTask&amp;lt;&lt;span class=&quot;pl-smi&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;pl-smi&quot;&gt;Long&lt;/span&gt;, &lt;span class=&quot;pl-smi&quot;&gt;Boolean&lt;/span&gt;&amp;gt;&lt;/span&gt; {

        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt;/ ... 코드 계속.&lt;/span&gt;

        &lt;b&gt;&lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onPreExecute&lt;/span&gt;() {
            mProgressCopy&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;setMax(&lt;span class=&quot;pl-c1&quot;&gt;100&lt;/span&gt;) ;
            mProgressCopy&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;setProgress(&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;) ;
        }&lt;/b&gt;

        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt;/ 코드 계속 ...&lt;/span&gt;
    }&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;57-doinbackground-메서드-오버라이드&quot;&gt;5.7 doInBackground() 메서드 오버라이드.&lt;/h4&gt;
&lt;p&gt;이제 실질적인 비동기 작업이 실행되는 doInBackground() 메서드를 오버라이드합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;앞에서도 강조했듯이, doInBackground() 메서드는 메인스레드가 아닌, 백그라운드 스레드에서 실행되는 코드입니다. 그러므로 doInBackground() 메서드 내에서 UI를 직접 제어하면 안됩니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;대신, publishProgress() 메서드를 사용하여 화면에 표시될 데이터를 전달하고, onProgressUpdate() 메서드에서 UI 화면을 갱신할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-6] &quot;MainActivity.java&quot; - doInBackground() 메서드 오버라이드.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;pl-k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;CopyDatabaseAsyncTask&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;AsyncTask&amp;lt;&lt;span class=&quot;pl-smi&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;pl-smi&quot;&gt;Long&lt;/span&gt;, &lt;span class=&quot;pl-smi&quot;&gt;Boolean&lt;/span&gt;&amp;gt;&lt;/span&gt; {
        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt;/ ... 코드 계속&lt;/span&gt;

        &lt;b&gt;&lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Boolean&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;doInBackground&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;String&lt;/span&gt;... &lt;span class=&quot;pl-v&quot;&gt;params&lt;/span&gt;) {
            &lt;span class=&quot;pl-smi&quot;&gt;AssetManager&lt;/span&gt; am &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; mContext&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;getResources()&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;getAssets() ;
            &lt;span class=&quot;pl-smi&quot;&gt;File&lt;/span&gt; file &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt; ;
            &lt;span class=&quot;pl-smi&quot;&gt;InputStream&lt;/span&gt; is &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt; ;
            &lt;span class=&quot;pl-smi&quot;&gt;FileOutputStream&lt;/span&gt; fos &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt; ;
            &lt;span class=&quot;pl-k&quot;&gt;long&lt;/span&gt; fileSize &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt; ;
            &lt;span class=&quot;pl-k&quot;&gt;long&lt;/span&gt; copySize &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt; ;
            &lt;span class=&quot;pl-k&quot;&gt;int&lt;/span&gt; len &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt; ;

            &lt;span class=&quot;pl-k&quot;&gt;byte&lt;/span&gt;[] buf &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;byte&lt;/span&gt;[&lt;span class=&quot;pl-c1&quot;&gt;1024&lt;/span&gt;] ;

            &lt;span class=&quot;pl-k&quot;&gt;try&lt;/span&gt; {
                fileSize &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; am&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;openFd(params[&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;])&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;getLength() ;

                is &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; am&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;open(params[&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;]) ;

                file &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;File&lt;/span&gt;(getFilesDir(), params[&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;]) ;
                fos &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;FileOutputStream&lt;/span&gt;(file) ;

                &lt;span class=&quot;pl-k&quot;&gt;while&lt;/span&gt; ((len &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; is&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;read(buf)) &lt;span class=&quot;pl-k&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;) {
                    fos&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;write(buf, &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;, len) ;

                    copySize &lt;span class=&quot;pl-k&quot;&gt;+=&lt;/span&gt; len ;

                    publishProgress(fileSize, copySize) ;

                    &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; sleep 100ms.&lt;/span&gt;
                    &lt;span class=&quot;pl-smi&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;sleep(&lt;span class=&quot;pl-c1&quot;&gt;10&lt;/span&gt;) ;
                }

                &lt;span class=&quot;pl-smi&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;sleep(&lt;span class=&quot;pl-c1&quot;&gt;500&lt;/span&gt;) ;

                fos&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;close() ;
                is&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;close() ;
            } &lt;span class=&quot;pl-k&quot;&gt;catch&lt;/span&gt; (&lt;span class=&quot;pl-smi&quot;&gt;Exception&lt;/span&gt; e) {
                e&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;printStackTrace() ;
            }

            &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; (fileSize &lt;span class=&quot;pl-k&quot;&gt;==&lt;/span&gt; copySize) ;
        }&lt;/b&gt;

        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt;/ 코드 계속 ...&lt;/span&gt;
    }&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;58-onprogressupdate-메서드-오버라이드&quot;&gt;5.8 onProgressUpdate() 메서드 오버라이드.&lt;/h4&gt;
&lt;p&gt;doInBackground() 메서드에서 publishProgress() 메서드를 호출했을 때, 메인 UI 스레드에서 실행할 onProgressUpdate() 메서드를 구현합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-7] &quot;MainActivity.java&quot; - onProgressUpdate() 메서드 오버라이드.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;pl-k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;CopyDatabaseAsyncTask&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;AsyncTask&amp;lt;&lt;span class=&quot;pl-smi&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;pl-smi&quot;&gt;Long&lt;/span&gt;, &lt;span class=&quot;pl-smi&quot;&gt;Boolean&lt;/span&gt;&amp;gt;&lt;/span&gt; {
        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt;/ ... 코드 계속&lt;/span&gt;

        &lt;b&gt;&lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onProgressUpdate&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;Long&lt;/span&gt;... &lt;span class=&quot;pl-v&quot;&gt;values&lt;/span&gt;) {
            &lt;span class=&quot;pl-k&quot;&gt;long&lt;/span&gt; fileSize &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; values[&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;] ;
            &lt;span class=&quot;pl-k&quot;&gt;long&lt;/span&gt; copySize &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; values[&lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;] ;
            &lt;span class=&quot;pl-k&quot;&gt;int&lt;/span&gt; percent &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;pl-k&quot;&gt;int&lt;/span&gt;)((copySize &lt;span class=&quot;pl-k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;100&lt;/span&gt;) &lt;span class=&quot;pl-k&quot;&gt;/&lt;/span&gt; fileSize) ;

            mTextMessage&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;setText(percent &lt;span class=&quot;pl-k&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt; %&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;) ;
            mProgressCopy&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;setProgress(percent) ;
        }&lt;/b&gt;

        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt;/ 코드 계속 ...&lt;/span&gt;
    }&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;59-onpostexecute-메서드-오버라이드&quot;&gt;5.9 onPostExecute() 메서드 오버라이드.&lt;/h4&gt;
&lt;p&gt;마지막으로 doInBackground() 메서드 실행이 완료되어 리턴되었을 때 호출되는 onPostExecute() 메서드를 구현합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-8] &quot;MainActivity.java&quot; - onPostExecute() 메서드 오버라이드.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;pl-k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;CopyDatabaseAsyncTask&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;AsyncTask&amp;lt;&lt;span class=&quot;pl-smi&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;pl-smi&quot;&gt;Long&lt;/span&gt;, &lt;span class=&quot;pl-smi&quot;&gt;Boolean&lt;/span&gt;&amp;gt;&lt;/span&gt; {
        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt;/ ... 코드 계속&lt;/span&gt;

        &lt;b&gt;&lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onPostExecute&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;Boolean&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;result&lt;/span&gt;) {
            mTextMessage&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;setText(&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;Copy completed.&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;) ;
        }&lt;/b&gt;

        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt;/ 코드 계속 ...&lt;/span&gt;
    }&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;510-asynctask-실행&quot;&gt;5.10 AsyncTask 실행.&lt;/h4&gt;
&lt;p&gt;이제 AsyncTask에서 구현해야 할 메서드는 모두 작성하였으므로, 메인액티비티에서 앞서 작성한 AsyncTask를 실행하기 위해 execute() 메서드를 호출하는 코드를 작성합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-9] &quot;MainActivity.java&quot; - onPostExecute() 메서드 오버라이드.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;MainActivity&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;AppCompatActivity&lt;/span&gt; {

    &lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onCreate&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;Bundle&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;savedInstanceState&lt;/span&gt;) {

        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt;/ ... 코드 계속.&lt;/span&gt;

        &lt;b&gt;&lt;span class=&quot;pl-smi&quot;&gt;Button&lt;/span&gt; buttonCopy &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; findViewById(&lt;span class=&quot;pl-smi&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;buttonCopy) ;
        buttonCopy&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;setOnClickListener(&lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Button&lt;/span&gt;.&lt;span class=&quot;pl-smi&quot;&gt;OnClickListener&lt;/span&gt;() {
            &lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onClick&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;View&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;v&lt;/span&gt;) {
                &lt;span class=&quot;pl-smi&quot;&gt;CopyDatabaseAsyncTask&lt;/span&gt; task &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;CopyDatabaseAsyncTask&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;MainActivity&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;this&lt;/span&gt;) ;
                task&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;execute(&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;intro.mp4&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;) ;
            }
        });&lt;/b&gt;
    }
}&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;6-실행-결과&quot;&gt;6. 실행 결과.&lt;/h3&gt;
&lt;p&gt;예제를 실행하면, 아래와 같은 화면이 표시됩니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99708A4B5F26D54F14&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99708A4B5F26D54F14&quot; width=&quot;700&quot; height=&quot;416&quot; alt=&quot;AsyncTask 예제 실행 화면 1&quot; filename=&quot;asynctask_example_screenshot_1.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;화면의 &quot;COPY&quot; 버튼을 클릭하면, 아래 그림과 같이, 파일 복사와 함께 진행 상태가 화면에 업데이트 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99833C475F26D54F1B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99833C475F26D54F1B&quot; width=&quot;700&quot; height=&quot;416&quot; alt=&quot;AsyncTask 예제 실행 화면 2&quot; filename=&quot;asynctask_example_screenshot_2.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;복사가 모두 완료되면, AsyncTask가 종료되고 아래 화면과 같이 &quot;Copy completed&quot; 메시지가 표시됩니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BE143E5F26D54F0F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BE143E5F26D54F0F&quot; width=&quot;700&quot; height=&quot;416&quot; alt=&quot;AsyncTask 예제 실행 화면 3&quot; filename=&quot;asynctask_example_screenshot_3.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;7-참고&quot;&gt;7. 참고.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;개발자 레시피 - 스레드 관련 항목.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/143&quot; title=&quot;[https://recipes4dev.tistory.com/143] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드(Android Thread)&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/150&quot; title=&quot;[https://recipes4dev.tistory.com/150] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드 예제. 스레드로 고민해보기. (Android Thread UseCase)&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/166&quot; title=&quot;[https://recipes4dev.tistory.com/166] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드. 핸들러와 메시지. (Android Thread. Handler and Message.)&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/170&quot; title=&quot;[https://recipes4dev.tistory.com/170] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드. 핸들러와 Runnable. (Android Thread. Handler and Runnable.)&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/172&quot; title=&quot;[https://recipes4dev.tistory.com/172] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 runOnUiThread() 메서드. (Android runOnUiThread() Method)&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;AsyncTask에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/AsyncTask&quot; title=&quot;[https://developer.android.com/reference/android/os/AsyncTask] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. AsyncTask&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;UI 스레드와 통신하기.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/training/multiple-threads/communicate-ui&quot; title=&quot;[https://developer.android.com/training/multiple-threads/communicate-ui] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 가이드. Communicate with the UI thread&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Thread에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/java/lang/Thread.html&quot; title=&quot;[https://developer.android.com/reference/java/lang/Thread.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Thread&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Runnable에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/java/lang/Runnable.html&quot; title=&quot;[https://developer.android.com/reference/java/lang/Runnable.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Runnable&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Looper에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/Looper.html&quot; title=&quot;[https://developer.android.com/reference/android/os/Looper.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Looper&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Handler에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/Handler.html&quot; title=&quot;[https://developer.android.com/reference/android/os/Handler.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Handler&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Message에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/Message.html&quot; title=&quot;[https://developer.android.com/reference/android/os/Message.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Message&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MessageQueue에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/MessageQueue.html&quot; title=&quot;[https://developer.android.com/reference/android/os/MessageQueue.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. MessageQueue&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.END.&lt;/p&gt;&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>ANDROID 프로그래밍/THREAD</category>
      <category>Android</category>
      <category>asynchronous</category>
      <category>AsyncTask</category>
      <category>doInBackground</category>
      <category>onPostExecute</category>
      <category>onPreExecute</category>
      <category>onProgressUpdate</category>
      <category>synchronous</category>
      <category>synchronous vs asynchronous</category>
      <category>동기</category>
      <category>동기 vs 비동기</category>
      <category>비동기</category>
      <category>비동기 작업</category>
      <category>안드로이드</category>
      <category>어싱크태스크</category>
      <category>태스크</category>
      <author>뽀따</author>
      <guid isPermaLink="true">https://recipes4dev.tistory.com/174</guid>
      <comments>https://recipes4dev.tistory.com/174#entry174comment</comments>
      <pubDate>Mon, 3 Aug 2020 00:28:40 +0900</pubDate>
    </item>
    <item>
      <title>오픈JDK 다운로드 및 설치. (OpenJDK Download and Install)</title>
      <link>https://recipes4dev.tistory.com/173</link>
      <description>&lt;link rel=&quot;stylesheet&quot; href=&quot;https://tistory1.daumcdn.net/tistory/1573970/skin/images/style_gfm.css&quot; type=&quot;text/css&quot;&gt;

&lt;article class=&quot;madwin-body&quot;&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;1-자바와-오라클-그리고-openjdk&quot;&gt;1. 자바와 오라클. 그리고 OpenJDK.&lt;/h3&gt;
&lt;p&gt;&quot;썬 마이크로시스템즈(Sun Microsystems)&quot; 시절의 자바(Java)는 GPL 라이센스를 가졌기 때문에 자바 프로그램 개발 및 운용에 있어 JDK(Java Development Kit, 자바 개발 도구)를 사용하는 것에 별다른 제약이 존재하지 않았습니다. 즉, 누구나 무료로 사용할 수 있었죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 &quot;썬 마이크로시스템즈(Sun Microsystems)&quot;가 오라클(Oracle)로 인수되고나서 오라클의 JDK에 대한 정책(년 단위 구독형 유료 라이센스로 전환)이 변경되면서, 오라클에서 제공하는 JDK를 무조건 무료로만 사용할 수는 없게 되었습니다. 물론, 비상업적(Non-commercial)인 용도에 한해서는 여전히 무료 사용이 가능하지만, 이익 창출이 최우선 목적인 일반 회사들에서는 오라클 JDK의 유료 전환이 부담으로 느껴질 수 밖에 없습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;하지만 다행히도, 유료로 전환된 오라클 JDK 대신, 무료로 사용할 수 있는 JDK가 존재합니다. 바로 &quot;OpenJDK&quot; 입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99082A415D8D488017&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99082A415D8D488017&quot; width=&quot;700&quot; height=&quot;176&quot; alt=&quot;OpenJDK&quot; filename=&quot;openjdk_logo.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;11-openjdk&quot;&gt;1.1 OpenJDK&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;OpenJDK&lt;/strong&gt;는 &quot;썬 마이크로시스템즈(Sun Microsystems)&quot;가 만든 JDK의 오픈소스 프로젝트입니다. 자바가 대중화되고 많은 기업들이 소프트웨어 개발에 자바를 사용함에 따라 자바의 오픈 소스 공개를 요구하는 목소리가 커지게 되었고, 이에 &quot;썬 마이크로시스템즈(Sun Microsystems)&quot;는 JDK 소스코드를 GPL 라이센스 하에 공개하고, OpenJDK라는 오픈소스 프로젝트로 만들게 된 것이죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;하지만 OpenJDK가 오픈소스라고 해도, 누구나 마음대로 OpenJDK의 소스를 수정하고 배포할 수는 없습니다. &quot;썬 마이크로시스템즈(Sun Microsystems)&quot;가 OpenJDK를 공개할 때, 개발 참여 권한에 대한 인증 및 협약 절차를 만들어두었기 때문입니다. TCK(Technology Compatibility Kit)와 OCTLA(OpenJDK Community TCK License Agreement)가 바로 그것인데요. OpenJDK는 TCK 인증을 받고 OCTLA 협약을 체결한 업체와 기관들에 의해 개발 및 관리됩니다. 그리고 현재는 오라클이 &quot;썬 마이크로시스템즈(Sun Microsystems)&quot;의 역할을 그대로 물려받아 인증과 협약 절차를 수행하고 있습니다.&lt;/p&gt;
&lt;h4 id=&quot;12-오라클-jdk-vs-openjdk&quot;&gt;1.2 오라클 JDK vs OpenJDK.&lt;/h4&gt;
&lt;p&gt;그러면 &quot;오라클 JDK와 OpenJDK 둘 다 오라클에서 관리하니, 결국 둘이 같은 거 아닌가?&quot; 라는 의문이 들 수도 있을텐데요. 결론부터 말하자면, 이 둘은 동일한 스펙과 구현을 포함하고 있지만, 명백히 다른 JDK입니다. OpenJDK는 모든 JDK의 구현 기준(reference implementation)이 되는 JDK이고, 오라클 JDK는 OpenJDK의 구현에 더해 여러 추가적인 요소(Libraries, Plugins, WebStart, Third Party Components...)들을&amp;nbsp;포함하고 있죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그리고 결정적으로, 앞서 언급한 유/무료 라이센스에서 유추할 수 있듯이, 지원 및 유지보수의 범위와 기간에서 차이를 가집니다. OpenJDK는 6개월마다 릴리즈되는데, 일단 릴리즈된 버전은 다음 릴리즈 전까지만 지원 가능하고 그 후에는 유지보수가 이루어지지 않습니다. 즉, 릴리즈 후 6개월이 지난 JDK에 업데이트 Feature 또는&amp;nbsp;버그 픽스를 적용하기 위해서는 새로운 버전의 JDK로 업그레이드해야 한다는 것이죠. 이는 개발자에게는 큰 무리없는 릴리즈 정책이지만, 오랜 기간 안정적인 운영 및 유지보수가 요구되는 사용자 측면에서는 꽤 큰 위험 부담으로 다가올 수 밖에 없습니다. 반면 오라클 JDK는 약 3년 정도의 릴리즈 주기를 가지며, 오랜 기간(Long Term) 오라클에 의해 지원이 이루어집니다.&lt;/p&gt;
&lt;h4 id=&quot;13-어떤-jdk를-써야-하는가&quot;&gt;1.3 어떤 JDK를 써야 하는가?&lt;/h4&gt;
&lt;p&gt;현재 오라클 JDK 라이센스를 보유하지 않은 기업의 개발자라면, 일단 OpenJDK를 사용하는 게 맞습니다. 그리고 아마도 대부분 큰 어려움없이 개발 진행이 가능할거라 예상합니다. OpenJDK의 안정성이 과거에 비해 매우 좋아졌으니까요. 그리고 만약 오라클 JDK에 포함된 요소를 반드시 사용해야 한다면, 그 때 오라클 JDK로 변경해도 큰 무리가 없을 것 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;다만, 운용 측면에서는 조금 더 신중한 접근이 필요할 것 같은데요. 하지만 아쉽게도, 지금 제가 가진 지식과 경험으로는 확실한 정보를 드리기 쉽지 않습니다. 오라클 홈페이지 또는 컨설팅 업체 등 다른 경로를 통해 정보를 습득하시는게 이슈를 줄이는 방법이 될 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;음, 구구절절 설명이 좀 길어졌는데요, 그럼 이제 OpenJDK를 다운로드하고 설치하는 방법에 대해 알아보겠습니다.&lt;/p&gt;
&lt;h3 id=&quot;2-openjdk-다운로드&quot;&gt;2. OpenJDK 다운로드&lt;/h3&gt;
&lt;h4 id=&quot;21-openjdk-다운로드-페이지-접속&quot;&gt;2.1 OpenJDK 다운로드 페이지 접속.&lt;/h4&gt;
&lt;p&gt;OpenJDK 공식 홈페이지는 [&lt;a href=&quot;https://openjdk.java.net&quot; title=&quot;openjdk.java.net&quot;&gt;openjdk.java.net&lt;/a&gt;]입니다. 하지만 여기서 설치 파일을 바로 다운로드 할 수는 없고, [&lt;a href=&quot;https://jdk.java.net&quot; title=&quot;jdk.java.net&quot;&gt;jdk.java.net&lt;/a&gt;]에서 제공하는 링크를 통해 설치 파일을 다운로드 할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99FDC9375D8CC65932&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99FDC9375D8CC65932&quot; width=&quot;700&quot; height=&quot;686&quot; alt=&quot;OpenJDK 다운로드 페이지 접속&quot; filename=&quot;openjdk_download_1.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;22-openjdk-다운로드&quot;&gt;2.2 OpenJDK 다운로드.&lt;/h4&gt;
&lt;p&gt;2019년 9월 현재, 릴리즈 버전은 13이며, [&lt;a href=&quot;https://jdk.java.net/13&quot; title=&quot;jdk.java.net/13&quot;&gt;jdk.java.net/13&lt;/a&gt;] 페이지를 통해 [&lt;a href=&quot;https://download.java.net/java/GA/jdk13/5b8a42f3905b406298b72d750b6919f6/33/GPL/openjdk-13_windows-x64_bin.zip&quot; title=&quot;https://download.java.net/java/GA/jdk13/5b8a42f3905b406298b72d750b6919f6/33/GPL/openjdk-13_windows-x64_bin.zip&quot; rel=&quot;nofollow&quot;&gt;openjdk-13_windows-x64_bin.zip&lt;/a&gt;]파일을 다운로드할 수 있습니다. (파일 사이즈는 약 187MB.)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9986FC475D8CC65928&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9986FC475D8CC65928&quot; width=&quot;700&quot; height=&quot;482&quot; alt=&quot;OpenJDK 다운로드&quot; filename=&quot;openjdk_download_2.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;3-openjdk-설치&quot;&gt;3. OpenJDK 설치.&lt;/h3&gt;
&lt;h4 id=&quot;31-압축-파일-풀기&quot;&gt;3.1 압축 파일 풀기.&lt;/h4&gt;
&lt;p&gt;앞서 다운로드한 압축 파일(openjdk-13_windows-x64_bin.zip)을 풀어보면 아래 그림과 같은 파일과 폴더가 포함되어 있는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99FE8A445D8CC65A2C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99FE8A445D8CC65A2C&quot; width=&quot;700&quot; height=&quot;281&quot; alt=&quot;OpenJDK 압축 파일 풀기&quot; filename=&quot;openjdk_install_1.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;32-openjdk-실행-파일-복사&quot;&gt;3.2 OpenJDK 실행 파일 복사.&lt;/h4&gt;
&lt;p&gt;이제 OpenJDK에 포함된 파일들을 적절한 실행 경로에 복사하는 작업을 수행할텐데요. 여기서는 &quot;C:\Program Files&quot; 아래에 &quot;openjdk&quot;라는 폴더를 하나 만들고, 그곳에 &quot;jdk-13&quot; 디렉토리를 복사합니다. (&quot;C:\\Program Files\openjdk\jdk-13&quot;)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99810E425D8CC65A2F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99810E425D8CC65A2F&quot; width=&quot;700&quot; height=&quot;372&quot; alt=&quot;OpenJDK 실행 파일 복사&quot; filename=&quot;openjdk_install_2.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;OpenJDK 실행 파일은 복사했지만, 아직 모든 설치가 완료된 것은 아닙니다. OpenJDK에 포함된 실행 파일들(java, javac, ...)이 제대로 실행될 수 있도록, OpenJDK 설치 경로를 시스템 PATH 환경 변수에 추가해야 합니다.&lt;/p&gt;
&lt;h4 id=&quot;33-openjdk-실행-경로-환경-변수-추가&quot;&gt;3.3 OpenJDK 실행 경로 환경 변수 추가.&lt;/h4&gt;
&lt;p&gt;시스템 환경 변수는 &quot;제어판&quot;의 &quot;고급 시스템 설정&quot;을 통해 지정할 수 있습니다.&lt;/p&gt;
&lt;h5 id=&quot;331-제어판-실행&quot;&gt;3.3.1 제어판 실행&lt;/h5&gt;
&lt;p&gt;아래 그림과 같이, [시작] - [Windows 시스템] - [제어판] 메뉴를 통해 &quot;제어판&quot;을 실행합니다. (또는 &lt;kbd&gt;윈도우 키&lt;/kbd&gt; + &lt;kbd&gt;Pause&lt;/kbd&gt; 키를 눌러 &quot;제어판&quot;의 &quot;시스템&quot; 항목을 바로 실행할 수 있습니다.)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BABC475D8CC6591E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BABC475D8CC6591E&quot; width=&quot;700&quot; height=&quot;351&quot; alt=&quot;제어판 실행&quot; filename=&quot;openjdk_environment_1.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h5 id=&quot;332-고급-시스템-설정&quot;&gt;3.3.2 고급 시스템 설정.&lt;/h5&gt;
&lt;p&gt;&quot;제어판&quot; 화면에서 [시스템 및 보안] - [시스템] - [고급 시스템 설정] 메뉴를 선택하면 &quot;고급 시스템 설정&quot; 기능을 실행할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D6ED455D8CC65902&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D6ED455D8CC65902&quot; width=&quot;700&quot; height=&quot;684&quot; alt=&quot;고급 시스템 설정&quot; filename=&quot;openjdk_environment_2.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h5 id=&quot;333-환경-변수-설정-실행&quot;&gt;3.3.3 환경 변수 설정 실행.&lt;/h5&gt;
&lt;p&gt;환경 변수 관리는 &quot;시스템 속성&quot; 화면의 &quot;고급&quot; 탭에 있는 &quot;환경 변수&quot; 버튼을 통해 실행할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F2E44F5D8CC65935&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F2E44F5D8CC65935&quot; width=&quot;700&quot; height=&quot;401&quot; alt=&quot;환경 변수 설정&quot; filename=&quot;openjdk_environment_3.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h5 id=&quot;334-java_home-환경-변수-추가&quot;&gt;3.3.4 JAVA_HOME 환경 변수 추가.&lt;/h5&gt;
&lt;p&gt;먼저 추가해야 할 환경 변수는 &quot;JAVA_HOME&quot;입니다. JDK의 여러 실행 요소 및 자바 실행 환경을 필요로 하는 프로그램들에서 이 환경 변수를 참조하므로, &quot;시스템 변수&quot; 그룹의 &quot;새로 만들기&quot; 버튼을 클릭하여 &quot;JAVA_HOME&quot; 변수를 추가합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993F37445D8CC6592A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993F37445D8CC6592A&quot; width=&quot;700&quot; height=&quot;483&quot; alt=&quot;JAVA_HOME 환경 변수 추가&quot; filename=&quot;openjdk_environment_4.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h5 id=&quot;335-path-환경-변수에-자바-실행-경로java_homebin-추가&quot;&gt;3.3.5 PATH 환경 변수에 자바 실행 경로(JAVA_HOME/bin) 추가.&lt;/h5&gt;
&lt;p&gt;이제 시스템 PATH 환경 변수에 자바 실행 경로를 추가하여 자바 실행 파일(java, javac, ...)이 시스템에서 자유롭게 실행될 수 있게 만듭니다. 자바 실행 파일들은 OpenJDK의 &quot;bin&quot; 디렉토리에 들어 있으며, 앞서 &quot;JAVA_HOME&quot; 환경 변수를 추가해두었기 때문에 PATH 환경 변수에 &quot;%JAVA_HOME%\bin&quot;을 추가하면 됩니다. (여기서는 &quot;C:\Program Files\openjdk\jdk-13\bin&quot;에 해당.)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;PATH 환경 변수에 자바 실행 경로를 추가하기 위해, &quot;시스템 변수&quot; 리스트에서 &quot;Path&quot; 항목을 선택한 다음, &quot;편집&quot; 버튼을 클릭하여 PATH 환경 변수를 수정합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99296D465D8CC65A2F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99296D465D8CC65A2F&quot; width=&quot;700&quot; height=&quot;380&quot; alt=&quot;PATH 환경 변수 수정&quot; filename=&quot;openjdk_environment_5.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h5 id=&quot;336-환경-변수-설정-완료&quot;&gt;3.3.6 환경 변수 설정 완료.&lt;/h5&gt;
&lt;p&gt;이제 모든 과정이 완료되었습니다. &quot;확인&quot; 버튼을 클릭하여 설정을 완료합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99FE5B445D8CC65A16&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99FE5B445D8CC65A16&quot; width=&quot;700&quot; height=&quot;450&quot; alt=&quot;환경 변수 설정 완료&quot; filename=&quot;openjdk_envronment_6.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;4-openjdk-실행-확인&quot;&gt;4. OpenJDK 실행 확인.&lt;/h3&gt;
&lt;p&gt;OpenJDK 설치의 모든 과정이 완료되었으므로 Cmd 또는 Powershell을 통해 자바 실행 파일이 제대로 실행되는지 확인합니다.&lt;/p&gt;
&lt;h4 id=&quot;41-cmd-또는-powershell-실행&quot;&gt;4.1 Cmd 또는 Powershell 실행.&lt;/h4&gt;
&lt;p&gt;&lt;kbd&gt;윈도우 키&lt;/kbd&gt; + &lt;kbd&gt;R&lt;/kbd&gt;을 눌러 &quot;실행&quot;창을 띄웁니다. 그리고 &quot;cmd&quot; 또는 &quot;powershell&quot;을 입력하고 &quot;확인&quot; 버튼을 클릭합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9989B7455D8CC65A41&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9989B7455D8CC65A41&quot; width=&quot;700&quot; height=&quot;487&quot; alt=&quot;Cmd 또는 Powershell 실행&quot; filename=&quot;openjdk_execution_1.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;42-자바-실행-및-버전-확인&quot;&gt;4.2 자바 실행 및 버전 확인.&lt;/h4&gt;
&lt;p&gt;Cmd 또는 Powershell에서 &quot;java -version&quot; 명령을 실행하여 자바 실행 파일이 정상적으로 실행되는지 확인합니다. 특히, &quot;OpenJDK&quot;와 버전 정보가, 앞서 설치한 정보와 정확히 일치하는지 확인하는 것이 중요합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999D943A5D8CC65A30&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999D943A5D8CC65A30&quot; width=&quot;700&quot; height=&quot;220&quot; alt=&quot;자바 실행 및 버전 확인&quot; filename=&quot;openjdk_execution_2.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;5-완료&quot;&gt;5. 완료.&lt;/h3&gt;
&lt;p&gt;이제 OpenJDK를 설치하는 모든 과정이 완료되었습니다.&lt;/p&gt;
&lt;h3 id=&quot;6-참고&quot;&gt;6. 참고.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;OpenJDK 홈페이지.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;http://openjdk.java.net/&quot; title=&quot;http://openjdk.java.net&quot; rel=&quot;nofollow&quot;&gt;http://openjdk.java.net&lt;/a&gt;]의 내용을 확인하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JDK 홈페이지.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;http://openjdk.java.net/&quot; title=&quot;http://jdk.java.net/&quot; rel=&quot;nofollow&quot;&gt;http://jdk.java.net/&lt;/a&gt;]의 내용을 확인하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.END.&lt;/p&gt;&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>개발자 도구 및 서비스/JDK</category>
      <category>jdk 무료</category>
      <category>JDK 설치</category>
      <category>OpenJDK vs OracleJDK</category>
      <category>OpenJDK 다운로드</category>
      <category>openjdk 설치</category>
      <category>오라클 JDK</category>
      <category>오픈JDK</category>
      <category>윈도우 OpenJDK 설치</category>
      <category>자바 개발 환경</category>
      <author>뽀따</author>
      <guid isPermaLink="true">https://recipes4dev.tistory.com/173</guid>
      <comments>https://recipes4dev.tistory.com/173#entry173comment</comments>
      <pubDate>Thu, 26 Sep 2019 23:17:42 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드 스튜디오 설치하기. (Installing Android Studio on Windows OS)</title>
      <link>https://recipes4dev.tistory.com/53</link>
      <description>&lt;link rel=&quot;stylesheet&quot; href=&quot;https://tistory1.daumcdn.net/tistory/1573970/skin/images/style_gfm.css&quot; type=&quot;text/css&quot;&gt;

&lt;article class=&quot;madwin-body&quot;&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;1-안드로이드-스튜디오-android-studio&quot;&gt;1. 안드로이드 스튜디오 (Android Studio)&lt;/h3&gt;
&lt;p&gt;안드로이드 스튜디오는 안드로이드 앱 개발을 위한 공식적인(official) 통합 개발 환경(IDE, Integrated Development Environment)을 제공하는 소프트웨어입니다. JetBrains(&lt;a href=&quot;http://www.jetbrains.com&quot; rel=&quot;nofollow&quot;&gt;http://www.jetbrains.com&lt;/a&gt;)에서 만든 Java 개발을 위한 소프트웨어를 기반으로, 구글에서 만들어 배포하는 프로그램이죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;구글이 안드로이드 스튜디오를 공식 IDE로 제공하기 전에는 강력한 확장성을 자랑하는 Eclipse(&lt;a href=&quot;http://www.eclipse.org&quot; rel=&quot;nofollow&quot;&gt;http://www.eclipse.org&lt;/a&gt;)를 기반으로 앱 개발을 위한 환경을 제공하였습니다. 오픈 소스 프로젝트인 Eclipse 소프트웨어에 Plug-in형태로 ADT(Android Development Tools)를 설치하면 누구나 앱 개발을 할 수 있었습니다만, Eclipse 버전에 따른 ADT의 호환성 및 Eclipse 자체의 무거움 등의 단점이 있었죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;어쨌든 여러 이유로 구글이 안드로이드 스튜디오를 공식 IDE로 제공하게 되었고, Eclipse 개발 환경에 익숙해있던 개발자들도 이제는 거의 대부분 안드로이드 스튜디오를 사용해 안드로이드 앱을 개발하고 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그럼 지금부터, 안드로이드 앱 개발에 필요한 안드로이드 스튜디오를 설치하는 방법에 대해 설명하겠습니다. 참고로, 본문에서 설명하는 내용은 2019년 8월, 3.4.x 버전을 기준으로 정리되었습니다.&lt;/p&gt;
&lt;h3 id=&quot;2-안드로이드-스튜디오-다운로드&quot;&gt;2. 안드로이드 스튜디오 다운로드.&lt;/h3&gt;
&lt;p&gt;안드로이드 스튜디오는 안드로이드 개발자 페이지(&lt;a href=&quot;https://developer.android.com&quot; rel=&quot;nofollow&quot;&gt;https://developer.android.com&lt;/a&gt;)에서 다운로드 받을 수 있습니다.&lt;/p&gt;
&lt;h4 id=&quot;21-안드로이드-개발자-페이지-접속&quot;&gt;2.1 안드로이드 개발자 페이지 접속.&lt;/h4&gt;
&lt;p&gt;아래 그림과 같이 안드로이드 개발자 페이지(&lt;a href=&quot;https://developer.android.com&quot; rel=&quot;nofollow&quot;&gt;https://developer.android.com&lt;/a&gt;)에 접속한 다음, 페이지 상위의 &quot;Android Studio&quot; 메뉴를 선택합니다. (&quot;&lt;a href=&quot;https://developer.android.com/studio/&quot; rel=&quot;nofollow&quot;&gt;https://developer.android.com/studio/&lt;/a&gt;&quot; 페이지로 바로 접속해도 됩니다.)&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9954D83B5D56BBA922&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9954D83B5D56BBA922&quot; width=&quot;700&quot; height=&quot;493&quot; alt=&quot;안드로이드 개발자 페이지 접속&quot; filename=&quot;android_studio_download_1.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;22-안드로이드-스튜디오-다운로드&quot;&gt;2.2 안드로이드 스튜디오 다운로드.&lt;/h4&gt;
&lt;p&gt;화면 중앙의 &quot;DOWNLOAD ANDROID STUDIO&quot; 버튼을 선택합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D104335D56BBA91D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D104335D56BBA91D&quot; width=&quot;700&quot; height=&quot;493&quot; alt=&quot;안드로이드 스튜디오 다운로드&quot; filename=&quot;android_studio_download_2.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;23-사용-약관-동의-및-다운로드&quot;&gt;2.3 사용 약관 동의 및 다운로드.&lt;/h4&gt;
&lt;p&gt;이제 안드로이드 스튜디오 사용 약관 및 다운로드 화면이 표시됩니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B99F4C5D56BBA929&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B99F4C5D56BBA929&quot; width=&quot;700&quot; height=&quot;493&quot; alt=&quot;사용 약관 동의 및 다운로드&quot; filename=&quot;android_studio_download_3.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;안드로이드 스튜디오 사용 약관에 동의한 다음, &quot;ANDROID STUDIO FOR WINDOWS 다운로드&quot; 버튼을 클릭합니다.&lt;/p&gt;
&lt;h4 id=&quot;24-다운로드-진행&quot;&gt;2.4 다운로드 진행.&lt;/h4&gt;
&lt;p&gt;감사 인사 메시지 표시와 함께, 다운로드가 진행됩니다. 조금 기다리면, 다운로드가 완료됩니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9951AE4C5D56BBA91C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9951AE4C5D56BBA91C&quot; width=&quot;700&quot; height=&quot;493&quot; alt=&quot;안드로이드 스튜디오 다운로드 진행&quot; filename=&quot;android_studio_download_4.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;25-다운로드-완료&quot;&gt;2.5 다운로드 완료.&lt;/h4&gt;
&lt;p&gt;다운로드가 완료되고 다운로드 폴더로 이동해보면, &quot;android-studio-ide-183.5692245-windows.exe&quot; 파일이 저장된 것을 확인할 수 있습니다. (설치 프로그램 릴리즈 시점에 따라 파일 이름은 다를 수 있습니다.)&lt;/p&gt;
&lt;h3 id=&quot;3-안드로이드-스튜디오-설치&quot;&gt;3. 안드로이드 스튜디오 설치.&lt;/h3&gt;
&lt;h4 id=&quot;31-설치-파일-실행&quot;&gt;3.1 설치 파일 실행.&lt;/h4&gt;
&lt;p&gt;다운로드한 설치 파일을 실행하면 잠시 동안 설치 로딩 화면이 출력됩니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993230445D56BBA90D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993230445D56BBA90D&quot; width=&quot;700&quot; height=&quot;144&quot; alt=&quot;안드로이드 스튜디오 설치 로딩&quot; filename=&quot;android_studio_install_1.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;32-설치-환영-메시지&quot;&gt;3.2 설치 환영 메시지.&lt;/h4&gt;
&lt;p&gt;로딩이 완료되면 설치 환영 페이지가 표시됩니다. &quot;Next&quot; 버튼을 눌러 다음 단계로 진행합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99290D365D56BBA903&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99290D365D56BBA903&quot; width=&quot;700&quot; height=&quot;459&quot; alt=&quot;안드로이드 스튜디오 설치 환영 페이지&quot; filename=&quot;android_studio_install_2.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;33-구성-요소-선택&quot;&gt;3.3 구성 요소 선택.&lt;/h4&gt;
&lt;p&gt;안드로이드 스튜디오 설치 시 포함될 구성 요소를 선택하는 단계입니다. 모든 항목을 체크하고, &quot;Next&quot; 버튼을 클릭합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/990F25475D56BBA922&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F990F25475D56BBA922&quot; width=&quot;700&quot; height=&quot;459&quot; alt=&quot;안드로이드 스튜디오 구성 요소 선택&quot; filename=&quot;android_studio_install_3.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;34-설치-경로-지정&quot;&gt;3.4 설치 경로 지정.&lt;/h4&gt;
&lt;p&gt;안드로이드 스튜디오가 설치될 경로를 지정합니다. &quot;Next&quot; 버튼을 클릭하여 다음 단계로 넘어갑니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993840425D56BBA90E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993840425D56BBA90E&quot; width=&quot;700&quot; height=&quot;459&quot; alt=&quot;안드로이드 스튜디오 설치 경로 지정&quot; filename=&quot;android_studio_install_4.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;35-시작-메뉴-폴더-입력&quot;&gt;3.5 시작 메뉴 폴더 입력&lt;/h4&gt;
&lt;p&gt;시작 메뉴에 표시될 폴더 이름을 입력합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99CB42505D56BBA923&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99CB42505D56BBA923&quot; width=&quot;700&quot; height=&quot;459&quot; alt=&quot;시작 메뉴 폴더 입력&quot; filename=&quot;android_studio_install_5.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&quot;Install&quot; 버튼을 누르면 설치가 시작됩니다.&lt;/p&gt;
&lt;h4 id=&quot;36-설치-진행&quot;&gt;3.6 설치 진행.&lt;/h4&gt;
&lt;p&gt;설치 진행 과정이 표시됩니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BD0D3C5D56BBA92D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BD0D3C5D56BBA92D&quot; width=&quot;700&quot; height=&quot;459&quot; alt=&quot;안드로이드 스튜디오 설치 진행&quot; filename=&quot;android_studio_install_6.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;37-설치-완료&quot;&gt;3.7 설치 완료.&lt;/h4&gt;
&lt;p&gt;설치가 완료되었다는 메시지가 표시됩니다. &quot;Next&quot; 버튼을 클릭하여 설치 과정의 마지막 단계로 넘어갑니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99ECC23E5D56BBA91A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99ECC23E5D56BBA91A&quot; width=&quot;700&quot; height=&quot;459&quot; alt=&quot;안드로이드 스튜디오 설치 완료&quot; filename=&quot;android_studio_install_7.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;38-설치-종료&quot;&gt;3.8 설치 종료&lt;/h4&gt;
&lt;p&gt;설치 과정 중 마지막 단계입니다. &quot;Start Android Studio&quot; 체크 박스를 선택 한 후 Finish&quot; 버튼을 클릭하여 설치 과정을 종료합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E365495D56BBA925&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E365495D56BBA925&quot; width=&quot;700&quot; height=&quot;459&quot; alt=&quot;안드로이드 스튜디오 설치 종료&quot; filename=&quot;android_studio_install_8.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;4-실행-확인-및-개발-환경-설정&quot;&gt;4. 실행 확인 및 개발 환경 설정.&lt;/h3&gt;
&lt;h4 id=&quot;41-안드로이드-스튜디오-실행&quot;&gt;4.1 안드로이드 스튜디오 실행.&lt;/h4&gt;
&lt;p&gt;안드로이드 스튜디오 아이콘을 더블 클릭하여 안드로이드 스튜디오를 실행합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9963553E5D56BBA91D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9963553E5D56BBA91D&quot; width=&quot;700&quot; height=&quot;169&quot; alt=&quot;안드로이드 스튜디오 실행&quot; filename=&quot;android_studio_execute_1.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;42-안드로이드-설정-읽어오기&quot;&gt;4.2 안드로이드 설정 읽어오기&lt;/h4&gt;
&lt;p&gt;안드로이드 스튜디오를 처음 실행하면, 기존 설정 정보를 읽어들일 것인지 여부를 지정할 수 있습니다. 기존에 설치했던 안드로이드 스튜디오의 설정 정보를 import하거나, 초기 상태로 실행되도록 만들 수 있습니다. 일단, &quot;Do not import settings&quot;를 선택하여, 기존 설정 정보 import 없이 실행합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999B7E4D5D56BBA922&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999B7E4D5D56BBA922&quot; width=&quot;700&quot; height=&quot;233&quot; alt=&quot;안드로이드 스튜디오 설정 import&quot; filename=&quot;android_studio_execute_2.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이 단계에서 &quot;사용 데이터 공유&quot; 여부에 대한 설정 대화상자가 표시되는데요, 어떤 선택을 하더라도 안드로이드 스튜디오 사용에는 영향을 미치지 않으므로 결정에 따라 선택하면 됩니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99AF80495D56BBA917&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99AF80495D56BBA917&quot; width=&quot;700&quot; height=&quot;321&quot; alt=&quot;사용 데이터 공유&quot; filename=&quot;android_studio_execute_3.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;43-개발-환경-설정-마법사&quot;&gt;4.3 개발 환경 설정 마법사&lt;/h4&gt;
&lt;p&gt;앞 단계에서 기존 설정 정보를 import하지 않았으므로, 개발 환경 설정을 위한 설정 마법사가 실행됩니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A9374B5D56BBA922&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A9374B5D56BBA922&quot; width=&quot;700&quot; height=&quot;515&quot; alt=&quot;안드로이드 스튜디오 개발 환경 설정 마법사&quot; filename=&quot;android_studio_execute_4.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&quot;Next&quot; 버튼을 클릭하여 다음 단계로 진행합니다.&lt;/p&gt;
&lt;h4 id=&quot;44-개발-환경-설정-방식-결정&quot;&gt;4.4 개발 환경 설정 방식 결정.&lt;/h4&gt;
&lt;p&gt;안드로이드 스튜디오에서 추천하는 표준(Standard) 방식으로 설정할 것인지, 개발자 맞춤(Custom) 방식으로 설정할 것인지 결정하는 단계입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993943455D56BBA91D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993943455D56BBA91D&quot; width=&quot;700&quot; height=&quot;515&quot; alt=&quot;안드로이드 스튜디오 개발 환경 설정 방식 결정&quot; filename=&quot;android_studio_execute_5.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&quot;Standard&quot;를 선택하고, &quot;Next&quot; 버튼을 클릭합니다.&lt;/p&gt;
&lt;h4 id=&quot;45-ui-테마-설정&quot;&gt;4.5 UI 테마 설정.&lt;/h4&gt;
&lt;p&gt;안드로이드 스튜디오 UI 테마를 설정하는 화면입니다. 어두운 계열(Darcula)과 밝은 계열(IntelliJ) 테마가 있는데, 취향에 따라 선택하면 됩니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992186375D56BBA929&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992186375D56BBA929&quot; width=&quot;700&quot; height=&quot;515&quot; alt=&quot;안드로이드 스튜디오 UI 테마 설정&quot; filename=&quot;android_studio_execute_6.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&quot;Next&quot; 버튼을 클릭합니다.&lt;/p&gt;
&lt;h4 id=&quot;46-선택-사항-확인&quot;&gt;4.6 선택 사항 확인.&lt;/h4&gt;
&lt;p&gt;이제 마지막으로, 앞선 단계들에서 선택한 내용들을 확인하는 단계입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C7A2365D56BBA905&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C7A2365D56BBA905&quot; width=&quot;700&quot; height=&quot;515&quot; alt=&quot;안드로이드 스튜디오 선택 사항 확인&quot; filename=&quot;android_studio_execute_7.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&quot;Finish&quot; 버튼을 클릭하여, 설치를 진행합니다.&lt;/p&gt;
&lt;h4 id=&quot;47-구성요소-설치&quot;&gt;4.7 구성요소 설치.&lt;/h4&gt;
&lt;p&gt;앞서 선택한 설정에 따라 구성요소들의 다운로드를 진행합니다. (네트워크 상황에 따라 몇 분 또는 몇 십분 정도 소요됩니다.)&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9947E54A5D56BBA91C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9947E54A5D56BBA91C&quot; width=&quot;700&quot; height=&quot;515&quot; alt=&quot;구성요소 설치 진행&quot; filename=&quot;android_studio_execute_8.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;48-구성요소-설치-완료&quot;&gt;4.8 구성요소 설치 완료.&lt;/h4&gt;
&lt;p&gt;모든 설치가 완료되면, 로그 메시지와 함께 &quot;Finish&quot; 버튼이 표시됩니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9960173D5D56BBA919&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9960173D5D56BBA919&quot; width=&quot;700&quot; height=&quot;515&quot; alt=&quot;구성요소 설치 완료&quot; filename=&quot;android_studio_execute_9.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&quot;Finish&quot; 버튼을 클릭하면 모든 설치 과정이 완료됩니다.&lt;/p&gt;
&lt;h4 id=&quot;410-안드로이드-스튜디오-개발-준비-완료&quot;&gt;4.10 안드로이드 스튜디오 개발 준비 완료.&lt;/h4&gt;
&lt;p&gt;이제 개발에 필요한 기본적인 준비가 완료되었습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991FC1425D56BBA90F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991FC1425D56BBA90F&quot; width=&quot;700&quot; height=&quot;515&quot; alt=&quot;안드로이드 스튜디오 개발 준비 완료&quot; filename=&quot;android_studio_execute_10.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;5-참고&quot;&gt;5. 참고.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;윈도우 운영체제에 JDK 설치하기
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;http://recipes4dev.tistory.com/50&quot; title=&quot;윈도우 운영체제에 JDK 설치하기&quot; rel=&quot;nofollow&quot;&gt;윈도우 운영체제에 JDK 설치하기&lt;/a&gt;]의 내용을 확인하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;안드로이드 스튜디오 홈페이지
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;http://developer.android.com/intl/ko/sdk/index.html&quot; title=&quot;안드로이드 개발 도구 도움말&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 도구 도움말&lt;/a&gt;]의 내용을 확인하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.END.&lt;/p&gt;&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>ANDROID 스튜디오/준비 및 설치</category>
      <category>Android</category>
      <category>Android Studio</category>
      <category>AndroidStudio 설치</category>
      <category>install</category>
      <category>studio</category>
      <category>windows</category>
      <category>설치</category>
      <category>스튜디오</category>
      <category>안드로이드</category>
      <category>안드로이드 개발 환경</category>
      <category>안드로이드 스튜디오</category>
      <category>안드로이드 스튜디오 설치</category>
      <category>안드로이드스튜디오</category>
      <category>윈도우</category>
      <category>인ㄷ</category>
      <author>뽀따</author>
      <guid isPermaLink="true">https://recipes4dev.tistory.com/53</guid>
      <comments>https://recipes4dev.tistory.com/53#entry53comment</comments>
      <pubDate>Fri, 16 Aug 2019 23:27:25 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드 runOnUiThread() 메서드. (Android runOnUiThread() Method)</title>
      <link>https://recipes4dev.tistory.com/172</link>
      <description>&lt;link rel=&quot;stylesheet&quot; href=&quot;https://tistory1.daumcdn.net/tistory/1573970/skin/images/style_gfm.css&quot; type=&quot;text/css&quot;&gt;

&lt;article class=&quot;madwin-body&quot;&gt;&lt;p&gt;&lt;br /&gt;

&lt;/p&gt;&lt;h3 id=&quot;1-안드로이드-핸들러-android-handler&quot;&gt;1. 안드로이드 핸들러. (Android Handler)&lt;/h3&gt;
&lt;p&gt;지난 글 [&lt;a href=&quot;https://recipes4dev.tistory.com/170&quot; title=&quot;[https://recipes4dev.tistory.com/170] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드 통신. 핸들러와 Runnable. (Android Thread Communication. Handler and Runnable.)&lt;/a&gt;]에서, 핸들러를 통해 &lt;code&gt;Runnable&lt;/code&gt; 객체를 보내고, 객체에 담긴 &lt;code&gt;run()&lt;/code&gt; 메서드가 수신 스레드에서 실행되는 과정을 살펴보았습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;Runnable&lt;/code&gt; 객체와 핸들러를 사용하여 스레드 통신을 수행하는 방법은, &lt;code&gt;Message&lt;/code&gt; 객체를 사용할 때 요구되었던 메시지 식별 코드(what)나 파라미터(arg1, arg2), 또는 데이터 객체(obj)를 관리해야하는 번거로움을 덜어 줍니다. 그리고 핸들러의 &lt;code&gt;handleMessage()&lt;/code&gt; 메서드를 작성하는 수고도 줄일 수 있어서, 비교적 간단하게 스레드 간 통신 수행할 수 있게 해줍니다. 물론 &lt;code&gt;handlerMessage()&lt;/code&gt;에 들어갈 코드가 &lt;code&gt;Runnable&lt;/code&gt;의 &lt;code&gt;run()&lt;/code&gt; 메서드에 일부 포함되어야 하는 건 어쩔 수 없긴 하지만 말이죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그런데 여기서, 한번 짚고 넘어가고 싶은 내용이 있습니다. 바로, 핸들러를 사용한 스레드 통신이 &quot;어떤 상황에 가장 많이 사용되는가&quot;라는 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;안드로이드 앱을 만들 때, 가장 조심스럽게 다루어져야 하는 스레드는 메인 스레드(Main Thread)입니다. [&lt;a href=&quot;https://recipes4dev.tistory.com/143#3-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%95%B1%EC%9D%98-%EB%A9%94%EC%9D%B8-%EC%8A%A4%EB%A0%88%EB%93%9Cmain-thread&quot; title=&quot;[https://recipes4dev.tistory.com/143#3-안드로이드-앱의-메인-스레드main-thread] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드(Android Thread) - 3. 안드로이드 앱의 메인 스레드(Main Thread)&lt;/a&gt;]에서 설명했듯이, 안드로이드 앱의 시작점이자, 사용자 입력과 UI를 책임지는 스레드, 바로 메인 스레드죠. 그래서 앱이 실행될 때 메인 스레드와 병행적으로 처리되어야 하는 작업들은 새로운 스레드에서 실행하고, 그 결과(또는 코드)를 핸들러를 통해 메인 스레드로 전달한 다음 화면에 반영하는 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;자, 이제 &quot;핸들러를 통한 스레드 통신이 가장 많이 사용되는 경우&quot;가 예상되나요? 바로 &lt;strong&gt;새로운 스레드에서 실행된 결과를 메인 스레드를 통해 화면에 표시하고자 할 때&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;h3 id=&quot;2-핸들러handler와-runnable-되짚어보기&quot;&gt;2. 핸들러(Handler)와 Runnable 되짚어보기.&lt;/h3&gt;
&lt;p&gt;핸들러를 통해 &lt;code&gt;Runnable&lt;/code&gt; 객체를 보내는 과정을 다시 한번 정리해보겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;수신 측 스레드에서 핸들러 객체를 생성.&lt;/li&gt;
&lt;li&gt;송신 측 스레드에서 &lt;code&gt;Runnable&lt;/code&gt; 객체 생성 및 run() 메서드 구현.&lt;/li&gt;
&lt;li&gt;Handler.post() 메서드를 통해 &lt;code&gt;Runnable&lt;/code&gt; 객체를 전달.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;비교적 간단한 절차를 통해 &lt;code&gt;Runnable&lt;/code&gt; 객체를 보낼 수 있다는 것을 확인할 수 있는데요. 이 절차에서, 코드 작성의 수고를 조금이라도 줄일 수 있는 방법을 한번 고민해 보죠. 특히, &lt;code&gt;Runnable&lt;/code&gt; 객체의 수신 스레드가 UI를 관리하는 메인 스레드이고, 핸들러에 대한 참조를 &lt;code&gt;Activity&lt;/code&gt;가 가지는 경우를 말입니다.&lt;/p&gt;
&lt;h4 id=&quot;21-액티비티에서-runnable-수신하는-경우&quot;&gt;2.1 액티비티에서 Runnable 수신하는 경우.&lt;/h4&gt;
&lt;p&gt;앞에서, 핸들러를 통한 스레드 통신이 가장 많이 사용되는 경우가 &quot;스레드 실행 결과를 화면에 표시하고자 할 때&quot;라고 언급했습니다. 그래서 화면 구성의 가장 기본이 되는 요소인 액티비티에서 핸들러 객체를 생성하게 되는데요.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그렇다면, &lt;code&gt;Runnable&lt;/code&gt; 객체를 보낼 때마다 핸들러 객체를 새로 만들지 말고, 액비비티가 기본적으로 가지고 있는 핸들러를 사용하면 되지 않을까요? 그리고 그 핸들러를 통해 post() 메서드를 호출하게 만들면, 직접 Handler.post() 메서드를 호출하는 수고를 줄일 수 있을 것입니다. 그리고 이러한 작업을, 액티비티에 새로운 메서드를 추가해서 구현하면 되겠네요.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아참, &lt;code&gt;Runnable&lt;/code&gt; 객체를, 다른 스레드가 아닌 메인 스레드 자신이 보낼 수도 있으니깐, 이 때는 불필요하게 &lt;code&gt;post()&lt;/code&gt; 메서드를 호출하지 말고, 그냥 &lt;code&gt;Runnable&lt;/code&gt; 객체에 구현된 &lt;code&gt;run()&lt;/code&gt; 메서드를 바로 실행하도록 만드는 게 더 좋겠네요. 아래와 같이, pseudo-code로 구현해본 sendRunnable() 메서드처럼 말이죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;MainActivity&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; ... {

    &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;sendRunnable&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;Runnable&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;r&lt;/span&gt;) {
        &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; (메서드가 새로운 스레드에서 실행된다면) {
            핸들러의 post() 메서드를 통해 r 전달&lt;span class=&quot;pl-c1&quot;&gt;.&lt;/span&gt;
        } &lt;span class=&quot;pl-k&quot;&gt;else&lt;/span&gt; {
            r&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;run() 실행&lt;span class=&quot;pl-c1&quot;&gt;.&lt;/span&gt;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;자, 어떤가요? 위에서 액티비티에 sendRunnable() 메서드를 구현해놓았으니, 앞으로 매번 핸들러를 만들고 &lt;code&gt;post()&lt;/code&gt; 메서드를 호출할 필요가 없습니다. 그냥 전달할 &lt;code&gt;Runnable&lt;/code&gt; 객체를 sendRunnable() 메서드로 넘기기만 하면 되는 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;    sendRunnable(&lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Runnable&lt;/span&gt;() {
        &lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;run&lt;/span&gt;() {
            &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; TODO.&lt;/span&gt;
        }
    }) ;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;음, 그런데 잠깐, 왠지 이런 작업을 하는 메서드가 &lt;code&gt;Activity&lt;/code&gt; 클래스에 이미 만들어져 있을 것 같은데요?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;네. 바로 &lt;strong&gt;runOnUiThread()&lt;/strong&gt; 입니다.&lt;/p&gt;
&lt;h3 id=&quot;3-액티비티의-runonuithread-메서드&quot;&gt;3. 액티비티의 runOnUiThread() 메서드.&lt;/h3&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9922234F5D2347EA20&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9922234F5D2347EA20&quot; width=&quot;700&quot; height=&quot;182&quot; alt=&quot;액티비티의 runOnUiThread() 메서드&quot; filename=&quot;thread_runOnUiThread_runOnUiThread_method.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;runOnUiThread()&lt;/code&gt; 메서드는 &lt;code&gt;Activity&lt;/code&gt; 클래스에서 제공되는 메서드입니다. 앞에서 임의로 만들어본, sendRunnable() 메서드의 기능이 고스란히 구현된 메서드입니다. 즉, 개발자가 만든 &lt;code&gt;Runnable&lt;/code&gt; 객체를 메인 스레드에서 실행되도록 만드는 메서드인데, 현재 스레드가 메인 스레드인지 여부를 검사하여 메인 스레드가 아니라면 &lt;code&gt;post()&lt;/code&gt; 메서드를 실행하고, 메인 스레드라면 &lt;code&gt;Runnable&lt;/code&gt;의 &lt;code&gt;run()&lt;/code&gt; 메서드를 직접 실행합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;runOnUiThread()&lt;/code&gt; 메서드는 아래와 같이 간단하게 구현되어 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;b&gt;runOnUiThread&lt;/b&gt;(&lt;span class=&quot;pl-smi&quot;&gt;Runnable&lt;/span&gt; action) {
        &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;pl-smi&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;currentThread() &lt;span class=&quot;pl-k&quot;&gt;!=&lt;/span&gt; mUiThread) {
            mHandler&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;post(action);
        } &lt;span class=&quot;pl-k&quot;&gt;else&lt;/span&gt; {
            action&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;run();
        }
    }&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;runOnUiThread()&lt;/code&gt; 메서드를 한 문장으로 요약하자면, &lt;b&gt;&quot;&lt;/b&gt;&lt;b&gt;Runnable 객체에 구현된 코드를 반드시 메인 스레드에서 실행해야 할 때 사용하는 메서드&quot;&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h3 id=&quot;4-runonuithread-사용-예제&quot;&gt;4. runOnUiThread() 사용 예제.&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;runOnUiThread()&lt;/code&gt; 메서드에 대해 알아보았으니, 예제를 통해 &lt;code&gt;runOnUiThread()&lt;/code&gt; 메서드를 어떻게 사용하는지 알아보겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;작성할 예제는 [&lt;a href=&quot;https://recipes4dev.tistory.com/150#5-%EC%8A%A4%EB%A0%88%EB%93%9C-%EC%A0%81%EC%9A%A9-%EC%8A%A4%EB%A0%88%EB%93%9C-%EA%B0%84-%ED%86%B5%EC%8B%A0-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0&quot; title=&quot;[https://recipes4dev.tistory.com/150#5-스레드-적용-스레드-간-통신-적용하기] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드 예제. 스레드로 고민해보기. (Android Thread UseCase) - 5. 스레드 적용. 스레드 간 통신 적용하기.&lt;/a&gt;]와 [&lt;a href=&quot;https://recipes4dev.tistory.com/170#4-%ED%95%B8%EB%93%A4%EB%9F%AChandler%EC%99%80-runnable%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%86%B5%EC%8B%A0-%EC%98%88%EC%A0%9C&quot; title=&quot;[https://recipes4dev.tistory.com/170#4-핸들러handler와-runnable을-사용한-스레드-통신-예제] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드 통신. 핸들러와 Runnable - 4. 핸들러(handler)와 Runnable을 사용한 스레드 통신 예제&lt;/a&gt;]에서 작성했던 &quot;디지털 시계&quot; 예제와 동일합니다.&lt;/p&gt;
&lt;h4 id=&quot;41-메인액티비티-레이아웃-작성&quot;&gt;4.1 메인액티비티 레이아웃 작성.&lt;/h4&gt;
&lt;p&gt;메인액티비티 화면에는 아래 그림과 같이 화면 가운데 현재 시각을 표시할 수 있는 텍스트뷰를 배치합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-1] 메인액티비티 레이아웃 작성.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-xml&quot;&gt;&lt;pre&gt;&amp;lt;?&lt;span class=&quot;pl-ent&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt; version&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;1.0&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt; encoding&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;utf-8&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;?&amp;gt;
&amp;lt;&lt;span class=&quot;pl-ent&quot;&gt;android&lt;/span&gt;.support.constraint.ConstraintLayout &lt;span class=&quot;pl-e&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;http://schemas.android.com/apk/res/android&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;http://schemas.android.com/apk/res-auto&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;tools&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;http://schemas.android.com/tools&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_width&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;match_parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_height&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;match_parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_behavior&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@string/appbar_scrolling_view_behavior&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;context&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;.MainActivity&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;showIn&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@layout/activity_main&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;

    &lt;b&gt;&amp;lt;&lt;span class=&quot;pl-ent&quot;&gt;TextView&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_width&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;wrap_content&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_height&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;wrap_content&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;textSize&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;48sp&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;text&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;00:00:00&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@+id/clock&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintBottom_toBottomOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintLeft_toLeftOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintRight_toRightOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintTop_toTopOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; /&amp;gt;&lt;/b&gt;

&amp;lt;/&lt;span class=&quot;pl-ent&quot;&gt;android&lt;/span&gt;.support.constraint.ConstraintLayout&amp;gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;42-runonuithread-메서드로-runnable-객체-전달-기능-구현&quot;&gt;4.2 runOnUiThread() 메서드로 Runnable 객체 전달 기능 구현.&lt;/h4&gt;
&lt;p&gt;자, 이제 &lt;code&gt;Runnable&lt;/code&gt; 객체의 &lt;code&gt;run()&lt;/code&gt; 메서드에 현재 시각을 표시하는 코드를 작성하고, 해당 &lt;code&gt;Runnable&lt;/code&gt; 객체를 &lt;code&gt;runOnUiThread()&lt;/code&gt; 메서드에 전달하는 코드를 작성합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-2] Runnable 객체에 현재 시각 갱신 코드 작성 후, 메인 스레드로 전달.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;MainActivity&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;AppCompatActivity&lt;/span&gt; {

    &lt;span class=&quot;pl-smi&quot; style=&quot;&quot;&gt;TextView&lt;/span&gt; clockTextView ;

    &lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onCreate&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;Bundle&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;savedInstanceState&lt;/span&gt;) {
        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; ... 코드 계속.&lt;/span&gt;

        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; 핸들러로 전달할 runnable 객체. 수신 스레드 실행.&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;pl-smi&quot; style=&quot;&quot;&gt;Runnable&lt;/span&gt; runnable &lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot; style=&quot;&quot;&gt;Runnable&lt;/span&gt;() {
            &lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot; style=&quot;&quot;&gt;run&lt;/span&gt;() {
                &lt;span class=&quot;pl-smi&quot; style=&quot;&quot;&gt;Calendar&lt;/span&gt; cal &lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot; style=&quot;&quot;&gt;Calendar&lt;/span&gt;&lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;.&lt;/span&gt;getInstance();

                &lt;span class=&quot;pl-smi&quot; style=&quot;&quot;&gt;SimpleDateFormat&lt;/span&gt; sdf &lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot; style=&quot;&quot;&gt;SimpleDateFormat&lt;/span&gt;(&lt;span class=&quot;pl-s&quot; style=&quot;&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;HH:mm:ss&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;);
                &lt;span class=&quot;pl-smi&quot; style=&quot;&quot;&gt;String&lt;/span&gt; strTime &lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;=&lt;/span&gt; sdf&lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;.&lt;/span&gt;format(cal&lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;.&lt;/span&gt;getTime());

                clockTextView &lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;=&lt;/span&gt; findViewById(&lt;span class=&quot;pl-smi&quot; style=&quot;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;.&lt;/span&gt;clock);
                clockTextView&lt;span class=&quot;pl-k&quot; style=&quot;&quot;&gt;.&lt;/span&gt;setText(strTime);
            }
        } ;

        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; 새로운 스레드 실행 코드. 1초 단위로 현재 시각 표시 요청.&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;NewRunnable&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;Runnable&lt;/span&gt; {
            &lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;run&lt;/span&gt;() {
                &lt;span class=&quot;pl-k&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;) {

                    &lt;span class=&quot;pl-k&quot;&gt;try&lt;/span&gt; {
                        &lt;span class=&quot;pl-smi&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;sleep(&lt;span class=&quot;pl-c1&quot;&gt;1000&lt;/span&gt;);
                    } &lt;span class=&quot;pl-k&quot;&gt;catch&lt;/span&gt; (&lt;span class=&quot;pl-smi&quot;&gt;Exception&lt;/span&gt; e) {
                        e&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;printStackTrace() ;
                    }

                    &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; 메인 스레드에 runnable 전달.&lt;/span&gt;
                    &lt;b&gt;runOnUiThread(runnable) ;&lt;/b&gt;
                }
            }
        }

        &lt;span class=&quot;pl-smi&quot;&gt;NewRunnable&lt;/span&gt; nr &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;NewRunnable&lt;/span&gt;() ;
        &lt;span class=&quot;pl-smi&quot;&gt;Thread&lt;/span&gt; t &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Thread&lt;/span&gt;(nr) ;
        t&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;start() ;
    }
}&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;43-실행-결과&quot;&gt;4.3 실행 결과.&lt;/h4&gt;
&lt;p&gt;예제 작성을 완료하고 실행하면, 현재 시각이 1초마다 갱신되는 것을 확인할 수 있습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F8B5365D2347EA22&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F8B5365D2347EA22&quot; width=&quot;700&quot; height=&quot;437&quot; filename=&quot;thread_runOnUiThread_example_screenshot.png&quot; filemime=&quot;image/png&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;5-참고&quot;&gt;5. 참고.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;개발자 레시피 - 스레드 관련 항목.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/143&quot; title=&quot;[https://recipes4dev.tistory.com/143] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드(Android Thread)&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/150&quot; title=&quot;[https://recipes4dev.tistory.com/150] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드 예제. 스레드로 고민해보기. (Android Thread UseCase)&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/166&quot; title=&quot;[https://recipes4dev.tistory.com/166] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드. 핸들러와 메시지. (Android Thread. Handler and Message.)&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/170&quot; title=&quot;[https://recipes4dev.tistory.com/170] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드. 핸들러와 Runnable. (Android Thread. Handler and Runnable.)&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;runOnUiThread에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/app/Activity#runOnUiThread(java.lang.Runnable)&quot; title=&quot;[https://developer.android.com/reference/android/app/Activity#runOnUiThread(java.lang.Runnable)] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Activity.runOnUiThread&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;UI 스레드와 통신하기.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/training/multiple-threads/communicate-ui&quot; title=&quot;[https://developer.android.com/training/multiple-threads/communicate-ui] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 가이드. Communicate with the UI thread&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Thread에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/java/lang/Thread.html&quot; title=&quot;[https://developer.android.com/reference/java/lang/Thread.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Thread&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Runnable에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/java/lang/Runnable.html&quot; title=&quot;[https://developer.android.com/reference/java/lang/Runnable.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Runnable&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Looper에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/Looper.html&quot; title=&quot;[https://developer.android.com/reference/android/os/Looper.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Looper&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Handler에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/Handler.html&quot; title=&quot;[https://developer.android.com/reference/android/os/Handler.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Handler&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Message에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/Message.html&quot; title=&quot;[https://developer.android.com/reference/android/os/Message.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Message&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MessageQueue에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/MessageQueue.html&quot; title=&quot;[https://developer.android.com/reference/android/os/MessageQueue.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. MessageQueue&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.END.&lt;/p&gt;&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>ANDROID 프로그래밍/THREAD</category>
      <category>Activity runOnUiThread</category>
      <category>runOnUiThread</category>
      <category>runOnUiThread 메서드</category>
      <author>뽀따</author>
      <guid isPermaLink="true">https://recipes4dev.tistory.com/172</guid>
      <comments>https://recipes4dev.tistory.com/172#entry172comment</comments>
      <pubDate>Mon, 8 Jul 2019 22:49:11 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 awk 명령어 사용법. (Linux awk command) - 리눅스 파일 텍스트 데이터 검사, 조작, 출력.</title>
      <link>https://recipes4dev.tistory.com/171</link>
      <description>&lt;article class=&quot;madwin-body&quot;&gt;&lt;p&gt;&lt;br /&gt;

&lt;/p&gt;&lt;h3 id=&quot;1-awk-명령어&quot;&gt;1. awk 명령어.&lt;/h3&gt;
&lt;p&gt;대부분의 리눅스 명령들이, 그 명령의 이름만으로 대략적인 기능이 예상되는 것과 다르게, awk 명령은 이름에 그 기능을 의미하는 단어나 약어가 포함되어 있지 않습니다. awk는 최초에 awk 기능을 디자인한 사람들의 이니셜을 조합하여 만든 이름이기 때문입니다. &lt;b&gt;A&lt;/b&gt;ho + &lt;b&gt;W&lt;/b&gt;einberger + &lt;b&gt;K&lt;/b&gt;ernighan. (A:Alfred V. Aho, W:Peter J. Weinberger, K:Brian W. Kernighan)&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display:inline-block;width:700px;;height:auto;max-width:100%&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B8F3425D1CBC7B1F&quot; style=&quot;max-width:100%;height:auto&quot; width=&quot;700&quot; height=&quot;126&quot; alt=&quot;리눅스 awk 명령어&quot; filename=&quot;linux_cmd_awk_awk.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;awk&lt;/strong&gt;는 파일로부터 레코드(record)를 선택하고, 선택된 레코드에 포함된 값을 조작하거나 데이터화하는 것을 목적으로 사용하는 프로그램입니다. 즉, awk 명령의 입력으로 지정된 파일로부터 데이터를 분류한 다음, 분류된 텍스트 데이터를 바탕으로 패턴 매칭 여부를 검사하거나 데이터 조작 및 연산 등의 액션을 수행하고, 그 결과를 출력하는 기능을 수행합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;awk에 대한 설명이 잘 이해되시나요? 패턴, 분류, 텍스트, 조작, 연산, 액션. 뭔가 복잡한 작업을 하는 프로그램인 것은 맞는 것 같은데, 구체적으로 어떤 기능을 수행하는지, 어떤 목적을 위해 사용해야 하는지 쉽게 떠오르지 않네요. awk를 어떻게 사용해야 하는지도...&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;자, 그러면, 구체적인 동작 방식과 사용법을 알아보기에 앞서, awk 명령으로 할 수 있는 일들을 간단히 나열해 보겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;텍스트 파일의 전체 내용 출력.&lt;/li&gt;
&lt;li&gt;파일의 특정 필드만 출력.&lt;/li&gt;
&lt;li&gt;특정 필드에 문자열을 추가해서 출력.&lt;/li&gt;
&lt;li&gt;패턴이 포함된 레코드 출력.&lt;/li&gt;
&lt;li&gt;특정 필드에 연산 수행 결과 출력.&lt;/li&gt;
&lt;li&gt;필드 값 비교에 따라 레코드 출력.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display:inline-block;width:700px;;height:auto;max-width:100%&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C761465D1CBF9B28&quot; style=&quot;max-width:100%;height:auto&quot; width=&quot;700&quot; height=&quot;424&quot; alt=&quot;awk 명령 사용 예&quot; filename=&quot;linux_cmd_awk_use_case.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;awk로 할 수 있는 작업 중에서, 가장 단순하고 기본적인 몇 개의 예제만 소개해봤는데, awk 명령의 사용 목적이 조금은 이해되시나요? awk 명령에 대한 설명과 소개된 예제를 보면 awk가 어떻게 동작하는지 어느 정도 감을 잡으셨을거라 생각합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;awk의 기본 동작 방식 자체는 매우 단순합니다. 입력 데이터로부터 주어진 패턴을 포함하는 라인을 찾기 위해 파일의 내용을 탐색한 다음, 패턴에 일치하는 라인이 발견되면 해당 라인에 대해 지정된 액션을 실행합니다. 그리고 이 과정을 입력 파일의 끝을 만날 때까지 수행합니다. 개념은 단순하죠? 하지만 실질적인 사용법은 꽤 복잡합니다. 이유는 바로, awk가 실행하는 기능(패턴 매칭과 액션 실행) 들이 &quot;프로그래밍 언어&quot;로 작성되기 때문입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;awk는 &quot;&lt;b&gt;awk programming language&lt;/b&gt;&quot;라는 프로그래밍 언어로 작성된 프로그램을 실행합니다. 리눅스에서 쉘 스크립트(Shell Script)로 작성된 파일이 리눅스 쉘(Shell)에 의해 실행되는 것을 떠올리면, awk가 &quot;awk programming language&quot; 문법으로 작성된 코드를 실행한다는 것의 의미가 쉽게 이해되죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;awk는 기본적으로 입력 데이터를 라인(line) 단위의 &lt;b&gt;레코드(Record)&lt;/b&gt;로 인식합니다. 그리고 각 레코드에 들어 있는 텍스트는 공백 문자(space, tab)로 구분된 &lt;b&gt;필드(Field)&lt;/b&gt;들로 분류되는데요. 이렇게 식별된 레코드 및 필드의 값들은 awk 프로그램에 의해 패턴 매칭 및 다양한 액션의 파라미터로 사용됩니다. (참고로, 레코드 구분 문자(newline)와 필드 구분 문자(space, tab)는 awk 프로그램 옵션으로 변경할 수 있습니다.)&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display:inline-block;width:700px;;height:auto;max-width:100%&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998C54465D1CBC7B16&quot; style=&quot;max-width:100%;height:auto&quot; width=&quot;700&quot; height=&quot;205&quot; alt=&quot;awk에서 레코드와 필드&quot; filename=&quot;linux_cmd_awk_record_and_field.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;2-awk-명령어-옵션&quot;&gt;2. awk 명령어 옵션.&lt;/h3&gt;
&lt;p&gt;awk 명령의 기본 형식과 옵션은 아래와 같습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot;&gt;&lt;pre&gt;    &lt;b&gt;awk [OPTION...] [awk program] [ARGUMENT...]&lt;/b&gt;
      OPTION
        -F        &lt;span class=&quot;pl-c1&quot;&gt;:&lt;/span&gt; 필드 구분 문자 지정.
        -f        &lt;span class=&quot;pl-c1&quot;&gt;:&lt;/span&gt; awk program 파일 경로 지정.
        -v        &lt;span class=&quot;pl-c1&quot;&gt;:&lt;/span&gt; awk program에서 사용될 특정 variable값 지정.
      awk program
        -f 옵션이 사용되지 않은 경우, awk가 실행할 awk program 코드 지정.
      ARGUMENT
        입력 파일 지정 또는 variable 값 지정.&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;21-awk-program&quot;&gt;2.1 awk program.&lt;/h4&gt;
&lt;p&gt;awk 명령의 기본 형식을 보면 알겠지만, awk 명령에는 사용 가능한 옵션이 몇 개 없습니다. 대신, awk 사용자는 옵션의 사용보다는, awk program의 작성에 거의 대부분의 수고를 들이게 되는데요, 앞서 간단히 언급했듯이, awk program은 스크립트 형식의 프로그래밍 언어로 작성되기 때문에, 작성 방법이 매우 다양합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;하지만 awk program의 기본 구조는 아래와 같습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    pattern { action }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 awk 명령에서 awk program은 ' '(single quotation marks) 안에 작성합니다. 풀어서 써보면 아래 형태가 되겠죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &lt;b&gt;awk [OPTION...] 'pattern { action }' [ARGUMENT...]&lt;/b&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;pattern과 action은 모두 생략이 가능한데, pattern을 생략하는 경우는 &quot;모든 레코드&quot;가 적용되고, action을 생략하면 &quot;print&quot;가 적용됩니다. 즉, 아래와 같이 pattern이 생략되는 경우, 매칭 여부를 검사할 문자열 패턴 정보가 없기 때문에 모든 레코드가 선택되고, action을 생략하면, 기본 액션인 print가 실행되는 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;#&lt;/span&gt; pattern 생략.&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;{ print }&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt      &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;#&lt;/span&gt; file.txt의 모든 레코드 출력.&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;#&lt;/span&gt; action 생략.&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;/p/&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt            &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;#&lt;/span&gt; file.txt에서 p를 포함하는 레코드 출력.&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;pattern과 action에 작성되는 awk program 코드에는 다양한 표현식, 변수, 함수 등이 사용됩니다. 이 중 가장 중요한 변수는 레코드와 필드를 나타내는 변수인데, 하나의 레코드는 $0, 레코드에 포함된 각 필드는 그 순서대로 $1, $2, ..., $n 으로 지칭됩니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display:inline-block;width:700px;;height:auto;max-width:100%&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992D703F5D1CBC7B27&quot; style=&quot;max-width:100%;height:auto&quot; width=&quot;700&quot; height=&quot;205&quot; alt=&quot;awk에서 레코드와 필드 변수&quot; filename=&quot;linux_cmd_awk_record_and_field_variable.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아래 예제는 레코드의 길이가 10 이상인 경우, 세 번째($3), 네 번째($4), 다섯 번째($5) 필드를 출력하는 예제입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;length($0) &amp;gt; 10 { print $3, $4, $5} &lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 패턴 중에 &quot;BEGIN&quot; 과 &quot;END&quot; 라고 하는 특별한 패턴이 존재하는데요, awk가 BEGIN 패턴을 식별하면 입력 데이터로부터 첫 번째 레코드를 처리하기 전에 &quot;BEGIN&quot;에 지정된 액션을 실행합니다. 그리고 &quot;END&quot; 패턴은 &quot;BEGIN&quot;과 반대로, 모든 레코드를 처리한 다음 &quot;END&quot;에 지정된 액션을 실행합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아래 예제는 &quot;BEGIN&quot;과 &quot;END&quot; 패턴의 사용 예제를 보여줍니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;BEGIN { print &quot;TITLE : Field value 1,2&quot;} {print $1, $2} END {print &quot;Finished&quot;}&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; file.txt&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;일단, awk program 을 이해하는데 있어서 가장 기본이 되는 내용들에 대해서만 정리를 했는데요, 이 외에도 awk program에는 많은 수의 표현식과 변수, 함수 등이 제공됩니다. 이 모든 것을 본문에 정리하기는 쉽지 않기 때문에, 본문의 [&lt;a href=&quot;#4-awk-program-language&quot; title=&quot;[4. awk program language] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;4. awk program language&lt;/a&gt;]에서, 대충 어떤 것들이 있는지만 나열하겠습니다. 좀 더 자세한 내용들에 대해서는 [&lt;a href=&quot;#5-참고&quot; title=&quot;[5. 참고] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;5. 참고&lt;/a&gt;]에 링크된 사이트에서 확인하실 수 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;3-awk-명령-사용-예제&quot;&gt;3. awk 명령 사용 예제.&lt;/h3&gt;
&lt;p&gt;앞에서도 설명했듯이, awk 명령은 아래와 같은 형식으로 사용할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pl-c1&quot;&gt;    awk [OPTION...] [pattern {action} ...] [ARGUMENT...]&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아래 표는 awk 명령 사용 예제를 정리한 것입니다. 각 항목의 링크를 선택하면, 좀 더 자세한 설명과 사용 예제를 확인할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;table class=&quot;smalltbl&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;awk 사용 예&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;명령어 옵션&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#31-파일의-전체-내용-출력&quot; rel=&quot;nofollow&quot;&gt;파일의 전체 내용 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk '{ print }' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#32-필드-값-출력&quot; rel=&quot;nofollow&quot;&gt;필드 값 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk '{ print $1 }' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#33-필드-값에-임의-문자열을-같이-출력&quot; rel=&quot;nofollow&quot;&gt;필드 값에 임의 문자열을 같이 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk '{print &quot;STR&quot;$1, &quot;STR&quot;$2}' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#34-지정된-문자열을-포함하는-레코드만-출력&quot; rel=&quot;nofollow&quot;&gt;지정된 문자열을 포함하는 레코드만 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk '/STR/' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#35-특정-필드-값-비교를-통해-선택된-레코드만-출력&quot; rel=&quot;nofollow&quot;&gt;특정 필드 값 비교를 통해 선택된 레코드만 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk '$1 == 10 { print $2 }' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#36-지정된-필드의-값을-더한-값-출력-특정-필드에-대한-합-구하기&quot; rel=&quot;nofollow&quot;&gt;특정 필드들의 합 구하기&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk '{sum += $3} END { print sum }' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#37-여러-필드의-값을-더한-값-출력-여러-필드에-대한-합-구하기&quot; rel=&quot;nofollow&quot;&gt;여러 필드들의 합 구하기&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk '{ for (i=2; i&amp;lt;=NF; i++) total += $i }; END { print &quot;TOTAL : &quot;total }' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#38-레코드-단위로-필드-합-및-평균-값-구하기&quot; rel=&quot;nofollow&quot;&gt;레코드 단위로 필드 합 및 평균 값 구하기&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk '{ sum = 0 } {sum += ($3+$4+$5) } { print $0, sum, sum/3 }' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#39-필드에-연산을-수행한-결과-출력하기&quot; rel=&quot;nofollow&quot;&gt;필드에 연산을 수행한 결과 출력하기&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk '{print $1, $2, $3+2, $4, $5}' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#310-레코드-또는-필드의-문자열-길이-검사&quot; rel=&quot;nofollow&quot;&gt;레코드 또는 필드의 문자열 길이 검사&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk ' length($0) &amp;gt; 20' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#311-파일에-저장된-awk-program-실행&quot; rel=&quot;nofollow&quot;&gt;파일에 저장된 awk program 실행&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk -f [AWK FILE] [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#312-필드-구분-문자-변경하기&quot; rel=&quot;nofollow&quot;&gt;필드 구분 문자 변경하기&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk -F ':' '{ print $1 }' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#313-awk-실행-결과-레코드-정렬하기&quot; rel=&quot;nofollow&quot;&gt;awk 실행 결과 레코드 정렬하기&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk '{ print $0 }' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#314-특정-레코드만-출력하기&quot; rel=&quot;nofollow&quot;&gt;특정 레코드만 출력하기&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk 'NR == 2 { print $0; exit }' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#315-출력-필드-너비-지정하기&quot; rel=&quot;nofollow&quot;&gt;출력 필드 너비 지정하기&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk '{ printf &quot;%-3s %-8s %-4s %-4s %-4s\n&quot;, $1, $2, $3, $4, $5}' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;#316-필드-중-최대-값-출력&quot; rel=&quot;nofollow&quot;&gt;필드 중 최대 값 출력&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot; class=&quot;command&quot;&gt;&lt;code class=&quot;command&quot;&gt;awk '{max = 0; for (i=3; i&amp;lt;NF; i++) max = ($i &amp;gt; max) ? $i : max ; print max}' [FILE]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;31-파일의-전체-내용-출력&quot;&gt;3.1 파일의 전체 내용 출력.&lt;/h4&gt;
&lt;p&gt;awk 파일에 &quot;print&quot; 액션만 지정한 경우, 입력으로 지정된 파일의 내용을 출력합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;$ awk '{ print }' ./file.txt            &amp;gt; file.txt의 전체 파일 내용 출력.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;{ print }&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;32-필드-값-출력&quot;&gt;3.2 필드 값 출력.&lt;/h4&gt;
&lt;p&gt;&quot;print $n&quot; 액션을 통해 n번째 필드 값을 출력할 수 있습니다. 참고로, &quot;$0&quot;은 전체 레코드를 나타내는 변수입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;$ awk '{ print $2 }' ./file.txt           &amp;gt; 두 번째 필드 값 출력.
$ awk '{ print $1,$2 }' ./file.txt        &amp;gt; 첫 번째, 두 번째 필드 값 출력.
$ awk '{ print $0}' ./file.txt            &amp;gt; 레코드 출력.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;{ print $1, $2}&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;33-필드-값에-임의-문자열을-같이-출력&quot;&gt;3.3 필드 값에 임의 문자열을 같이 출력.&lt;/h4&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk '{print &quot;no:&quot;$1, &quot;user:&quot;$2}' ./file.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;{print &quot;no:&quot;$1, &quot;user:&quot;$2}&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;no:1 user:ppotta&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;no:2 user:soft&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;no:3 user:prog&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;34-지정된-문자열을-포함하는-레코드만-출력&quot;&gt;3.4 지정된 문자열을 포함하는 레코드만 출력.&lt;/h4&gt;
&lt;p&gt;awk의 패턴에 정규 표현식(Regular Expression)을 사용하여 문자열 패턴을 검사할 수 있습니다. 이 때, 정규 표현식은 &quot;/regex/&quot; 형태로 지정할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk '/pp/' ./file.txt                   # &quot;pp&quot; 가 포함된 레코드만 유효.
awk '/[2-3]0/' ./file.txt               # 20, 30 이 포함된 레코드만 유효.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;/pp/&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;/[2-3]0/&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;35-특정-필드-값-비교를-통해-선택된-레코드만-출력&quot;&gt;3.5 특정 필드 값 비교를 통해 선택된 레코드만 출력.&lt;/h4&gt;
&lt;p&gt;awk program language의 표현식을 사용하여, 유효한 레코드를 위한 필드 값을 비교할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk '$1 == 2 { print $2 }' ./file.txt   # 첫 번째 필드가 2인 레코드의 두 번째 필드 출력.
awk '$3 &amp;gt; 70 { print $0 }' ./file.txt   # 세 번째 필드가 70보다 큰 레코드 출력.
awk '$3 == 30 &amp;amp;&amp;amp; $4 ==40 { print $2 }' file.txt   # 세 번째 필드가 30이고 네 번째 필드가 40인 레코드의 두 번째 필드 출력.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;$1 == 2 { print $2 }&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;soft&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;$3 &amp;gt; 70 { print $0 }&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;$3 == 30 &amp;amp;&amp;amp; $4 ==40 { print $2 }&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;ppotta&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;36-지정된-필드의-값을-더한-값-출력-특정-필드에-대한-합-구하기&quot;&gt;3.6 지정된 필드의 값을 더한 값 출력. (특정 필드에 대한 합 구하기)&lt;/h4&gt;
&lt;p&gt;awk program에서 변수의 사용을 통해 특정 필드의 값을 더하고, 더해진 총 합을 출력할 수 있습니다. 이 때, 총합은 모든 레코드 탐색이 끝난 시점인, &quot;END&quot; 패턴의 액션에서 실행합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk '{sum += $3} END { print sum }' ./file.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;{sum += $3} END { print &quot;SUM : &quot;sum }&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;SUM : 180&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;37-여러-필드의-값을-더한-값-출력-여러-필드에-대한-합-구하기&quot;&gt;3.7 여러 필드의 값을 더한 값 출력. (여러 필드에 대한 합 구하기)&lt;/h4&gt;
&lt;p&gt;for 루프를 수행하여 여러 필드의 값을 연산에 포함시킬 수 있습니다. 참고로 아래 예제에서 &quot;NF&quot;는 현재 레코드의 필드 갯수를 뜻하며, &quot;$i&quot;는 변수 i가 매핑된 필드를 뜻합니다. (i=2일 때 $2)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk '{ for (i=2; i&amp;lt;=NF; i++) total += $i }; END { print &quot;TOTAL : &quot;total }' ./file.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;{ for (i=2; i&amp;lt;=NF; i++) total += $i }; END { print &quot;TOTAL : &quot;total }&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;TOTAL : 450&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;38-레코드-단위로-필드-합-및-평균-값-구하기&quot;&gt;3.8 레코드 단위로 필드 합 및 평균 값 구하기.&lt;/h4&gt;
&lt;p&gt;변수 및 액션을 조합하여 레코드 단위로 필드들의 값 및 평균을 계산하여 출력할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk '{ sum = 0 } {sum += ($3+$4+$5) } { print $0, sum, sum/3 }' ./file.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;{ sum = 0 } {sum += ($3+$4+$5) } { print $0, sum, sum/3 }&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50 120 40&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80 210 70&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20 120 40&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;39-필드에-연산을-수행한-결과-출력하기&quot;&gt;3.9 필드에 연산을 수행한 결과 출력하기.&lt;/h4&gt;
&lt;p&gt;awk program 표현식을 사용하여, 필드에 연산을 수행한 결과를 출력할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk '{print $1, $2, $3+2, $4, $5}' ./file.txt     # 세 번째 필드에 2를 더한 값을 출력.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;{print $1, $2, $3+2, $4, $5}&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 32 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft 62 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog 92 10 20&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;310-레코드-또는-필드의-문자열-길이-검사&quot;&gt;3.10 레코드 또는 필드의 문자열 길이 검사.&lt;/h4&gt;
&lt;p&gt;length() 함수를 사용해 레코드 또는 필드의 문자열 길이를 확인할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk ' length($0) &amp;gt; 20' ./file.txt               # 레코드의 길이가 20보다 큰 경우.
awk ' length($2) &amp;gt; 4 { print $0 } ' ./file.txt  # 두 번째 필드의 길이가 4보다 큰 레코드 출력.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt; length($2) &amp;gt; 4 { print $0 } &lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;311-파일에-저장된-awk-program-실행&quot;&gt;3.11 파일에 저장된 awk program 실행.&lt;/h4&gt;
&lt;p&gt;awk 실행 시, &quot;-f&quot; 옵션을 사용하여 파일로부터 awk program을 실행할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk -f awkp.script ./file.txt           # awkp.script에 저장된 awk program 실행
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;cat awkp.script&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;    for (i=2; i&amp;lt;=NF; i++)&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;        total += $i&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-c1&quot;&gt;END {&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;    print &quot;TOTAL : &quot;total&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;}&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk -f awkp.script ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;TOTAL : 450&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;312-필드-구분-문자-변경하기&quot;&gt;3.12 필드 구분 문자 변경하기.&lt;/h4&gt;
&lt;p&gt;기본적으로 레코드의 필드를 구분하는 문자는 space 입니다. 이를 &quot;-F&quot; 사용하여 변경할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk -F ':' '{ print $1 }' ./file.txt         # 필드 구분 문자를 : 로 변경.
awk -F ',' '{ print $1 }' ./file.txt         # 필드 구분 문자를 , 로 변경.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file2.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1, ppotta, 30, 40, 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2, soft,   60, 70, 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3, prog,   90, 10, 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk -F &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;,&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;{ print $1 }&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file2.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;313-awk-실행-결과-레코드-정렬하기&quot;&gt;3.13 awk 실행 결과 레코드 정렬하기.&lt;/h4&gt;
&lt;p&gt;awk 명령과 sort 명령을 조합하여, awk 실행 결과로 출력되는 레코드를 정렬할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk '{ print $0 }' file.txt | sort      # 출력 레코드를 오름차순으로 정렬.
awk '{ print $0 }' file.txt | sort -r   # 출력 레코드를 역순으로 정렬.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;{ print $0 }&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; file.txt &lt;span class=&quot;pl-k&quot;&gt;|&lt;/span&gt; sort -r&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;314-특정-레코드만-출력하기&quot;&gt;3.14 특정 레코드만 출력하기.&lt;/h4&gt;
&lt;p&gt;exit 키워드를 사용하여, 조건에 따라 awk 실행을 중지시킬 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk '{ print $0; exit }' file.txt       # 첫 번째 레코드만 출력하고 실행 중지.
awk 'NR == 2 { print $0; exit }' file.txt         # 두 번째 레코드만 출력하고 실행 중지.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;NR == 2 { print $0; exit }&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;315-출력-필드-너비-지정하기&quot;&gt;3.15 출력 필드 너비 지정하기.&lt;/h4&gt;
&lt;p&gt;printf 함수를 사용하여 필드 값 출력 포맷을 지정할 수 있습니다. printf 함수에 사용하는 출력 포맷은 C 언어와 동일합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk '{ printf &quot;%-3s %-8s %-4s %-4s %-4s\n&quot;, $1, $2, $3, $4, $5}' file.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;{ printf &quot;%-3s %-8s %-4s %-4s %-4s\n&quot;, $1, $2, $3, $4, $5}&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1   ppotta   30   40   50  &lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2   soft     60   70   80  &lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3   prog     90   10   20&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;316-필드-중-최대-값-출력&quot;&gt;3.16 필드 중 최대 값 출력.&lt;/h4&gt;
&lt;p&gt;아래와 같은 코드를 통해 레코드 내 필드의 최대 값을 구하여 출력할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;usage&quot;&gt;&lt;code&gt;awk '{max = 0; for (i=3; i&amp;lt;=NF; i++) max = ($i &amp;gt; max) ? $i : max ; print max}' ./file.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-shell-session&quot;&gt;&lt;pre&gt;$ &lt;span class=&quot;pl-s1&quot;&gt;cat file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;1 ppotta 30 40 50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;2 soft   60 70 80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;3 prog   90 10 20&lt;/span&gt;
$ &lt;span class=&quot;pl-s1&quot;&gt;awk &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;{max = 0; for (i=3; i&amp;lt;=NF; i++) max = ($i &amp;gt; max) ? $i : max ; print max}&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ./file.txt&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;50&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;80&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;90&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;4-awk-program-language&quot;&gt;4. awk program language&lt;/h3&gt;
&lt;p&gt;awk program 이 프로그래밍 언어로 작성되는 만큼 다양한 요소들을 사용하여 프로그래밍됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;먼저 awk 표현식은 C 프로그래밍 언어 표현식과 유사한 형태로 제공됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    (E),    $n,     ++E,    --E,    E++,    E--,    E^E,    !E,     +E,
    -E,     E*E,    E/E,    E%E,    E+E,    E-E,    E E,    E&amp;lt;E,    E&amp;lt;=E,
    E!=E,   E==E,   E&amp;gt;E,    E&amp;gt;=E,   E~E,    E!-E,   E in array,     (n) in array, 
    E&amp;amp;&amp;amp;E,   E||E,   E1?E2:E3        V^=E,   V%=E,   V*=E,   V/=E,   V+=E,
    V-=E,   V=E
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;awk program에는 아래와 같은 키워드가 제공됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    BEGIN   delete  END     function    in      printf
    break   do      exit    getline     next    return
    continue        else    for         if      print      while
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;awk program 에서는 새로운 변수를 선언하고 값을 할당하거나 참조할 수 있습니다. 그리고 아래와 같이 특수 목적으로 미리 정의된 변수들을 사용할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    ARGC        : ARGV 배열 요소의 갯수.
    ARGV        : command line argument에 대한 배열.
    CONVFMT     : 문자열을 숫자로 변경할 때 사용할 형식. (ex, &quot;%.6g&quot;)
    ENVIRON     : 환경변수에 대한 배열.
    FILENAME    : 경로를 포함한 입력 파일 이름.
    FNR         : 현재 파일에서 현재 레코드의 순서 값.
    FS          : 필드 구분 문자. (기본 값 = space)
    NF          : 현재 레코드에 있는 필드의 갯수.
    NR          : 입력 시작 점에서 현재 레코드의 순서 값.
    OFMT        : 문자열을 출력할 때 사용할 형식.
    OFS         : 결과 출력 시 필드 구분 문자. (기본 값 = space)
    ORS         : 결과 출력 시 레코드 구분 문자. (기본 값 = newline)
    RLENGTH     : match 함수에 의해 매칭된 문자열의 길이.
    RS          : 레코드 구분 문자. (기본 값 = newline)
    RSTART      : match 함수에 의해 매칭된 문자열의 시작 위치.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;awk program 에서 사용할 수 있는 함수들에는 아래와 같은 것들이 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Arithmetic Functions :
    atan2(y,x),     cos(x),     sin(x),     exp(x),     log(x),     sqrt(x),
    int(x),         rand(),     srand([expr])

String Functions :
    gsub(ere, repl[, in]),      index(s, t),            length[([s])],
    match(s, ere),              split(s, a[, fs ]),     sprintf(fmt, expr, expr, ...),
    sub(ere, repl[, in ]),      substr(s, m[, n ]),     tolower(s),
    toupper(s)

Input/Output and General Functions :
    close(expression),          getline                 getline var
    system(expression)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;5-참고&quot;&gt;5. 참고.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;GNU Awk User's Guide.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://www.gnu.org/software/gawk/manual/gawk.html&quot; title=&quot;[https://www.gnu.org/software/gawk/manual/gawk.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;GNU Awk User's Guide.&lt;/a&gt;] 내용을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Man7 Linux Manual Page - awk
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;http://man7.org/linux/man-pages/man1/awk.1p.html&quot; title=&quot;[http://man7.org/linux/man-pages/man1/awk.1p.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;Man7. man. awk&lt;/a&gt;] 내용을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.END.&lt;/p&gt;&lt;/article&gt;</description>
      <category>LINUX 시스템/명령어 사용법</category>
      <category>awk</category>
      <category>awk 명령 사용법</category>
      <category>awk 사용 예</category>
      <category>awk 사용 예제</category>
      <category>awk 사용법</category>
      <category>awk 예제</category>
      <category>linux awk example</category>
      <category>linux 파일 데이터 조작</category>
      <category>리눅스 awk 명령</category>
      <category>리눅스 데이터 리포트</category>
      <category>리눅스 텍스트 데이터 조작</category>
      <category>텍스트 데이터 조작 명령</category>
      <author>뽀따</author>
      <guid isPermaLink="true">https://recipes4dev.tistory.com/171</guid>
      <comments>https://recipes4dev.tistory.com/171#entry171comment</comments>
      <pubDate>Wed, 3 Jul 2019 23:55:53 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드 스레드 통신. 핸들러와 Runnable. (Android Thread Communication. Handler and Runnable)</title>
      <link>https://recipes4dev.tistory.com/170</link>
      <description>&lt;link rel=&quot;stylesheet&quot; href=&quot;https://tistory1.daumcdn.net/tistory/1573970/skin/images/style_gfm.css&quot; type=&quot;text/css&quot;&gt;

&lt;article class=&quot;madwin-body&quot;&gt;&lt;p&gt;&lt;br /&gt;

&lt;/p&gt;&lt;h3 id=&quot;1-안드로이드-핸들러-android-handler&quot;&gt;1. 안드로이드 핸들러. (Android Handler)&lt;/h3&gt;
&lt;p&gt;지난 글 [&lt;a href=&quot;https://recipes4dev.tistory.com/166&quot; title=&quot;[https://recipes4dev.tistory.com/166] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드. 핸들러와 메시지. (Android Thread. Handler and Message)&lt;/a&gt;]에서, 안드로이드의 가장 기본적인 스레드 통신 방법인 핸들러(Handler)와 메시지(Message)에 대해 살펴보았습니다. 루퍼(Looper)와 메시지큐(MessageQueue), 그리고 핸들러(Handler)와 메시지(Message)에 대해 알아보고, 메시지 전달 및 처리 흐름 내에서 각 요소들이 수행하는 역할들에 대해서 설명했습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;핸들러를 통해 메시지를 전달하는 방식은 간단하고 명료합니다. 수신 측 스레드에 핸들러 객체를 생성한 다음 &lt;code&gt;handleMessage()&lt;/code&gt; 메서드를 오버라이드하고, 송신 측 스레드에서는 핸들러 객체에서 메시지 객체를 할당하여 값을 채운 다음 &lt;code&gt;sendMessage()&lt;/code&gt; 메서드로 보내면 됩니다. 구체적인 절차와 코드 작성 방법은 [&lt;a href=&quot;https://recipes4dev.tistory.com/166#4-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%ED%95%B8%EB%93%A4%EB%9F%AChandler-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95&quot; title=&quot;[https://recipes4dev.tistory.com/166#4-안드로이드-핸들러handler-사용-방법] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드. 핸들러와 메시지. (Android Thread. Handler and Message) - 4. 안드로이드 핸들러(Handler) 사용 방법.&lt;/a&gt;]에서 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 핸들러(Handler)를 통해 스레드 통신을 수행할 때, 반드시 &lt;code&gt;Message&lt;/code&gt; 객체만 사용해야 하는 것은 아닙니다. 경우에 따라 &lt;code&gt;Message&lt;/code&gt;를 사용하는 방법보다 간단하게 스레드 통신을 수행할 수 있는&amp;nbsp;방법이 있는데요, 바로 &lt;code&gt;Runnable&lt;/code&gt; 객체를 사용하는 방법입니다.&lt;/p&gt;
&lt;h4 id=&quot;11-핸들러handler-사용-목적과-runnable&quot;&gt;1.1 핸들러(Handler) 사용 목적과 Runnable&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/166&quot; title=&quot;[https://recipes4dev.tistory.com/166] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드. 핸들러와 메시지. (Android Thread. Handler and Message)&lt;/a&gt;]에서, 핸들러(Handler)가 스레드의 메시지 큐(Message Queue)에 메시지(Message)를 보내거나, 수신된 메시지(Message)를 처리할 때 사용하는 클래스라고 설명했었는데요. 사실, 보다 정확한 표현을 위해서는, 여기에 한 가지가 더 추가되어야 합니다. 바로 &lt;code&gt;Runnable&lt;/code&gt; 객체도 보낼 수 있다는 것이죠.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9904B3475D10CC0535&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9904B3475D10CC0535&quot; width=&quot;700&quot; height=&quot;202&quot; alt=&quot;Handler Message and Runnable&quot; filename=&quot;thread_handler_runnable_message_and_runnable.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;안드로이드 개발 참조문서의 &lt;code&gt;Handler&lt;/code&gt; 항목(&lt;a href=&quot;https://developer.android.com/reference/android/os/Handler&quot; rel=&quot;nofollow&quot;&gt;https://developer.android.com/reference/android/os/Handler&lt;/a&gt;)을 보면, &lt;code&gt;Handler&lt;/code&gt;에 대한 설명이 아래의 문장으로 시작되는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;번역해보면, &quot;핸들러(Handler)는 스레드의 메시지 큐(MessageQueue)와 관련된 &lt;strong&gt;Message&lt;/strong&gt; 및 &lt;strong&gt;Runnable&lt;/strong&gt; 객체를 보내고 처리할 수 있게 만들어준다&quot;는 내용입니다. 그런데 여기서, &lt;code&gt;Runnable&lt;/code&gt; 객체를 보낼 수 있다는 문장은, 구체적으로 무엇을 의미하는 걸까요? &lt;code&gt;Message&lt;/code&gt;를 보내는 것과 &lt;code&gt;Runnable&lt;/code&gt;을 보내는 것은 어떤 차이가 있는 걸까요?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;메시지(Message)와 핸들러(Hander)를 사용하여 스레드 통신을 수행하는 주 목적은, &lt;strong&gt;핸들러를 통해 데이터를 전달하여, 전달된 데이터 처리를 위해 작성된 대상 스레드의 코드가 실행되도록 만드는 것&lt;/strong&gt;입니다. 이를 위해, 메시지 객체(what, object, arg1, arg2, ...)에 값을 채워 수신 스레드의 핸들러에 보내고, 수신 측 스레드에서는 &lt;code&gt;handleMessage()&lt;/code&gt; 메서드를 오버라이드하여 수신된 메시지 객체를 처리하기 위해 작성된 코드를 실행하는 것이죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 &lt;code&gt;Message&lt;/code&gt; 객체를 사용하는 방법에는 조금 번거로운 절차가 필요합니다. 메시지에 저장된 데이터의 종류를 식별하기 위한 값을 상수로 정의해야 하고, &lt;code&gt;handleMessage()&lt;/code&gt;에서는 상수 값에 따른 처리 코드를 조건 문으로 작성해야 합니다. 그리고 메시지를 보내는 측에서도, 전달할 데이터 종류에 따라 별도의 &lt;code&gt;Message&lt;/code&gt; 객체를 구성하고 값을 채워 보내야 합니다. 오직, &lt;strong&gt;대상 스레드에 작성된 코드를 실행하기 위해&lt;/strong&gt;서 말이죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;여기서, 한 가지 질문을 던져 보겠습니다. 핸들러 사용의 주 목적이 대상 스레드의 코드를 실행하는 것이라면, 메시지를 통해 데이터를 전달하는 번거로운 과정을 거치지 말고, 그냥 &lt;b&gt;&quot;실행 코드&quot;&lt;/b&gt;를 바로 보내면 되지 않을까요? 즉, 핸들러에 실행 코드가 담긴 객체를 보내고, 대상 스레드에서는 수신된 객체의 코드를 직접 실행하도록 만드는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;네. 여기서 말하는 &quot;실행 코드가 담긴 객체&quot;. 그것이 바로 &lt;code&gt;Runnable&lt;/code&gt; 객체입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/990BEF3A5D10CC0517&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F990BEF3A5D10CC0517&quot; width=&quot;700&quot; height=&quot;260&quot; alt=&quot;Handler Runnable 스레드 통신 흐름&quot; filename=&quot;thread_handler_runnable_thread_communication_flow.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자, 이제 핸들러를 통해 &lt;code&gt;Runnable&lt;/code&gt; 객체를 보낼 수 있다는 문장의 의미가 조금 이해 되시나요? 좀 더 나아가서, [&lt;a href=&quot;https://recipes4dev.tistory.com/143&quot; title=&quot;[https://recipes4dev.tistory.com/143] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드(Android Thread)&lt;/a&gt;]를 살펴보고 그 내용을 정확히 이해했다면, 그리고 [&lt;a href=&quot;https://developer.android.com/reference/java/lang/Runnable.html&quot; title=&quot;[https://developer.android.com/reference/java/lang/Runnable.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Runnable&lt;/a&gt;]를 확인한 적이 있다면, 대상 스레드에서 실행될 코드를 &lt;code&gt;Runnable&lt;/code&gt;의 &lt;code&gt;run()&lt;/code&gt; 메서드에 작성한다는 것도 눈치채셨을 것 같네요.&lt;/p&gt;
&lt;h3 id=&quot;2-핸들러handler로-runnable-객체-보내기&quot;&gt;2. 핸들러(Handler)로 Runnable 객체 보내기.&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Runnable&lt;/code&gt; 객체를 보내는 방법도, 수신 스레드 측의 &lt;code&gt;Handler&lt;/code&gt; 참조를 사용한다는 점에서는 &lt;code&gt;Message&lt;/code&gt; 객체를 보내는 방법과 동일합니다. 하지만 &lt;code&gt;Runnable&lt;/code&gt; 객체로 보내고 전달된 코드가 실행되는 부분은 조금 다른데요, 먼저 다음 그림을 통해 &lt;code&gt;Runnable&lt;/code&gt; 객체를 보내는 절차를 확인해 보시죠.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E8424C5D10CC0533&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E8424C5D10CC0533&quot; width=&quot;700&quot; height=&quot;274&quot; alt=&quot;Handler로 Runnable 객체를 보내는 절차.&quot; filename=&quot;thread_handler_runnable_usage_flow.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;21-runnable-수신-스레드--handler-객체-생성&quot;&gt;2.1 Runnable 수신 스레드 : Handler 객체 생성.&lt;/h4&gt;
&lt;p&gt;핸들러를 사용해 &lt;code&gt;Runnable&lt;/code&gt; 객체를 보내기 위해서는, 먼저 수신 스레드에서 핸들러 객체를 생성해야 합니다. [&lt;a href=&quot;https://recipes4dev.tistory.com/166#41-%EB%A9%94%EC%8B%9C%EC%A7%80-%EC%88%98%EC%8B%A0-%EC%8A%A4%EB%A0%88%EB%93%9C--handler-%EA%B0%9D%EC%B2%B4-%EC%83%9D%EC%84%B1-%EB%B0%8F-handlemessage-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%93%9C&quot; title=&quot;[https://recipes4dev.tistory.com/166#41-메시지-수신-스레드--handler-객체-생성-및-handlemessage-메서드-오버라이드] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드. 핸들러와 메시지. (Android Thread. Handler and Message.) - 4. 안드로이드 핸들러(Handler) 사용 방법&lt;/a&gt;]에서 설명했듯이, &lt;code&gt;Handler&lt;/code&gt; 객체는 생성과 동시에 해당 스레드에서 동작 중인 루퍼(Looper)와 메시지 큐(MessageQueue)에 자동으로 연결됩니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;pl-smi&quot;&gt;Handler&lt;/span&gt; mHandler &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Handler&lt;/span&gt;() ;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자, 수신 스레드에서 할 일은 이게 전부입니다. [&lt;a href=&quot;https://recipes4dev.tistory.com/166#41-%EB%A9%94%EC%8B%9C%EC%A7%80-%EC%88%98%EC%8B%A0-%EC%8A%A4%EB%A0%88%EB%93%9C--handler-%EA%B0%9D%EC%B2%B4-%EC%83%9D%EC%84%B1-%EB%B0%8F-handlemessage-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%93%9C&quot; title=&quot;[https://recipes4dev.tistory.com/166#41-메시지-수신-스레드--handler-객체-생성-및-handlemessage-메서드-오버라이드] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드. 핸들러와 메시지. (Android Thread. Handler and Message.) - 4. 안드로이드 핸들러(Handler) 사용 방법&lt;/a&gt;] 에서는 핸들러를 생성하고, 수신 메시지를 처리하기 위해 &lt;code&gt;handleMessage()&lt;/code&gt; 메서드를 오버라이드했었지만, &lt;code&gt;Runnable&lt;/code&gt; 객체를 보낼 때는 이 과정이 필요없습니다. 실행될 코드는 이미 &lt;code&gt;Runnable&lt;/code&gt; 객체의 &lt;code&gt;run()&lt;/code&gt; 메서드 안에 담겨져 있으니까요.&lt;/p&gt;
&lt;h4 id=&quot;22-runnable-송신-스레드--runnable-객체-생성-및-run-메서드-오버라이드&quot;&gt;2.2 Runnable 송신 스레드 : Runnable 객체 생성 및 run() 메서드 오버라이드.&lt;/h4&gt;
&lt;p&gt;이제 송신 측 스레드에서 &lt;code&gt;Runnable&lt;/code&gt; 객체를 만들고 &lt;code&gt;run()&lt;/code&gt; 메서드를 오버라이드해야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;NewThread&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;Thread&lt;/span&gt; {
        &lt;span class=&quot;pl-smi&quot;&gt;Handler&lt;/span&gt; handler &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; mHandler ;

        &lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;run&lt;/span&gt;() {
            &lt;span class=&quot;pl-k&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;) {
                &lt;b&gt;&lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; create Runnable instance.&lt;/span&gt;
                &lt;span class=&quot;pl-smi&quot;&gt;Runnable&lt;/span&gt; runnable &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Runnable&lt;/span&gt;() {
                    &lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
                    &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;run&lt;/span&gt;() {
                        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; TODO : 실행 코드 작성.&lt;/span&gt;
                    }
                }&lt;/b&gt;

                &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; send runnable object.&lt;/span&gt;
                handler&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;post(runnable) ;
            }
        }
        
    }
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;23-runnable-객체-보내기&quot;&gt;2.3 Runnable 객체 보내기&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Runnable&lt;/code&gt; 객체를 만들고 &lt;code&gt;run()&lt;/code&gt; 메서드를 오버라이드하고 나면, 마지막으로 할 일은 &lt;code&gt;Handler.post()&lt;/code&gt; 메서드를 사용하여, 앞서 생성한 &lt;code&gt;Runnable&lt;/code&gt; 객체를 수신 측 스레드로 보내는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;    handler&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;post(runnable) ;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/166#41-%EB%A9%94%EC%8B%9C%EC%A7%80-%EC%88%98%EC%8B%A0-%EC%8A%A4%EB%A0%88%EB%93%9C--handler-%EA%B0%9D%EC%B2%B4-%EC%83%9D%EC%84%B1-%EB%B0%8F-handlemessage-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%93%9C&quot; title=&quot;[https://recipes4dev.tistory.com/166#41-메시지-수신-스레드--handler-객체-생성-및-handlemessage-메서드-오버라이드] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드. 핸들러와 메시지. (Android Thread. Handler and Message.) - 4. 안드로이드 핸들러(Handler) 사용 방법&lt;/a&gt;]에서 &lt;code&gt;Message&lt;/code&gt; 객체를 보내기 위해 &lt;code&gt;sendMessage()&lt;/code&gt; 메서드를 사용한다는 것 확인했을텐데요, &lt;code&gt;Runnable&lt;/code&gt; 객체를 보낼 때는 아래 표에 정리된 &quot;post&quot;로 시작하는 이름의 메서드를 사용합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;table class=&quot;smalltbl&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;메서드 프로토타입&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;boolean &lt;b&gt;&lt;span style=&quot;color: rgb(0, 85, 255);&quot;&gt;post&lt;/span&gt;&lt;/b&gt;(Runnable r)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Runnable 객체를 전달. (핸들러에 연결된 메시지큐에 추가.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;boolean &lt;b&gt;&lt;span style=&quot;color: rgb(0, 85, 255);&quot;&gt;postAtFrontOfQueue&lt;/span&gt;&lt;/b&gt;((Runnable r)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Runnable 객체를 메시지큐의 가장 앞에 추가.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot; style=&quot;height: 47px;&quot;&gt;boolean &lt;b&gt;&lt;span style=&quot;color: rgb(0, 85, 255);&quot;&gt;postAtTime&lt;/span&gt;&lt;/b&gt;(Runnable r, long uptimeMillis)&lt;/td&gt;
&lt;td align=&quot;left&quot; style=&quot;height: 47px;&quot;&gt;uptimeMillis로 지정된 시각에, Runnable 객체 전달.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;boolean &lt;b&gt;&lt;span style=&quot;color: rgb(0, 85, 255);&quot;&gt;postAtTime&lt;/span&gt;&lt;/b&gt;(Runnable r, Object token, long uptimeMillis)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;uptimeMillis로 지정된 시각에, Runnable 객체 전달. r을 취소하는데 사용될 수 있는 token 인스턴스 사용 가능.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;boolean &lt;b&gt;&lt;span style=&quot;color: rgb(0, 85, 255);&quot;&gt;postDelayed&lt;/span&gt;&lt;/b&gt;(Runnable r, long delayMillis)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;현재 시각에서 delayMillis 만큼의 시간 후에, Runnable 객체 실행.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;boolean &lt;b&gt;&lt;span style=&quot;color: rgb(0, 85, 255);&quot;&gt;postDelayed&lt;/span&gt;&lt;/b&gt;(Runnable r, Object token, long delayMillis)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;현재 시각에서 delayMillis 만큼의 시간 후에, Runnable 객체 실행. token 인스턴스를 통해 r의 실행 취소 가능.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&quot;post&quot; 다음에 AtFrontOfQueue, AtTime, Delayed 등의 접미사가 붙은 메서드는 메시지큐 내에서의 &lt;code&gt;Runnable&lt;/code&gt; 객체의 위치와 &lt;code&gt;Runnable&lt;/code&gt; 객체가 처리되는 시점을 직접 지정하기 때문에, &lt;code&gt;Runnable&lt;/code&gt; 객체의 처리 우선순위 또는 스레드 실행 대기 시간 등에 영향을 미칠 수 있습니다. 그러므로 각 메서드의 정확한 동작 방식과 그에 따른 주의사항에 대해 정확히 인지하고 사용하시길 바랍니다.&lt;/p&gt;
&lt;h3 id=&quot;3-runnable-인터페이스&quot;&gt;3. Runnable 인터페이스.&lt;/h3&gt;
&lt;p&gt;보통 자바 개발자들이 &lt;code&gt;Runnable&lt;/code&gt; 인터페이스를 처음 접하게 되는 순간은, 새로운 스레드를 실행할 때 입니다. [&lt;a href=&quot;https://recipes4dev.tistory.com/143#22-runnable-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EA%B5%AC%ED%98%84implements&quot; title=&quot;[https://recipes4dev.tistory.com/143#22-runnable-인터페이스-구현implements] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드(Android Thread)&lt;/a&gt;]에서 살펴보았듯이, &lt;code&gt;Runnable&lt;/code&gt; 인터페이스를 implements 한 다음, &lt;code&gt;Thread&lt;/code&gt; 인스턴스에 전달하고, 생성된 &lt;code&gt;Thread&lt;/code&gt; 인스턴스의 &lt;code&gt;start()&lt;/code&gt; 메서드를 실행하는 과정을 통해 새로운 스레드를 만들고 실행할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;NewRunnable&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;Runnable&lt;/span&gt; {
        &lt;span class=&quot;pl-en&quot;&gt;NewRunnable&lt;/span&gt;() {

        }

        &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;run&lt;/span&gt;() {
            &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; TODO : thread running codes.&lt;/span&gt;
        }
    }

    &lt;span class=&quot;pl-smi&quot;&gt;NewRunnable&lt;/span&gt; nr &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;NewRunnable&lt;/span&gt;() ;
    &lt;span class=&quot;pl-smi&quot;&gt;Thread&lt;/span&gt; t &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Thread&lt;/span&gt;(nr) ;
    t&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;start() ;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 스레드를 생성할 때 작성한 &lt;code&gt;Runnable&lt;/code&gt; 인터페이스의 코드를 보고, 단순히 &lt;code&gt;Runnable&lt;/code&gt; 인터페이스가 새로운 스레드를 실행할 때만 사용된다거나, 심지어 &lt;code&gt;Thread&lt;/code&gt; 클래스처럼 스레드 실행 코드가 구현된 클래스로 착각하는 경우가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;하지만 명확히 알아두어야 할 것은, 새로운 스레드를 실행하는 역할은 &lt;code&gt;Thread&lt;/code&gt; 클래스의 역할입니다. &lt;code&gt;Runnable&lt;/code&gt;은 단지 새로운 스레드에서 실행될 &lt;code&gt;run()&lt;/code&gt; 메서드를 가지는 인터페이스일 뿐인 것이죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Runnable&lt;/code&gt; 인터페이스는 단 하나의 메서드, &lt;code&gt;run()&lt;/code&gt; 메서드만 가집니다. &lt;code&gt;Runnable&lt;/code&gt; 인터페이스를 상속한 클래스가 오버라이드해야 할 단 하나의 메서드이자, &lt;code&gt;Runnable&lt;/code&gt; 객체를 참조하는 곳에서 호출할 메서드인 &lt;code&gt;run()&lt;/code&gt; 메서드.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Thread&lt;/code&gt; 생성 시에 &lt;code&gt;Runnable&lt;/code&gt; 인터페이스를 implements 하는 것은 굳이 &lt;code&gt;Thread&lt;/code&gt; 클래스를 상속하지 않아도 스레드 실행 코드를 작성할 수 있기 때문이지, &lt;code&gt;Runnable&lt;/code&gt;의 용도가 새로운 스레드를 만드는 것에만 국한된 것은 아니라는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Runnable&lt;/code&gt; 객체는 어디서든 사용될 수 있습니다. 코드 실행이 필요한 곳이라면 어디서든 &lt;code&gt;Runnable&lt;/code&gt; 인터페이스를 상속받아 &lt;code&gt;run()&lt;/code&gt; 메서드를 작성한 다음, 해당 객체를 전달해 &lt;code&gt;run()&lt;/code&gt; 메서드를 실행할 수 있는 것입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BFC2485D10CC0508&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BFC2485D10CC0508&quot; width=&quot;700&quot; height=&quot;146&quot; alt=&quot;Runnable 인터페이스&quot; filename=&quot;thread_handler_runnable_runnable_interface.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;다소 설명이 길어졌는데요, 요약하자면, &lt;code&gt;Runnable&lt;/code&gt; 인터페이스가 사용된 코드를 보고, 단순히 새로운 스레드를 실행하는 코드로만 해석하는 실수를 하지 말라는 것입니다.&lt;/p&gt;
&lt;h3 id=&quot;4-핸들러handler와-runnable을-사용한-스레드-통신-예제&quot;&gt;4. 핸들러(Handler)와 Runnable을 사용한 스레드 통신 예제.&lt;/h3&gt;
&lt;p&gt;이제 예제를 통해 &lt;code&gt;Runnable&lt;/code&gt; 객체를 전달하여 스레드 간 통신을 수행하는 방법을 알아보겠습니다. 예제는, [&lt;a href=&quot;https://recipes4dev.tistory.com/150&quot; title=&quot;[https://recipes4dev.tistory.com/150] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드 예제. 스레드로 고민해보기. (Android Thread UseCase)&lt;/a&gt;]에서 핸들러와 메시지를 사용하여 만들어본 디지털 시계를, &lt;code&gt;Message&lt;/code&gt; 대신 &lt;code&gt;Runnable&lt;/code&gt;을 사용하여 만들어보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;아래 예제 코드와 [&lt;a href=&quot;https://recipes4dev.tistory.com/150#5-%EC%8A%A4%EB%A0%88%EB%93%9C-%EC%A0%81%EC%9A%A9-%EC%8A%A4%EB%A0%88%EB%93%9C-%EA%B0%84-%ED%86%B5%EC%8B%A0-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0&quot; title=&quot;[https://recipes4dev.tistory.com/150#5-스레드-적용-스레드-간-통신-적용하기] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드 예제. 스레드로 고민해보기. (Android Thread UseCase) - 5. 스레드 적용. 스레드 간 통신 적용하기.&lt;/a&gt;]에서 작성된 코드를 비교하면, &lt;code&gt;Message&lt;/code&gt;와 &lt;code&gt;Runnable&lt;/code&gt; 사용 방법의 차이를 확인할 수 있습니다.&lt;/p&gt;
&lt;h4 id=&quot;41-runnable을-전달을-통해-스레드-간-통신을-수행하는-앱-구조-설계&quot;&gt;4.1 Runnable을 전달을 통해 스레드 간 통신을 수행하는 앱 구조 설계.&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Runnable&lt;/code&gt;을 핸들러로 전달하여 현재 시각을 표시하는 방법의 실행 절차는 아래와 같은 구조를 가집니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-1] 앱 구조 설계. (핸들러를 통해 Runnable 전달)
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99AADD495D10CC0517&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99AADD495D10CC0517&quot; width=&quot;700&quot; height=&quot;509&quot; alt=&quot;앱 구조 설계. (핸들러에 Runnable 전달)&quot; filename=&quot;Thread_handler_runnable_example_flow.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;42-메인액티비티-레이아웃-작성&quot;&gt;4.2 메인액티비티 레이아웃 작성.&lt;/h4&gt;
&lt;p&gt;메인액티비티 화면에는 아래 그림과 같이 화면 가운데 현재 시각을 표시할 수 있는 텍스트뷰를 배치합니다.&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-2] 메인액티비티 레이아웃 작성.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-text-xml&quot;&gt;&lt;pre&gt;&amp;lt;?&lt;span class=&quot;pl-ent&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt; version&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;1.0&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt; encoding&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;utf-8&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;?&amp;gt;
&amp;lt;&lt;span class=&quot;pl-ent&quot;&gt;android&lt;/span&gt;.support.constraint.ConstraintLayout &lt;span class=&quot;pl-e&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;http://schemas.android.com/apk/res/android&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;http://schemas.android.com/apk/res-auto&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;tools&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;http://schemas.android.com/tools&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_width&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;match_parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_height&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;match_parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_behavior&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@string/appbar_scrolling_view_behavior&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;context&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;.MainActivity&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-e&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;showIn&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@layout/activity_main&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;

    &amp;lt;&lt;span class=&quot;pl-ent&quot;&gt;TextView&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_width&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;wrap_content&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_height&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;wrap_content&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;textSize&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;48sp&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;text&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;00:00:00&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@+id/clock&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintBottom_toBottomOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintLeft_toLeftOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintRight_toRightOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-e&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;pl-e&quot;&gt;layout_constraintTop_toTopOf&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;parent&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; /&amp;gt;

&amp;lt;/&lt;span class=&quot;pl-ent&quot;&gt;android&lt;/span&gt;.support.constraint.ConstraintLayout&amp;gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;43-runnable-객체-전달-기능-구현&quot;&gt;4.3 Runnable 객체 전달 기능 구현.&lt;/h4&gt;
&lt;p&gt;자, 이제 &lt;code&gt;Runnable&lt;/code&gt; 객체의 &lt;code&gt;run()&lt;/code&gt; 메서드에 현재 시각을 표시하는 코드를 작성하고 핸들러를 통해 전달하여, 메인스레드에서 실행되도록 만들겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre lang=&quot;step&quot;&gt;&lt;code&gt;[STEP-3] Runnable 객체에 현재 시각 갱신 코드 작성 후, 메인 스레드로 전달.
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight highlight-source-java&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;MainActivity&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;AppCompatActivity&lt;/span&gt; {

    &lt;b&gt;&lt;span class=&quot;pl-smi&quot;&gt;TextView&lt;/span&gt; clockTextView ;
    &lt;span class=&quot;pl-k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Handler&lt;/span&gt; mHandler ;&lt;/b&gt;

    &lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onCreate&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;Bundle&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;savedInstanceState&lt;/span&gt;) {
        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; ... 코드 계속.&lt;/span&gt;

        &lt;b&gt;mHandler &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Handler&lt;/span&gt;() ;&lt;/b&gt;

        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; 핸들러로 전달할 runnable 객체. 수신 스레드 실행.&lt;/span&gt;
        &lt;b&gt;&lt;span class=&quot;pl-k&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Runnable&lt;/span&gt; runnable &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Runnable&lt;/span&gt;() {
            &lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;run&lt;/span&gt;() {
                &lt;span class=&quot;pl-smi&quot;&gt;Calendar&lt;/span&gt; cal &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Calendar&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;getInstance();

                &lt;span class=&quot;pl-smi&quot;&gt;SimpleDateFormat&lt;/span&gt; sdf &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;SimpleDateFormat&lt;/span&gt;(&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;HH:mm:ss&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;);
                &lt;span class=&quot;pl-smi&quot;&gt;String&lt;/span&gt; strTime &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; sdf&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;format(cal&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;getTime());

                clockTextView &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; findViewById(&lt;span class=&quot;pl-smi&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;clock);
                clockTextView&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;setText(strTime);
            }
        } ;&lt;/b&gt;

        &lt;span class=&quot;pl-c&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;//&lt;/span&gt; 새로운 스레드 실행 코드. 1초 단위로 현재 시각 표시 요청.&lt;/span&gt;
        &lt;b&gt;&lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;NewRunnable&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;Runnable&lt;/span&gt; {
            &lt;span class=&quot;pl-k&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;run&lt;/span&gt;() {
                &lt;span class=&quot;pl-k&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;) {

                    &lt;span class=&quot;pl-k&quot;&gt;try&lt;/span&gt; {
                        &lt;span class=&quot;pl-smi&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;sleep(&lt;span class=&quot;pl-c1&quot;&gt;1000&lt;/span&gt;);
                    } &lt;span class=&quot;pl-k&quot;&gt;catch&lt;/span&gt; (&lt;span class=&quot;pl-smi&quot;&gt;Exception&lt;/span&gt; e) {
                        e&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;printStackTrace() ;
                    }

                    mHandler&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;post(runnable) ;
                }
            }
        }

        &lt;span class=&quot;pl-smi&quot;&gt;NewRunnable&lt;/span&gt; nr &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;NewRunnable&lt;/span&gt;() ;
        &lt;span class=&quot;pl-smi&quot;&gt;Thread&lt;/span&gt; t &lt;span class=&quot;pl-k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Thread&lt;/span&gt;(nr) ;
        t&lt;span class=&quot;pl-k&quot;&gt;.&lt;/span&gt;start() ;&lt;/b&gt;
    }
}&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;44-실행-결과&quot;&gt;4.4 실행 결과.&lt;/h4&gt;
&lt;p&gt;예제 작성을 완료하고 실행하면, 현재 시각을 1초 마다 화면에 표시하는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998A143F5D10CC0506&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998A143F5D10CC0506&quot; width=&quot;700&quot; height=&quot;437&quot; alt=&quot;스레드 간 통신 적용 예제 실행 화면&quot; filename=&quot;thread_handler_runnable_example_screenshot.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;5-참고&quot;&gt;5. 참고.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;개발자 레시피 - 스레드 관련 항목.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/143&quot; title=&quot;[https://recipes4dev.tistory.com/143] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드(Android Thread)&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/150&quot; title=&quot;[https://recipes4dev.tistory.com/150] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드 예제. 스레드로 고민해보기. (Android Thread UseCase)&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;li&gt;[&lt;a href=&quot;https://recipes4dev.tistory.com/166&quot; title=&quot;[https://recipes4dev.tistory.com/166] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 스레드. 핸들러와 메시지. (Android Thread. Handler and Message.)&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;UI 스레드와 통신하기.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/training/multiple-threads/communicate-ui&quot; title=&quot;[https://developer.android.com/training/multiple-threads/communicate-ui] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 가이드. Communicate with the UI thread&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Thread에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/java/lang/Thread.html&quot; title=&quot;[https://developer.android.com/reference/java/lang/Thread.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Thread&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Runnable에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/java/lang/Runnable.html&quot; title=&quot;[https://developer.android.com/reference/java/lang/Runnable.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Runnable&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Looper에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/Looper.html&quot; title=&quot;[https://developer.android.com/reference/android/os/Looper.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Looper&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Handler에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/Handler.html&quot; title=&quot;[https://developer.android.com/reference/android/os/Handler.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Handler&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Message에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/Message.html&quot; title=&quot;[https://developer.android.com/reference/android/os/Message.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. Message&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MessageQueue에 대한 자세한 도움말.
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://developer.android.com/reference/android/os/MessageQueue.html&quot; title=&quot;[https://developer.android.com/reference/android/os/MessageQueue.html] 페이지로 이동합니다.&quot; rel=&quot;nofollow&quot;&gt;안드로이드 개발 참조문서. MessageQueue&lt;/a&gt;]을 참고하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.END.&lt;/p&gt;&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>ANDROID 프로그래밍/THREAD</category>
      <category>handler</category>
      <category>Handler Runnable</category>
      <category>post()</category>
      <category>postAtFrontOfQueue()</category>
      <category>postAtTime()</category>
      <category>postDelayed()</category>
      <category>Runnable 인터페이스</category>
      <category>스레드 통신</category>
      <category>안드로이드 스레드</category>
      <category>핸들러</category>
      <author>뽀따</author>
      <guid isPermaLink="true">https://recipes4dev.tistory.com/170</guid>
      <comments>https://recipes4dev.tistory.com/170#entry170comment</comments>
      <pubDate>Mon, 24 Jun 2019 22:26:10 +0900</pubDate>
    </item>
  </channel>
</rss>