<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>아키텍트를 꿈꾸며 - 에코지오</title>
    <link>https://ecogeo.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 14 Apr 2026 20:20:46 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>에코지오</managingEditor>
    <image>
      <title>아키텍트를 꿈꾸며 - 에코지오</title>
      <url>https://t1.daumcdn.net/cfile/tistory/2638C74458DB49BC17</url>
      <link>https://ecogeo.tistory.com</link>
    </image>
    <item>
      <title>제가 만든 'TV편성표' 안드로이드 앱 소개</title>
      <link>https://ecogeo.tistory.com/356</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;안녕하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;국내 주요 TV 채널의 방송프로그램 편성표를 한눈에 쉽게 확인할 수 있는 안드로이드 앱을 소개합니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;* 앱 이름 : TV편성표 &lt;br /&gt;* 앱 설치주소 : &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.gmail.ecogeo.tvschedule2&quot;&gt;https://play.google.com/store/apps/details?id=com.gmail.ecogeo.tvschedule2&lt;/a&gt;&lt;br /&gt;* 가격 : 무료&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;*주요&amp;nbsp;기능 &lt;br /&gt;ㅁ 즐겨찾는 채널의 편성정보를 모아서 보기(테이블형) &lt;br /&gt;-&amp;nbsp;한&amp;nbsp;화면에서&amp;nbsp;여러&amp;nbsp;채널의&amp;nbsp;편성정보를&amp;nbsp;한번에&amp;nbsp;확인 &lt;br /&gt;-&amp;nbsp;원하는&amp;nbsp;채널의&amp;nbsp;선택&amp;nbsp;및&amp;nbsp;정렬&amp;nbsp;지원 &lt;br /&gt;-&amp;nbsp;테이블의&amp;nbsp;가로축과&amp;nbsp;세로축&amp;nbsp;전환&amp;nbsp;가능 &lt;br /&gt;-&amp;nbsp;테이블&amp;nbsp;확대/축소&amp;nbsp;지원(두손가락을&amp;nbsp;벌리거나&amp;nbsp;오므리는&amp;nbsp;핀치줌&amp;nbsp;이용) &lt;br /&gt;-&amp;nbsp;현재&amp;nbsp;시간을&amp;nbsp;쉽게&amp;nbsp;확인하기&amp;nbsp;위한&amp;nbsp;막대표시 &lt;br /&gt;-&amp;nbsp;현재&amp;nbsp;방송&amp;nbsp;중인&amp;nbsp;프로그램은&amp;nbsp;색상을&amp;nbsp;다르게하여&amp;nbsp;쉽게&amp;nbsp;구분 &lt;br /&gt;-&amp;nbsp;현재&amp;nbsp;시간대&amp;nbsp;위치로&amp;nbsp;자동&amp;nbsp;스크롤 &lt;br /&gt;&lt;br /&gt;ㅁ&amp;nbsp;특정&amp;nbsp;채널의&amp;nbsp;편성정보만&amp;nbsp;보기(목록형) &lt;br /&gt;- 해당 채널의 편성정보를 목록형태로 표시 &lt;br /&gt;-&amp;nbsp;화면을&amp;nbsp;좌/우로&amp;nbsp;밀어서(스와이프)&amp;nbsp;다른날짜의&amp;nbsp;편성정보를&amp;nbsp;확인 &lt;br /&gt;-&amp;nbsp;현재&amp;nbsp;방송&amp;nbsp;중인&amp;nbsp;프로그램을&amp;nbsp;쉽게&amp;nbsp;구분 &lt;br /&gt;-&amp;nbsp;현재&amp;nbsp;시간대&amp;nbsp;위치로&amp;nbsp;자동&amp;nbsp;스크롤 &lt;br /&gt;&lt;br /&gt;ㅁ전체&amp;nbsp;채널목록&lt;br /&gt;-&amp;nbsp;채널이름이나&amp;nbsp;채널번호로&amp;nbsp;채널검색&lt;br /&gt;- 카테고리별로 채널목록 확인 &lt;br /&gt;-&amp;nbsp;핀치줌&amp;nbsp;동작으로&amp;nbsp;전체&amp;nbsp;카테고리를&amp;nbsp;접거나&amp;nbsp;펼칠&amp;nbsp;수&amp;nbsp;있음 &lt;br /&gt;- 방송서비스제공자 선택시 채널번호 자동입력 &lt;br /&gt;&lt;br /&gt;ㅁ&amp;nbsp;방송&amp;nbsp;알림예약 &lt;br /&gt;-&amp;nbsp;프로그램&amp;nbsp;시작&amp;nbsp;전&amp;nbsp;미리&amp;nbsp;알림을&amp;nbsp;받을&amp;nbsp;수&amp;nbsp;있음 &lt;br /&gt;-&amp;nbsp;알림&amp;nbsp;반복유형&amp;nbsp;:&amp;nbsp;한번만/매일반복/매주반복 &lt;br /&gt;-&amp;nbsp;알림시&amp;nbsp;진동/소리&amp;nbsp;등&amp;nbsp;상세설정&amp;nbsp;지원 &lt;br /&gt;-&amp;nbsp;알림시각&amp;nbsp;:&amp;nbsp;정각/5분전/10분전/30분전/1시간전 &lt;br /&gt;-&amp;nbsp;설정된&amp;nbsp;알림목록&amp;nbsp;보기 &lt;br /&gt;-&amp;nbsp;알림의&amp;nbsp;수정/삭제&amp;nbsp;가능 &lt;br /&gt;&lt;br /&gt;ㅁ&amp;nbsp;그외 &lt;br /&gt;-&amp;nbsp;프로그램&amp;nbsp;정보검색&amp;nbsp;:&amp;nbsp;네이버,&amp;nbsp;다음 &lt;br /&gt;-&amp;nbsp;프로그램&amp;nbsp;제목&amp;nbsp;글자크기&amp;nbsp;변경&amp;nbsp;가능 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;*제공&amp;nbsp;채널 &lt;br /&gt;-&amp;nbsp;지상파&amp;nbsp;:&amp;nbsp;KBS1,&amp;nbsp;KBS2,&amp;nbsp;MBC,&amp;nbsp;SBS,&amp;nbsp;EBS1,&amp;nbsp;EBS2&amp;nbsp;및&amp;nbsp;지역지상파&amp;nbsp;채널 &lt;br /&gt;-&amp;nbsp;종편&amp;nbsp;:&amp;nbsp;JTBC,&amp;nbsp;MBN,&amp;nbsp;채널A,&amp;nbsp;TV조선 &lt;br /&gt;-&amp;nbsp;케이블&amp;nbsp;:&amp;nbsp;약&amp;nbsp;230여&amp;nbsp;개의&amp;nbsp;채널&amp;nbsp;(채널은&amp;nbsp;계속해서&amp;nbsp;추가됩니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-112021.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bztoFF/btrfU3vqpFo/4QEGZBKL2Q84mn3SlKf5tK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bztoFF/btrfU3vqpFo/4QEGZBKL2Q84mn3SlKf5tK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bztoFF/btrfU3vqpFo/4QEGZBKL2Q84mn3SlKf5tK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbztoFF%2FbtrfU3vqpFo%2F4QEGZBKL2Q84mn3SlKf5tK%2Fimg.png&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-112021.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-112217.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCdM9i/btrfVsuAbo1/oZwEVQauWxdQixCAfWZyW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCdM9i/btrfVsuAbo1/oZwEVQauWxdQixCAfWZyW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCdM9i/btrfVsuAbo1/oZwEVQauWxdQixCAfWZyW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCdM9i%2FbtrfVsuAbo1%2FoZwEVQauWxdQixCAfWZyW1%2Fimg.png&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-112217.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-104826.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MU39f/btrfXxI5Cnb/CpHrXCOIAk4Uo8AENbEHlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MU39f/btrfXxI5Cnb/CpHrXCOIAk4Uo8AENbEHlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MU39f/btrfXxI5Cnb/CpHrXCOIAk4Uo8AENbEHlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMU39f%2FbtrfXxI5Cnb%2FCpHrXCOIAk4Uo8AENbEHlk%2Fimg.png&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-104826.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-105819.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clfyIa/btrfWM0NqIy/8yAUmHDZ8BG2HkBXEt13P1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clfyIa/btrfWM0NqIy/8yAUmHDZ8BG2HkBXEt13P1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clfyIa/btrfWM0NqIy/8yAUmHDZ8BG2HkBXEt13P1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclfyIa%2FbtrfWM0NqIy%2F8yAUmHDZ8BG2HkBXEt13P1%2Fimg.png&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-105819.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-105847.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4Nrly/btrfUPjW9UO/B2Bs9FauaC7c2XLRwIqw7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4Nrly/btrfUPjW9UO/B2Bs9FauaC7c2XLRwIqw7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4Nrly/btrfUPjW9UO/B2Bs9FauaC7c2XLRwIqw7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4Nrly%2FbtrfUPjW9UO%2FB2Bs9FauaC7c2XLRwIqw7k%2Fimg.png&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-105847.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-111459.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp0DRd/btrfU24mept/zZedCuvtQQhhSziK5Rk8HK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp0DRd/btrfU24mept/zZedCuvtQQhhSziK5Rk8HK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp0DRd/btrfU24mept/zZedCuvtQQhhSziK5Rk8HK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp0DRd%2FbtrfU24mept%2FzZedCuvtQQhhSziK5Rk8HK%2Fimg.png&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-111459.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-111554.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MYm7k/btrfVsPfsxI/wDDgV3IxnSegwCFgBiujqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MYm7k/btrfVsPfsxI/wDDgV3IxnSegwCFgBiujqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MYm7k/btrfVsPfsxI/wDDgV3IxnSegwCFgBiujqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMYm7k%2FbtrfVsPfsxI%2FwDDgV3IxnSegwCFgBiujqK%2Fimg.png&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-111554.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-111813.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K7dJ5/btrfXzmCJGZ/yK6trqgq4N0IdO9CPG6UFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K7dJ5/btrfXzmCJGZ/yK6trqgq4N0IdO9CPG6UFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K7dJ5/btrfXzmCJGZ/yK6trqgq4N0IdO9CPG6UFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK7dJ5%2FbtrfXzmCJGZ%2FyK6trqgq4N0IdO9CPG6UFk%2Fimg.png&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-111813.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-111826.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drpTg0/btrf5hZvQOb/aAcVqA8mY6Q5gRFP6OHLy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drpTg0/btrf5hZvQOb/aAcVqA8mY6Q5gRFP6OHLy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drpTg0/btrf5hZvQOb/aAcVqA8mY6Q5gRFP6OHLy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdrpTg0%2Fbtrf5hZvQOb%2FaAcVqA8mY6Q5gRFP6OHLy1%2Fimg.png&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;480&quot; data-filename=&quot;수정됨_device-2021-09-24-111826.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;많은 이용을 부탁드립니다.&amp;nbsp;&lt;br /&gt;감사합니다.&lt;/p&gt;</description>
      <category>Android/앱홍보</category>
      <category>TV편성표</category>
      <author>에코지오</author>
      <guid isPermaLink="true">https://ecogeo.tistory.com/356</guid>
      <comments>https://ecogeo.tistory.com/356#entry356comment</comments>
      <pubDate>Sun, 26 Sep 2021 12:31:46 +0900</pubDate>
    </item>
    <item>
      <title>Token 기반 자동 로그인 구현 예제</title>
      <link>https://ecogeo.tistory.com/353</link>
      <description>&lt;p&gt;여러분은 [로그인 유지] 또는 [자동 로그인] 기능을 어떻게 구현하시나요?&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;p&gt;ID/PW 기반 방식을 폐기하고 보안이 강화된 토큰(token) 기반 방식으로 변경&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;- 사용자 비밀번호를 단말기에 저장하지 않는다.&lt;/p&gt;&lt;p&gt;- (단말기) 해킹을 당한 경우 해킹여부를 쉽게 파악할 수 있다.&lt;/p&gt;&lt;p&gt;- 해킹을 당하더라도 사용자 비밀번호는 유출되지 않는다.&lt;/p&gt;&lt;p&gt;- 단말기 분실시 서버측에서 해당 인증세션을 무효화할 수 있다.&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://jaspan.com/improved_persistent_login_cookie_best_practice&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://jaspan.com/improved_persistent_login_cookie_best_practice&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://blog.naver.com/PostView.nhn?blogId=junhwen&amp;amp;logNo=130145534571&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://blog.naver.com/PostView.nhn?blogId=junhwen&amp;amp;logNo=130145534571&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/244882/what-is-the-best-way-to-implement-remember-me-for-a-website&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://stackoverflow.com/questions/244882/what-is-the-best-way-to-implement-remember-me-for-a-website&lt;/a&gt;&lt;/p&gt;</description>
      <category>Android</category>
      <author>에코지오</author>
      <guid isPermaLink="true">https://ecogeo.tistory.com/353</guid>
      <comments>https://ecogeo.tistory.com/353#entry353comment</comments>
      <pubDate>Tue, 28 May 2013 18:20:06 +0900</pubDate>
    </item>
    <item>
      <title>[안드로이드] Sonar를 통한 소스 품질분석용 Ant 빌드스크립트 예제</title>
      <link>https://ecogeo.tistory.com/352</link>
      <description>&lt;p&gt;&lt;a href=&quot;http://www.sonarsource.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Sonar&lt;/a&gt;를 통해 안드로이드 앱&amp;nbsp;소스코드의 품질을 분석하고자 하는 분을 위해 현재 제가 사용중인&amp;nbsp;Ant 빌드스크립트를 공유합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;처음에는 custom_rules.xml 파일에 소스분석 스크립트를 작성했었는데요, 별도의 스크립트(analysis.xml)로 분리시켰습니다. 앱 프로젝트 루트경로에 build.xml, local.properties, project.properties 파일 등과 함께 두시면 됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;[analysis.xml]&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(254, 137, 67); background-color: rgb(254, 222, 199); padding: 10px;&quot;&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;lt;project name=&quot;my-android-app-analysis&quot; default=&quot;sonar&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;lt;property file=&quot;local.properties&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;lt;property file=&quot;ant.properties&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;lt;loadproperties srcFile=&quot;project.properties&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;lt;fail message=&quot;sdk.dir is missing... &quot;&lt;/span&gt;&lt;span style=&quot;font-family: Verdana; font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; unless=&quot;sdk.dir&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;lt;import file=&quot;${sdk.dir}/tools/ant/build.xml&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;lt;taskdef uri=&quot;antlib:org.sonar.ant&quot; resource=&quot;org/sonar/ant/antlib.xml&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;classpath path=&quot;${ant.home}/lib/sonar-ant-task-2.0.jar&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;lt;/taskdef&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;lt;target name=&quot;sonar&quot;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;depends=&quot;-set-release-mode, -release-obfuscation-check, -compile&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; description=&quot;Sonar를 이용한 소스분석&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;xpath input=&quot;${manifest.abs.file}&quot;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;expression=&quot;/manifest/@android:versionName&quot;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;output=&quot;app.version.name&quot;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;default=&quot;1.0&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana; font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.host.url&quot; value=&quot;http://127.0.0.1:8888/sonar&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.jdbc.url&quot;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: Verdana; font-size: 9pt; line-height: 1.5;&quot;&gt;value=&quot;jdbc:h2:tcp://127.0.0.1:9092/sonar&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.jdbc.username&quot; value=&quot;sonar&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.jdbc.password&quot; value=&quot;sonar&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana; font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.projectKey&quot; value=&quot;${project.app.package}:my-android&lt;/span&gt;&lt;span style=&quot;font-family: Verdana; font-size: 9pt; line-height: 1.5;&quot;&gt;&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.projectName&quot; value=&quot;my-android&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.projectVersion&quot; value=&quot;${app.version.name}&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.java.source&quot; value=&quot;${java.source}&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.java.target&quot; value=&quot;${java.target}&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.sourceEncoding&quot; value=&quot;UTF-8&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.language&quot; value=&quot;java&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;!-- property name=&quot;sonar.sources&quot; value=&quot;${source.absolute.dir},${gen.absolute.dir}&quot; / --&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.sources&quot; value=&quot;${source.absolute.dir}&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.binaries&quot; value=&quot;${out.classes.absolute.dir}&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.libraries&quot; value=&quot;${project.target.android.jar},${jar.libs.dir}/*.jar&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;property name=&quot;sonar.scm.url&quot; value=&quot;scm:svn:svn://vcs.xxx.com/trunk/my-android&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;!-- 더많은&amp;nbsp;소나 파라미터 : http://docs.codehaus.org/display/SONAR/Analysis+Parameters --&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;sonar:sonar xmlns:sonar=&quot;antlib:org.sonar.ant&quot; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Verdana;&quot;&gt;&amp;nbsp; &amp;lt;/target&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;굵은 글씨로 나와있듯이&amp;nbsp;-set-release-mode, -release-obfuscation-check, -compile 이렇게 3개의 타겟이 미리 실행되도록 해야 문제없이 소스분석이 이루어집니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이렇게 만드시고 실제 수행은 Jenkins 같은 CI서버에서 수행하시면 지속적으로 소스코드 품질을 체크하실 수 있습니다.&amp;nbsp;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;저는 Jenkins 서버에 앱 소스분석용 Job을 만들고 아래와 같이 analysis.xml 빌드스크립트의 sonar 타겟을 &lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;실행하게 했습니다.(보통 며칠~몇주에 한번씩 수행하도록 설정)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&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: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/0253A74251A3192B18&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F0253A74251A3192B18&quot; width=&quot;800&quot; height=&quot;295&quot; filename=&quot;사용자 지정 1.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그러면 아래와 같이 sonar 대시보드 페이지에서 내 앱 소스의 품질지표를 확인할 수 있어서 참 좋습니다.&lt;/p&gt;&lt;p&gt;(부끄럽게도 junit 등의 단위테스트 케이스는 없어서 테스트 커버리지는 0 퍼센트네요 -.-)&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: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2619153D51A31A960F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2619153D51A31A960F&quot; width=&quot;800&quot; height=&quot;362&quot; filename=&quot;사용자 지정 2.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Android</category>
      <category>ANT</category>
      <category>jenkins</category>
      <category>SONAR</category>
      <category>소스품질</category>
      <category>스크립트</category>
      <category>안드로이드</category>
      <author>에코지오</author>
      <guid isPermaLink="true">https://ecogeo.tistory.com/352</guid>
      <comments>https://ecogeo.tistory.com/352#entry352comment</comments>
      <pubDate>Mon, 27 May 2013 17:36:16 +0900</pubDate>
    </item>
    <item>
      <title>[안드로이드] 기본 user agent 헤더 스트링 구하기</title>
      <link>https://ecogeo.tistory.com/351</link>
      <description>&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;WebView의 기본 User-Agent 구하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(193, 193, 193); background-color: rgb(238, 238, 238); padding: 10px;&quot;&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;String userAgent =&amp;nbsp;&lt;/span&gt;new WebView(context).getSettings().getUserAgentString();&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;&lt;b&gt;WebView의 user-agent 변경하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(193, 193, 193); background-color: rgb(238, 238, 238); padding: 10px;&quot;&gt;&lt;p&gt;webview.getSettings().setUserAgentString(&quot;변경된 스트링&quot;);&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&lt;b&gt;URLConnection의 기본 User-Agent 구하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(254, 137, 67); background-color: rgb(254, 222, 199); padding: 10px;&quot;&gt;&lt;p&gt;String userAgent = System.getProperty(&quot;http.agent&quot;);&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 10pt;&quot;&gt;URLConnection의 user-agent 변경하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(254, 137, 67); background-color: rgb(254, 222, 199); padding: 10px;&quot;&gt;&lt;p&gt;HttpURLConnection conn = ...;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;conn.setRequestProperty(&quot;User-Agent&quot;, &quot;변경된 스트링&quot;);&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/p&gt;&lt;p&gt;* 참고&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/3626071/retrieve-user-agent-programaticallyhttp://stackoverflow.com/questions/3626071/retrieve-user-agent-programatically&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://stackoverflow.com/questions/3626071/retrieve-user-agent-programatically&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://arabiannight.tistory.com/204&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://arabiannight.tistory.com/204&lt;/a&gt;&lt;/p&gt;</description>
      <category>Android</category>
      <category>urlconnection</category>
      <category>User Agent</category>
      <category>webview</category>
      <category>안드로이드</category>
      <author>에코지오</author>
      <guid isPermaLink="true">https://ecogeo.tistory.com/351</guid>
      <comments>https://ecogeo.tistory.com/351#entry351comment</comments>
      <pubDate>Thu, 23 May 2013 10:43:57 +0900</pubDate>
    </item>
    <item>
      <title>[안드로이드] AOP를 이용한 에러처리 사례</title>
      <link>https://ecogeo.tistory.com/349</link>
      <description>&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;안드로이드 앱 개발이 점점 성숙해지면서, 우리가 과거에 웹시스템을 개발하면서 했던 것처럼, 앱의 여러&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;위치에서 발생하는 에러를 한 곳에서 일관되게 처리할 수 있는 중앙집중식 에러처리 기능에 대한 인식과 요구가 늘어나고 있습니다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;지난 글에서는 안드로이드 앱에서 중앙집중화된 방식으로&amp;nbsp;에러를 처리하기 위해 Thread.UncaughtExceptionHandler 를 활용하는 방법을 살펴보았습니다. 유명한 오픈소스 에러리포트 라이브러리인 ACRA&amp;nbsp;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;(&lt;a href=&quot;https://github.com/ACRA/acra&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://github.com/ACRA/acra&lt;/a&gt;)도 내부적으로는&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;UncaughtExceptionHandler&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;를&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;이용하고 있는 것으로 알고있습니다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그러나!!!&amp;nbsp;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;UncaughtExceptionHandler를 이용하는&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;방법만 있는 것은 아닙니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;AOP(Aspect Oriented Programming) 기법을&amp;nbsp;통해서도 글로벌한&amp;nbsp;에러처리가 가능합니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;AOP를 통해서 다양한 곳에서 발생하는(throw) 에러를 자동으로 잡아내고(catch), 잡아낸 에러를 한 곳에서 처리(handle)할 수 있습니다. 실제로 저는 현재 서비스중인 앱에 이 방법을 적용하였습니다.(앱 개발 당시에 ACRA를 몰랐습니다... ㅠㅠ)&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;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px; width: 500px; height: 199px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2637A35051944C9C05&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2637A35051944C9C05&quot; width=&quot;500&quot; height=&quot;199&quot; filename=&quot;1.png&quot; filemime=&quot;image/jpeg&quot; style=&quot;width: 500px; height: 199px;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;1. 던져진 에러를 잡아내는 애스펙트&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;저의 경우 아래의 위치에서 던져진 에러를 자동으로 잡아내는&amp;nbsp;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;애스펙트 구현체&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;를 만들었습니다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;① Activity의 주요 라이프사이클 메소드&lt;/p&gt;&lt;p&gt;② 각종 이벤트 리스너 메소드&lt;/p&gt;&lt;p&gt;③ java.lang.Runnable 구현체의 run() 메소드&lt;/p&gt;&lt;p&gt;④ @ApplyExceptionHandler 어노테이션이 선언된 메소드&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;다음은&amp;nbsp;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;ExceptionCatcherAspect 구현 예제 코드입니다.(AspectJ&amp;nbsp;라이브러리 이용)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(193, 193, 193); background-color: rgb(238, 238, 238); padding: 10px;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;import org.aspectj.lang.ProceedingJoinPoint;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;import org.aspectj.lang.annotation.Around;&lt;/div&gt;&lt;div&gt;import org.aspectj.lang.annotation.Aspect;&lt;/div&gt;&lt;div&gt;import org.aspectj.lang.annotation.Pointcut;&lt;/div&gt;&lt;div&gt;... ...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;/**&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;* 다양한 곳에서 발생하는 에러를 잡아내기 위한 애스펙트.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;*/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;@Aspect&lt;/b&gt;&lt;/div&gt;&lt;div&gt;public class &lt;b&gt;ExceptionCatcherAspect &lt;/b&gt;{&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; @Inject&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; protected ExceptionHandler exceptionHandler;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; /** @IgnoreExceptionHandler 어노테이션이 붙은 메소드 및 &lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;ExceptionHandler 클래스에는 적용하지 않는다. */&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; @Pointcut(&quot; @annotation(my.IgnoreExceptionHandler) ||&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;within(my.ExceptionHandler+) &quot;)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; protected void ignore() {&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;/**&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; * Activity 하위 클래스의 주요 라이프사이클 메소드들.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; * &amp;nbsp;정확히 일치하지는 않을 수 있으며,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;onCreate(..), onResume(..) 등 주요 메소드만 포함됨&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; */&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; @Pointcut(&quot;within(android.app.Activity+) &amp;amp;&amp;amp; (execution(void onCreate(..)) || execution(void onStart())&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;|| execution(void onResume()) ||&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;execution(void onPause()) || execution(void onStop())&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;|| execution(void onRestart()) || execution(void onDestroy())&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;&quot;)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; protected void activityLifecycleMethods() {}&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; //TODO protected void fragmentLifecycleMethods() {}&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; /**&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; * 이벤트 리스너 메소드들.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; * On*Listener 형태의 리스너를 구현한 클래스의 on* 형태의 메소드.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; *&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;정확히 일치하지는 않을 수 있음.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; */&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; @Pointcut(&quot; within(android..On*Listener+) &amp;amp;&amp;amp; execution(!private !static * on*(..) throws !Exception)&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;amp;&amp;amp; !activityLifecycleMethods() &quot;)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; protected void eventListenerMethods() {&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; /**&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* Runnable 또는 Thread 및 하위 클래스의 run 메소드.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;*/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; @Pointcut(&quot; execution(public void java.lang.Runnable.run()) &quot;)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;protected&amp;nbsp;void runnableMethod() {&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; /**&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* 액티비티 생명주기 메소드에서 발생한 에러처리.&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;*/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; @Around(&quot; this(activity) &amp;amp;&amp;amp; !ignore() &amp;amp;&amp;amp; activityLifecycleMethods() &quot;)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; public Object &lt;b&gt;catchActivityException&lt;/b&gt;(final Activity activity, final ProceedingJoinPoint pjp) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; try {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return pjp.proceed();&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; } catch (final Throwable e) {&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; exceptionHandler.handleActivityException(activity, e);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // 정책에 따라 에러처리 후 액티비티를 종료하거나 말거나.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // activity.finish();&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return null;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; /**&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* 이벤트 리스너 메소드에서 발생한 에러처리.&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;*/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; @Around(&quot; !ignore() &amp;amp;&amp;amp; eventListenerMethods() &quot;)&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; public Object &lt;b&gt;catchListenerException&lt;/b&gt;(final ProceedingJoinPoint pjp) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; try {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return pjp.proceed();&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; } catch (final Throwable e) {&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; exceptionHandler.handleListenerException(e);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return null;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; /**&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* Runnable에서 발생한 에러처리.&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;*/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; @Around(&quot; !ignore() &amp;amp;&amp;amp; runnableMethod() &quot;)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; public void &lt;b&gt;catchRunnableException&lt;/b&gt;(final ProceedingJoinPoint pjp) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; try {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pjp.proceed();&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; } catch (final Throwable e) {&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; exceptionHandler.handleBackgroundException(e);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; /**&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* @ApplyExceptionHandler 어노테이션이 붙은&amp;nbsp;메소드에서 발생한 에러처리.&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;*/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; @Around(&quot; !ignore() &amp;amp;&amp;amp; @annotation(my.ApplyExceptionHandler) &quot;)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; public void &lt;b&gt;catchApplyExceptionHandler&lt;/b&gt;(final ProceedingJoinPoint pjp) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; try {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pjp.proceed();&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; } catch (final Throwable e) {&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; exceptionHandler.handle(e);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;에러가 발생한 위치(포인트컷)에 따라 &lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;다른 작업을 수행하는 것을 볼 수 있습니다. 액티비티 생명주기 메소드에서 던져진 에러인 경우에는 ExceptionHandler의&amp;nbsp;&lt;/span&gt;handleActivityException()를 호출하고, 이벤트리스너에서 던져진 에러의 경우에는&amp;nbsp;handleListenerException() 메소드를 호출하는 식입니다. 물론 에러처리 정책에 따라서 동일하게 작업을 수행하는 것도 가능하겠죠.&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;참고로, 위 예제에서는 모두 Around 어드바이스를 사용하고 있는데요, AfterThrowing&amp;nbsp;어드바이스를 이용할 수도 있습니다.&amp;nbsp;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;AfterThrowing&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;어드바이스를 이용한다면&amp;nbsp;에러를 처리하고나서도,&amp;nbsp;caller에 exception이&amp;nbsp;그대로 다시 전달됩니다. 캐치되지 않은 exception이라면&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;결국 Thread.UncaughtExceptionHandler에 의해 처리 되겠죠.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;이러한 에러처리 애스펙트를 적용하면, 앱 개발시 메소드마다 일일이 try~catch 문으로 에러를 잡아낼&amp;nbsp;필요가 없습니다. 컴파일시에&amp;nbsp;ExceptionCatcherAspect가 자동으로 try~catch를 삽입해주기&amp;nbsp;때문이죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;상황에 따라서 예외케이스가 있기 때문에 애스펙트가 적용되지 않기를 원하는 메소드에는, 예를들어&amp;nbsp;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;@IgnoreExceptionHandler 어노테이션을 붙일 수 있다는 것도 참고하시기 바랍니다.(IgnoreExceptionHandler와 ApplyExceptionHandler는 단순&amp;nbsp;어노테이션이므로 소스코드는 생략합니다)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;2. 잡아낸 에러를 처리하는 ExceptionHandler&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;에러를 잡아내는 것은 AOP를 이용하고 있지만, 실제로 무슨 작업&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;을 할 것인지의 내용은&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;별도의&amp;nbsp;ExceptionHandler 클래스 등에서 구현하는 것이 좋습니다.&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;ExceptionHandler에서는&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;아래와 같은 작업을 수행할 수 있을 것입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: square;&quot;&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;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(159, 211, 49); background-color: rgb(231, 253, 181); padding: 10px;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;import android.app.Activity;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;import android.content.Context;&lt;/div&gt;&lt;div&gt;import android.util.Log;&lt;/div&gt;&lt;div&gt;import android.widget.Toast;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;import com.google.inject.Inject;&lt;/div&gt;&lt;div&gt;import com.google.inject.Singleton;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;/**&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;* 에러처리 핸들러.(인터페이스와 구현체로 분리해도 됩니다)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;*/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;@Singleton&lt;/div&gt;&lt;div&gt;public class &lt;b&gt;ExceptionHandler&amp;nbsp;&lt;/b&gt;{&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; @Inject&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; protected Context applicationContext;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; protected void handle(Context context, Throwable t) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // 에러타입 t 에 해당하는 사용자 메시지 선택(ErrorMessageFinder 같은 별도 클래스 만드는 것 권장)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; String message = &quot;...&quot;;&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // exception 타입에 따라 아래 작업도 선택적으로 수행 가능.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; doLogging(context, t, message);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; doMessage(context, t, message);&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; doReport(context, t, message);&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // 그외 에러처리&amp;nbsp;작업 수행.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // 예를들어 exception 타입이 AuthenticationException 같은 것이라면,&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // 여기서 자동으로 로그인 액티비티로 이동하게 할 수 있음.&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; public void handle(Throwable t) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; handle(applicationContext, t);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; / ** 액티비티 생명주기 메소드에서 던져진 에러 처리. */&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; public void &lt;b&gt;handleActivityException&lt;/b&gt;(Activity activity, Throwable t) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; handle(activity, t);&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; //&amp;nbsp;여기서 액티비티를 종료하는 것도 가능.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; / ** 이벤트 리스너&amp;nbsp;메소드에서 던져진 에러 처리. */&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; public void &lt;b&gt;handleListenerException&lt;/b&gt;(Throwable t) {&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; handle(&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // 기타 작업&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; / ** 백그라운드 작업&amp;nbsp;메소드에서 던져진 에러 처리. */&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; public void &lt;b&gt;handleBackgroundException&lt;/b&gt;(Throwable t) {&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; handle(&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // 기타 작업&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; /**&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* 에러정보를 로그에 기록한다.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;*/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; protected void &lt;b&gt;doLogging&lt;/b&gt;(Context context, Throwable t, String message) {&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // 에러정보를 로깅&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // exception 타입에 따라 에러정보를 간략히 또는 상세히 로깅하거나 다른 레벨에 로깅&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; /**&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* 사용자에게 적절한 에러메시지를 보여준다.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* &lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;exception.getMessage() 같은 테크니컬한 내용을&amp;nbsp;보여주지 말 것.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;*/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; @UiThread&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; protected void &lt;b&gt;doMessage&lt;/b&gt;(Context context, Throwable t, String message) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // UI쓰레드에서 Toast 또는 Dialog 형태로 메시지를 출력.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // context가 액티비티 컨텍스트인 경우 Dialog를 띄울 수 있음&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; /**&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* 에러정보를 서버로 전송한다.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;*/&lt;/div&gt;&lt;div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; protected void &lt;b&gt;doReport&lt;/b&gt;(Context context, Throwable t, String message) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // 에러 정보 및 발생 환경(디바이스 정보 등)을&amp;nbsp;서버로 전송&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;위 ExceptionHandler 예제코드는 특별히 어려운 내용이 없으므로 상세한 설명은 하지 않겠습니다.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;제 생각에 AOP를 이용한 에러처리 방법이 Thread.UncaughtExceptionHandler를 이용한 방법보다 나은 점은 다음과 같습니다.&lt;/div&gt;&lt;ul style=&quot;list-style-type: square;&quot;&gt;&lt;li&gt;에러가 던져지는 위치(포인트컷)에 따라 다른 방식의 에러처리를 유연하게 적용할 수 있다.&lt;/li&gt;&lt;li&gt;액티비티(UI쓰레드)에서 던져진 에러인 경우에도 굳이 해당 액티비티를 종료하지 않아도 된다.&lt;/li&gt;&lt;li&gt;잡아낸 에러를 부모(caller)에 다시 던질 수도 있고, 던지지 않을 수도 있다.&lt;/li&gt;&lt;li&gt;심지어 에러를 변환해서 다시 던지는 것도 가능하다.&lt;/li&gt;&lt;li&gt;Runtime Exception뿐 아니라 checked exception도 잡아서 처리할 수 있&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;다.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;반면, 단점도 있겠죠.&amp;nbsp;&lt;/div&gt;&lt;ul style=&quot;list-style-type: square;&quot;&gt;&lt;li&gt;AOP(AspectJ)에 대한 학습부담이 있고, 추가적인&amp;nbsp;개발환경 세팅이 필요하다.&lt;/li&gt;&lt;li&gt;포인트컷을 꼼꼼하게 작성하지 않은 경우 캐치하지 못한 에러가 있을 수 있다.&lt;/li&gt;&lt;li&gt;이미 컴파일된 클래스/라이브러리에는 적용할 수 없다.&lt;/li&gt;&lt;li&gt;적용되는 메소드에 대해서 컴파일시 try/catch 코드가 추가되므로 클래스 용량이 살짝 증가한다.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;</description>
      <category>Android</category>
      <category>AOP</category>
      <category>AspectJ</category>
      <category>안드로이드</category>
      <category>에러처리</category>
      <author>에코지오</author>
      <guid isPermaLink="true">https://ecogeo.tistory.com/349</guid>
      <comments>https://ecogeo.tistory.com/349#entry349comment</comments>
      <pubDate>Wed, 15 May 2013 19:51:49 +0900</pubDate>
    </item>
    <item>
      <title>[안드로이드] Thread.UncaughtExceptionHandler 사용팁</title>
      <link>https://ecogeo.tistory.com/350</link>
      <description>&lt;p&gt;&lt;/p&gt;&lt;p&gt;최근에 안드로이드에서 글로벌한 방법으로 에러를 처리하는 방법에는 어떤 것이 있는지 찾아보다가&amp;nbsp;우연히 java.lang.Thread.UncaughtExceptionHandler 인터페이스에 대해서 알게됐습니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(193, 193, 193); background-color: rgb(238, 238, 238); padding: 10px;&quot;&gt;&lt;p&gt;Thread.setDefaultUncaughtExceptionHandler(new My&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;UncaughtExceptionHandler&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;());&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;public class&amp;nbsp;My&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;UncaughtExceptionHandler&amp;nbsp;&lt;/span&gt;implements UncaughtExceptionHandler {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @Override&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; public void uncaughtException(Thread thread, final Throwable ex) {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// 여기서 에러를 처리&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;위와 같은 코드를 통해서 캐치되지 않은 런타임&amp;nbsp;exception을 일관된 방식으로 한곳에서 처리할 수 있도록 JDK 5.0부터 추가된 것이더군요.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;안드로이드에서도 위 방법을 사용하는 것이 가능한데요,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;UncaughtExceptionHandler&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;구현시 도움이 될만한 팁을&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;공유합니다.&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;span style=&quot;font-size: 12pt;&quot;&gt;&lt;b&gt;1. uncaughtException() 메소드의 맨 마지막에는 반드시 System.exit()를 호출해야 한다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;그렇지 않으면 앱은 죽은 것도 아니고 작동하는 것도 아닌 불확실한 상태가 됩니다(백그라운드 쓰레드에서 던져진&amp;nbsp;exception인 경우에는 예외???).&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/13416879/show-a-dialog-in-thread-setdefaultuncaughtexceptionhandler&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://stackoverflow.com/questions/13416879/show-a-dialog-in-thread-setdefaultuncaughtexceptionhandler&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/11281182/setdefaultuncaughtexceptionhandler-makes-app-crash-silently&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://stackoverflow.com/questions/11281182/setdefaultuncaughtexceptionhandler-makes-app-crash-silently&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;참고로, ACRA의 경우에는 아래와 같은 코드를 사용하고 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(243, 197, 52); background-color: rgb(254, 254, 184); padding: 10px;&quot;&gt;&lt;p&gt;android.os.Process.killProcess(android.os.Process.myPid());&lt;/p&gt;&lt;p&gt;System.exit(10);&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;&lt;b&gt;2. Toast를 띄우려면 명시적으로 UI쓰레드에서 띄워야 한다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;그리고 사용자가 토스트 메시지를 읽을 수 있게 잠깐 쓰레드를 쉬는 것이 좋습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/11609640/toast-not-showing-up-in-uncaughtexceptionhandler&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://stackoverflow.com/questions/11609640/toast-not-showing-up-in-uncaughtexceptionhandler&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(254, 137, 67); background-color: rgb(254, 222, 199); padding: 10px;&quot;&gt;&lt;p&gt;&lt;p&gt;new Thread() {&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;@Override&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;public void run() {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // UI쓰레드에서 토스트 뿌림&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;		&lt;/span&gt;Looper.prepare();&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;		&lt;/span&gt;Toast.makeText(getApplicationContext(), &quot;에러메시지&quot;, Toast.LENGTH_SHORT)&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;				&lt;/span&gt;.show();&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;		&lt;/span&gt;Looper.loop();&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;}&lt;/p&gt;&lt;p&gt;}.start();&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;// 쓰레드 잠깐 쉼&lt;/p&gt;&lt;p&gt;try {&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;Thread.sleep(2000);&lt;/p&gt;&lt;p&gt;} catch (InterruptedException e) {&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;android.os.Process.killProcess(android.os.Process.myPid());&lt;/p&gt;&lt;p&gt;&amp;nbsp;System.exit(10);&lt;/p&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;3. Dialog&lt;/span&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;를 띄우려면 Dialog 테마를 가진 새로운 액티비티를 시작하면 된다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;(잘 안되는 경우 ACRA 소스를 참조.&amp;nbsp;Intent.FLAG_ACTIVITY_NEW_TASK 플래그 추가하여 액티비티 시작).&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;a href=&quot;http://stackoverflow.com/questions/13416879/show-a-dialog-in-thread-setdefaultuncaughtexceptionhandler&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://stackoverflow.com/questions/13416879/show-a-dialog-in-thread-setdefaultuncaughtexceptionhandler&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://lky1001.tistory.com/45&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://lky1001.tistory.com/45&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(159, 211, 49); background-color: rgb(231, 253, 181); padding: 10px;&quot;&gt;&lt;p&gt;Intent crashedIntent = new Intent(getApplicationContext(), MyErrorMessageDialogActivity.class);&lt;/p&gt;&lt;p&gt;crashedIntent.putExtra(&quot;error.message&quot;, &quot;에러메시지&quot;);&lt;/p&gt;&lt;p&gt;crashedIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);&lt;/p&gt;&lt;p&gt;startActivity(crashedIntent);&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;		&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(121, 165, 228); background-color: rgb(219, 232, 251); padding: 10px;&quot;&gt;&lt;p&gt;&amp;lt;activity&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;android:name=&quot;.MyErrorMessageDialogActivity&quot;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;android:excludeFromRecents=&quot;true&quot;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;android:finishOnTaskLaunch=&quot;true&quot;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;android:launchMode=&quot;singleInstance&quot;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;android:theme=&quot;@android:style/Theme.Dialog&quot; &amp;gt;&lt;/p&gt;&lt;p&gt;&amp;lt;/activity&amp;gt;&lt;/p&gt;&lt;/div&gt;&lt;div style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;그런데 Toast 띄우는 것과는 다르게 Dialog 띄우는 것은 exception이&amp;nbsp;UI 쓰레드에서 던져진 것인지&amp;nbsp;백그라운드 쓰레드에서 던져진 것인지에 따라 다르게 처리해주어야 할 것으로 보입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;실제로 ACRA 라이브러리의 경우&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;ReportingInteractionMode.DIALOG 모드로 설정했더라도 백그라운드 쓰레드에서 발생한 에러에 대해서는 dialog가&amp;nbsp;띄워지지 않았습니다(&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;System.exit() 때문?)&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;예를들어, UI쓰레드에서 던져진 exception인 경우에는 현재 액티비티를 바로 종료하고, 백그라운드 쓰레드에서 던져진 경우에는 현재&amp;nbsp;액티비티 화면을 그대로 살려두고 싶다면 아래와 같이 System.exit()를 선택적으로 호출할 수 있습니다.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(193, 193, 193); background-color: rgb(238, 238, 238); padding: 10px;&quot;&gt;&lt;div&gt;if (&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;Thread.currentThread() ==&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;Looper.getMainLooper().getThread() ) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;android.os.Process.killProcess(android.os.Process.myPid());&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;System.exit(10);&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;4. 앱 종료된 후 앱을 자동으로 재시작하고 싶으면 AlarmManager를 이용한다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.kmshack.kr/277#.UZCNP4Ez3E0&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://www.kmshack.kr/277#.UZCNP4Ez3E0&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/8943288/how-to-implement-uncaughtexception-android&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://stackoverflow.com/questions/8943288/how-to-implement-uncaughtexception-android&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;</description>
      <category>Android</category>
      <category>setDefaultUncaughtExceptionHandler</category>
      <category>Thread.UncaughtExceptionHandler</category>
      <category>안드로이드</category>
      <category>에러처리</category>
      <author>에코지오</author>
      <guid isPermaLink="true">https://ecogeo.tistory.com/350</guid>
      <comments>https://ecogeo.tistory.com/350#entry350comment</comments>
      <pubDate>Tue, 14 May 2013 14:49:59 +0900</pubDate>
    </item>
    <item>
      <title>greenrobot EventBus를 써보니...</title>
      <link>https://ecogeo.tistory.com/347</link>
      <description>&lt;p&gt;최근에 Sonar를 이용해서 회사에서 만든 안드로이드 앱 소스의 품질을 분석한 적이 있습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&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: 500px; width: 500px; height: 147px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/0302B338517A35EB1F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F0302B338517A35EB1F&quot; width=&quot;500&quot; height=&quot;147&quot; filename=&quot;2.png&quot; filemime=&quot;image/jpeg&quot; style=&quot;width: 500px; height: 147px;&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;나름 잘 만들었다고 생각하고 있었는데 규칙 위반사항이 꽤 많이 검출되어 놀랐었죠. 다행히 중복코드는 없었습니다.&amp;nbsp;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;Major한 위반사항부터 고쳐나가다가&amp;nbsp;패키지간 의존성을 없애기 위해 어떻게 하면 좋을까 고민을 많이 했습니다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;단순히 다른 Activity를 명시적으로 클래스명으로 부르지 않고 인텐트필터를 이용해서 부른다고 패키지간 의존성이 명쾌히 해소되지는 않더군요.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;그러다가 EventBus라는 라이브러리를 발견했습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;p&gt;EventBus 홈페이지&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/greenrobot/EventBus&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://github.com/greenrobot/EventBus&lt;/a&gt;&lt;a href=&quot;https://github.com/greenrobot/EventBus&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;&amp;nbsp;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;EventBus 사용 예제 설명&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://awalkingcity.com/blog/2013/02/26/productive-android-eventbus/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://awalkingcity.com/blog/2013/02/26/productive-android-eventbus/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;EventBus 슬라이드 자료&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.slideshare.net/greenrobot/eventbus-for-android-15314813&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://www.slideshare.net/greenrobot/eventbus-for-android-15314813&lt;/a&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;Square에서 만든 Otto라는 원조(?)&amp;nbsp;라이브러리도 있지만 greenrobot의 EventBus가 왠지 더 땡기더군요.&amp;nbsp;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;사용법도 심플하고, 홈페이지에 나오는 Otto와의 비교자료가 마음을 굳히게 만들었죠. (바빠서 직접 비교 테스트는 패스~)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;특히나 저희 앱에서는 로그인, 로그아웃 관련해서 단순히 세션을 조작하는데 그치지 않고 앱 내부적으로 다양한 일을 처리합니다. 그래서 로그인 모듈에서 로그인 완료후 다른 모듈들을 직접(!) 호출하는 방식으로 처리하고 있었는데, LoggedInEvent, LoggedOutEvent라는 걸 만들어서 이벤트버스 방식으로 변경했더니 모듈간 의존성도 없어지고&amp;nbsp;소스도 깔끔해지고 좋네요.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;물론 별별 상황에서 제대로 안정적으로 오류없이 작동하는지는 좀더 지켜봐야겠지만 현재까지는 만족하고 있습니다. 구글링해보면 사실&amp;nbsp;Otto가 더 많은 레퍼런스와 개발자의 지지를 받는 것으로 보입니다. Square 개발자의 기술력을 신뢰하기 때문으로 보이는데요, 여유가 생기면 Otto로도 재구현해서 테스트해볼 생각입니다. (EventBus의 컨벤션 방식과 비교해서&amp;nbsp;Otto의 어노테이션 방식도 나름 장점이 있기에...)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아직까지 EventBus 사용하면서 큰 이슈는 없었는데요 이런 점은 고려하셔야 합니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;(1) 이벤트를 수신하는 메소드가 컨벤션에 따라서 onEventMainThread(), onEventBackgroundThread() 와 같은 식이어서 만약 상속관계에 있는 클래스에서 동일한 메소드 시그너쳐를 쓴다면 부모 클래스의 메소드를 호출하는 것을 빼먹으면 안됩니다. 이런 경우는 Otto의 어노테이션 방식이 좀더 유연해보입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;(2) 이벤트를 어디서 던지고 어디에서 처리할 것인지 아키텍처적으로 정하는 일이 필요해보입니다. 그냥 아무데서나 이벤트 발생시키고 아무데서나 처리하는 것보다는 Presentation 레이어 던지고 처리한다거나, Biz 레이어에서 던지고 처리한다 처럼 어떤 규칙을 정해놓고 개발하는 것이 나을듯합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Android</category>
      <category>EventBus</category>
      <category>greenrobot</category>
      <category>otto</category>
      <category>안드로이드</category>
      <category>이벤트</category>
      <author>에코지오</author>
      <guid isPermaLink="true">https://ecogeo.tistory.com/347</guid>
      <comments>https://ecogeo.tistory.com/347#entry347comment</comments>
      <pubDate>Fri, 26 Apr 2013 17:28:05 +0900</pubDate>
    </item>
    <item>
      <title>저희회사 앱에 사용된 라이브러리</title>
      <link>https://ecogeo.tistory.com/346</link>
      <description>&lt;p&gt;작년 하반기에 제가 다니는 회사에서 쇼핑 관련된&amp;nbsp;앱을 하나 만들었습니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;사실 대부분의 기능이 웹으로 구현된 터라 실제 네이티브 앱으로 구현된 기능은 별로 없는(?) 편입니다.&lt;/p&gt;&lt;p&gt;그런데도 사용하는 라이브러리가 참 많다는 생각이 드네요.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;table border=&quot;0&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; width=&quot;754&quot; style=&quot;border-collapse: collapse; width: 754px;&quot;&gt;
 &lt;colgroup&gt;&lt;col width=&quot;238&quot; style=&quot;mso-width-source:userset;width:178pt&quot;&gt;
 &lt;col width=&quot;337&quot; style=&quot;mso-width-source:userset;width:253pt&quot;&gt;
 &lt;/colgroup&gt;&lt;tbody&gt;&lt;tr height=&quot;36&quot; style=&quot;mso-height-source:userset;height:27.32pt&quot;&gt;
  &lt;td height=&quot;36&quot; class=&quot;oa1&quot; width=&quot;238&quot; style=&quot;height: 37px; width: 207px; background-color: rgb(95, 142, 239); border-color: rgb(95, 142, 239) rgb(209, 223, 250) rgb(95, 142, 239) rgb(95, 142, 239); border-width: 1px; border-style: solid; color: rgb(255, 255, 255);&quot;&gt;
  &lt;p style=&quot;language:ko;margin-top:0pt;margin-bottom:0pt;margin-left:0in;
  text-align:center;direction:ltr;unicode-bidi:embed;mso-line-break-override:
  none;word-break:break-hangul;punctuation-wrap:hanging&quot;&gt;&lt;span style=&quot;font-size: 11pt; font-family: '맑은 고딕'; color: white;&quot;&gt;라이브러리&lt;/span&gt;&lt;span style=&quot;font-size: 11pt; font-family: '맑은 고딕'; color: white;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;
  &lt;/td&gt;
  &lt;td class=&quot;oa1&quot; width=&quot;337&quot; style=&quot;width: 362px; background-color: rgb(95, 142, 239); border-bottom-color: rgb(95, 142, 239); border-top-color: rgb(95, 142, 239); border-right-color: rgb(209, 223, 250); border-bottom-width: 1px; border-top-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-top-style: solid; border-right-style: solid; height: 37px; color: rgb(255, 255, 255);&quot;&gt;
  &lt;p style=&quot;language:ko;margin-top:0pt;margin-bottom:0pt;margin-left:0in;
  text-align:center;direction:ltr;unicode-bidi:embed;mso-line-break-override:
  none;word-break:break-hangul;punctuation-wrap:hanging&quot;&gt;&lt;span style=&quot;font-size: 11pt; font-family: '맑은 고딕'; color: white;&quot;&gt;용도&lt;/span&gt;&lt;span style=&quot;font-size: 11pt; font-family: '맑은 고딕'; color: white;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;
  &lt;/td&gt;&lt;td class=&quot;oa1&quot; width=&quot;337&quot; style=&quot;width: 194px; background-color: rgb(95, 142, 239); border-bottom-color: rgb(95, 142, 239); border-top-color: rgb(95, 142, 239); border-right-color: rgb(95, 142, 239); border-bottom-width: 1px; border-top-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-top-style: solid; border-right-style: solid; height: 37px; color: rgb(255, 255, 255);&quot; colspan=&quot;1&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: 11pt; font-family: Dotum, 돋움;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-size: 11pt; font-family: Dotum, 돋움;&quot;&gt;&amp;nbsp;대안&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;text-align: center; height: 37px;&quot;&gt;&lt;span style=&quot;font-size: 11pt; font-family: Dotum, 돋움;&quot;&gt;
 &lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: 11pt; font-family: Dotum, 돋움;&quot;&gt;
 &lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr height=&quot;36&quot; style=&quot;mso-height-source:userset;height:27.32pt&quot;&gt;
  &lt;td height=&quot;36&quot; class=&quot;oa2&quot; width=&quot;238&quot; style=&quot;height: 37px; width: 207px; background-color: rgb(239, 239, 255); border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-left-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-left-width: 1px; border-bottom-style: solid; border-right-style: solid; border-left-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;&lt;span style=&quot;font-size: 11pt; font-family: Dotum, 돋움;&quot;&gt;
  &lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; vertical-align: middle; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;Roboguice&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;
  &lt;td class=&quot;oa3&quot; width=&quot;337&quot; style=&quot;width: 362px; background-color: rgb(239, 239, 255); height: 37px; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;객체 의존성 &lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;주입&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black; vertical-align: baseline;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black; vertical-align: baseline;&quot;&gt;모듈 생명주기 관리&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;oa3&quot; width=&quot;337&quot; style=&quot;width: 194px; background-color: rgb(239, 239, 255); height: 37px; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot; colspan=&quot;1&quot;&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&amp;nbsp;AndroidAnnotations, Dagger&lt;/span&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr height=&quot;36&quot; style=&quot;mso-height-source:userset;height:27.32pt&quot;&gt;
  &lt;td height=&quot;36&quot; class=&quot;oa4&quot; width=&quot;238&quot; style=&quot;height: 37px; width: 207px; background-color: transparent; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-left-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-left-width: 1px; border-bottom-style: solid; border-right-style: solid; border-left-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; vertical-align: middle; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;AspectJ&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;
  &lt;td class=&quot;oa5&quot; width=&quot;337&quot; style=&quot;width: 362px; background-color: transparent; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0); height: 37px;&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;에러 처리&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;어노테이션 처리&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
, 아키텍처룰 체크&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;oa5&quot; width=&quot;337&quot; style=&quot;width: 194px; background-color: transparent; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0); height: 37px;&quot; colspan=&quot;1&quot;&gt;&lt;p&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr height=&quot;36&quot; style=&quot;mso-height-source:userset;height:27.32pt&quot;&gt;
  &lt;td height=&quot;36&quot; class=&quot;oa6&quot; width=&quot;238&quot; style=&quot;height: 27.32pt; width: 207px; background-color: rgb(239, 239, 255); border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-left-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-left-width: 1px; border-bottom-style: solid; border-right-style: solid; border-left-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; vertical-align: middle; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;Spring Android&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
(RestTemplate)&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;
  &lt;td class=&quot;oa7&quot; width=&quot;337&quot; style=&quot;width: 362px; background-color: rgb(239, 239, 255); border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;REST &lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;통신&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;oa7&quot; width=&quot;337&quot; style=&quot;width: 194px; background-color: rgb(239, 239, 255); border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot; colspan=&quot;1&quot;&gt;&lt;p&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&amp;nbsp;retrofit, restlet&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr height=&quot;36&quot; style=&quot;mso-height-source:userset;height:27.32pt&quot;&gt;
  &lt;td height=&quot;36&quot; class=&quot;oa4&quot; width=&quot;238&quot; style=&quot;height: 27.32pt; width: 207px; background-color: transparent; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-left-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-left-width: 1px; border-bottom-style: solid; border-right-style: solid; border-left-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; vertical-align: middle; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;Jackson Json&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;
  &lt;td class=&quot;oa5&quot; width=&quot;337&quot; style=&quot;width: 362px; background-color: transparent; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;JSON-Object &lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;매핑&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;oa5&quot; width=&quot;337&quot; style=&quot;width: 194px; background-color: transparent; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot; colspan=&quot;1&quot;&gt;&lt;p&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&amp;nbsp;Gson&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr height=&quot;36&quot; style=&quot;mso-height-source:userset;height:27.32pt&quot;&gt;
  &lt;td height=&quot;36&quot; class=&quot;oa6&quot; width=&quot;238&quot; style=&quot;height: 27.32pt; width: 207px; background-color: rgb(239, 239, 255); border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-left-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-left-width: 1px; border-bottom-style: solid; border-right-style: solid; border-left-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; vertical-align: middle; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;Simple Xml&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;
  &lt;td class=&quot;oa7&quot; width=&quot;337&quot; style=&quot;width: 362px; background-color: rgb(239, 239, 255); border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;XML-Object &lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;매핑&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;oa7&quot; width=&quot;337&quot; style=&quot;width: 194px; background-color: rgb(239, 239, 255); border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot; colspan=&quot;1&quot;&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr height=&quot;36&quot; style=&quot;mso-height-source:userset;height:27.32pt&quot;&gt;
  &lt;td height=&quot;36&quot; class=&quot;oa4&quot; width=&quot;238&quot; style=&quot;height: 27.32pt; width: 207px; background-color: transparent; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-left-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-left-width: 1px; border-bottom-style: solid; border-right-style: solid; border-left-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; vertical-align: middle; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;EventBus&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;
  &lt;td class=&quot;oa5&quot; width=&quot;337&quot; style=&quot;width: 362px; background-color: transparent; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;모듈간 의존성 제거&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;oa5&quot; width=&quot;337&quot; style=&quot;width: 194px; background-color: transparent; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot; colspan=&quot;1&quot;&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&amp;nbsp;Otto&lt;/span&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr height=&quot;36&quot; style=&quot;mso-height-source:userset;height:27.32pt&quot;&gt;
  &lt;td height=&quot;36&quot; class=&quot;oa6&quot; width=&quot;238&quot; style=&quot;height: 37px; width: 207px; background-color: rgb(239, 239, 255); border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-left-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-left-width: 1px; border-bottom-style: solid; border-right-style: solid; border-left-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; vertical-align: middle; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;Spring Security&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;
  &lt;td class=&quot;oa7&quot; width=&quot;337&quot; style=&quot;width: 362px; background-color: rgb(239, 239, 255); border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0); height: 37px;&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;데이터 암복호화&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;oa7&quot; width=&quot;337&quot; style=&quot;width: 194px; background-color: rgb(239, 239, 255); border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0); height: 37px;&quot; colspan=&quot;1&quot;&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr height=&quot;36&quot; style=&quot;mso-height-source:userset;height:27.32pt&quot;&gt;
  &lt;td height=&quot;36&quot; class=&quot;oa4&quot; width=&quot;238&quot; style=&quot;height: 27.32pt; width: 207px; background-color: transparent; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-left-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-left-width: 1px; border-bottom-style: solid; border-right-style: solid; border-left-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; vertical-align: middle; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;Zbar&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;
  &lt;td class=&quot;oa5&quot; width=&quot;337&quot; style=&quot;width: 362px; background-color: transparent; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(209, 223, 250); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;QR&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;코드 리더&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;oa5&quot; width=&quot;337&quot; style=&quot;width: 194px; background-color: transparent; border-bottom-color: rgb(209, 223, 250); border-right-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot; colspan=&quot;1&quot;&gt;&lt;p&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&amp;nbsp;zxing&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr height=&quot;36&quot; style=&quot;mso-height-source:userset;height:27.32pt&quot;&gt;
  &lt;td height=&quot;36&quot; class=&quot;oa6&quot; width=&quot;238&quot; style=&quot;height: 27.32pt; width: 207px; background-color: rgb(239, 239, 255); border-right-color: rgb(209, 223, 250); border-bottom-color: rgb(95, 142, 239); border-left-color: rgb(95, 142, 239); border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; vertical-align: middle; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;GCMClient&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;
  &lt;td class=&quot;oa7&quot; width=&quot;337&quot; style=&quot;width: 362px; background-color: rgb(239, 239, 255); border-bottom-color: rgb(95, 142, 239); border-right-color: rgb(209, 223, 250); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot;&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;p style=&quot;margin-top: 0pt; margin-bottom: 0pt; margin-left: 2em; direction: ltr; unicode-bidi: embed; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;GCM Push&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black; vertical-align: baseline;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black; vertical-align: baseline;&quot;&gt;수신&lt;/span&gt;&lt;span style=&quot;font-size: 10.5pt; font-family: '맑은 고딕'; color: black;&quot;&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; margin-left: 2em;&quot;&gt;
  &lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;oa7&quot; width=&quot;337&quot; style=&quot;width: 194px; background-color: rgb(239, 239, 255); border-bottom-color: rgb(95, 142, 239); border-right-color: rgb(95, 142, 239); border-bottom-width: 1px; border-right-width: 1px; border-bottom-style: solid; border-right-style: solid; color: rgb(0, 0, 0);&quot; colspan=&quot;1&quot;&gt;&lt;span style=&quot;font-size: 11pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/td&gt;
 &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Android</category>
      <category>라이브러리</category>
      <category>소프트웨어스택</category>
      <category>안드로이드</category>
      <author>에코지오</author>
      <guid isPermaLink="true">https://ecogeo.tistory.com/346</guid>
      <comments>https://ecogeo.tistory.com/346#entry346comment</comments>
      <pubDate>Thu, 18 Apr 2013 11:02:39 +0900</pubDate>
    </item>
    <item>
      <title>[안드로이드] POST방식 서버 통신시 java.io.EOFException 오류</title>
      <link>https://ecogeo.tistory.com/345</link>
      <description>&lt;p&gt;&lt;/p&gt;&lt;p&gt;앱단에서 서버와 java.net.HttpURLConnection을 이용해서 POST 방식으로 통신하는 경우에 가끔가다&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;java.io.EOFException 에러가 발생하더군요.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(254, 137, 67); background-color: rgb(254, 222, 199); padding: 10px;&quot;&gt;&lt;p&gt;Caused by: java.io.EOFException&lt;/p&gt;&lt;p&gt;at libcore.io.Streams.readAsciiLine(Streams.java:203)&lt;/p&gt;&lt;p&gt;at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:560)&lt;/p&gt;&lt;p&gt;at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:813)&lt;/p&gt;&lt;p&gt;at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:274)&lt;/p&gt;&lt;p&gt;at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:486)&lt;/p&gt;&lt;p&gt;at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:49)&lt;/p&gt;&lt;p&gt;at org.springframework.http.client.SimpleClientHttpResponse.getStatusCode(SimpleClientHttpResponse.java:55)&lt;/p&gt;&lt;p&gt;at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:46)&lt;/p&gt;&lt;p&gt;at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:476)&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;주로 삼성 갤럭시류의&amp;nbsp;폰에서 발생하는데,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;이 문제 때문에 엄청 골치가 아팠습니다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;구글링해보면&amp;nbsp;gzip 압축문제 때문이라고 하는 사람도 있고 여러가지 해법이 있었지만 현재까지는&amp;nbsp;&lt;/span&gt;http.keepAlive를 끄는 것이 맞는듯합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(159, 211, 49); background-color: rgb(231, 253, 181); padding: 10px;&quot;&gt;&lt;p&gt;public class MyApplication extends Application {&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; @Override&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; public void onCreate() {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; super.onCreate();&lt;span class=&quot;Apple-tab-span&quot; style=&quot;font-size: 9pt; line-height: 1.5; white-space: pre;&quot;&gt;		&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;... ...&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;patchEOFException();&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ... ...&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; }&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; private void patchEOFException() {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; System.setProperty(&quot;http.keepAlive&quot;, &quot;false&quot;);&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; }&lt;/p&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;* 참고 사이트&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;http://stackoverflow.com/questions/13182519/spring-rest-template-usage-causes-eofexception&lt;/p&gt;&lt;p&gt;https://jira.springsource.org/browse/ANDROID-102&lt;/p&gt;&lt;p&gt;http://stackoverflow.com/questions/12280629/nullpointerexception-when-using-spring-resttemplate-in-android&lt;/p&gt;&lt;p&gt;http://android-developers.blogspot.fr/2011/09/androids-http-clients.html&lt;/p&gt;&lt;p&gt;http://stackoverflow.com/questions/3352424/httpurlconnection-openconnection-fails-second-time&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;</description>
      <category>Android</category>
      <category>EOFException</category>
      <category>http.keepAlive</category>
      <category>안드로이드</category>
      <author>에코지오</author>
      <guid isPermaLink="true">https://ecogeo.tistory.com/345</guid>
      <comments>https://ecogeo.tistory.com/345#entry345comment</comments>
      <pubDate>Wed, 17 Apr 2013 18:02:47 +0900</pubDate>
    </item>
    <item>
      <title>[AOP] 아키텍처 규칙위반 체크 예제</title>
      <link>https://ecogeo.tistory.com/344</link>
      <description>&lt;p&gt;꼭 안드로이드일 필요는 없지만, AspectJ를 통해서 아키텍처 규칙 위반사항을 체크하는 예제를 공유합니다.&lt;/p&gt;&lt;p&gt;(&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;제가 다니는 회사에서 적용 중인 애스팩트를 살짝 수정한 것입니다)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(193, 193, 193); background-color: rgb(238, 238, 238); padding: 10px;&quot;&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;import org.aspectj.lang.annotation.Aspect;&lt;/p&gt;&lt;p&gt;import org.aspectj.lang.annotation.Pointcut;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;import android.app.Activity;&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;/**&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;* 아키텍처 규칙 위반을 체크하는 애스펙트.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;*/&lt;/span&gt;&lt;/p&gt;&lt;p&gt;@Aspect&lt;/p&gt;&lt;p&gt;public class ArchitectureRuleCheckAspect {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; private static final String PREFIX = &quot;[아키텍처 규칙위반]&quot;;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; //공통 액티비티(하위 액티비티)가 아닌 곳에 선언된 메소드 실행시&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; @Pointcut(&quot;!within(com.mycompany.xxx.BaseActivity+) &amp;amp;&amp;amp; execution(* *(..))&quot;)&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; private void notInBaseActivity() {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; }&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; @DeclareError(&quot;@annotation(com.mycompany.xxx.Click) &amp;amp;&amp;amp; notInBaseActivity()&quot;)&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; static final String useClickAnnotationOnlyInBaseActivity = &quot;@Click 어노테이션은 BaseActivity 하위클래스의 메소드에만 적용할 수 있습니다.&quot;;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; @DeclareError(&quot;call((@com.google.inject.Singleton *).new(..))&quot;)&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; static final String dontCreateSingletonDirectly = &quot;@Singleton 클래스 인스턴스를 직접 생성하면 안됩니다. @Inject를 사용하세요.&quot;;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; @DeclareError(&quot;within(com.mycompany.xxx.Controller+) &amp;amp;&amp;amp; call(com.mycompany.xxx.Controller+.new(..)) &quot;)&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; static final String dontUseAnotherControllerInControllers = PREFIX&amp;nbsp;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;+ &quot;콘트롤러에서 다른 콘트롤러를 사용할 수 없습니다.&quot;;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; @DeclareError(&quot;call(* com.mycompany.xxx.Controller+.*(..)) &amp;amp;&amp;amp; (within(*..*Action) || within(*..*Connector)) &quot;)&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; static final String useControllerOnlyInPresentationLayer = PREFIX&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;+ &quot;콘트롤러는 프리젠테이션 레이어에서 사용해야합니다.&quot;;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; @DeclareError(&quot;within(*..*Connector) &amp;amp;&amp;amp; call(* *.*Action.*(..)) &quot;)&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; static final String dontCallActionInConnectors = PREFIX&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;+ &quot;커넥터 레이어에서는 비즈니스 레이어(액션)를 호출할 수 없습니다.&quot;;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; @DeclareError(&quot;call(* android.app.Activity+.*(..)) &amp;amp;&amp;amp; (within(*..*Action) || within(*..*Connector)) &quot;)&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; static final String useActivityOnlyInPresentationLayer = PREFIX + &quot;액티비티는 프리젠테이션 레이어에서 사용해야합니다.&quot;;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; @DeclareError(&quot;@annotation(com.mycompany.xxx.Rest) &amp;amp;&amp;amp; !within(*..*Connector) &quot;)&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; static final String useRestAnnotationOnlyInConnectors = PREFIX&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&amp;nbsp;+ &quot;@Rest 어노테이션은 커넥터 레이어에서만 사용할 수 있습니다.&quot;;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;}&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;저의&amp;nbsp;경우 앱 개발시에 레이어 구조와 MVC 패턴을 적용한 아키텍처 표준을 정해놓고 개발합니다.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;레이어 구조는 Presentation(Activity) -&amp;gt; Business(Action) -&amp;gt; Connector(Connector)가 되고,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;MVC패턴은 Presentation 레이어에 적용됩니다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;위 애스펙트 예제는 이러한 &amp;nbsp;아키텍처 상에서 레이어간 역참조 및 MVC 담당 모듈을 엉뚱한 레이어에서 사용하는 것을 방지하고 있습니다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;아키텍처 표준뿐 아니라&amp;nbsp;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;자체 제작한 유틸리티 어노테이션을 올바른 곳에서 사용하고 있는지 체크하는 규칙을 포함하며,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 9pt; line-height: 1.5;&quot;&gt;Injection에 의해 주입받아야할 컴포넌트를 직접 instance화하는지도 검사합니다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Android</category>
      <category>AOP</category>
      <category>AspectJ</category>
      <category>아키텍처 규칙</category>
      <category>안드로이드</category>
      <author>에코지오</author>
      <guid isPermaLink="true">https://ecogeo.tistory.com/344</guid>
      <comments>https://ecogeo.tistory.com/344#entry344comment</comments>
      <pubDate>Wed, 17 Apr 2013 17:49:31 +0900</pubDate>
    </item>
  </channel>
</rss>