728x90

 

1. Apk를 디컴파일하는 방법 소개

(1) 단계벌 디컴파일

  • Apktool: apk의 리소스를 변환하는데 사용됩니다.
  • dex2jar: dex를 jar로 변환하는데 사용됩니다.
  • jd-cmd: jar를 java 코드로 변환하는데 사용됩니다.

(2) 명령어 한번에 apk를 쉽게 디컴파일해주는 툴 존재

  • jadx : Apk를 decompile하며, GUI와 Command line 툴 모두 제공합니다

 

2. Jadx로 디컴파일하는 방법

Jadx는 Jadx-release에서 빌드된 파일을 다운받을 수 있음

Jadx는 command line과 GUI tool을 모두 제공.

1) tool zip 파일을 다운받고 압축을 품

2) bin 폴더를 보면 실행 파일이 존재

- jadx는 command line tool이고, jadx-gui는 GUI tool

(Linux 사용자는 양쪽 다 사용 가능, Windows 사용자의 경우 jadx-gui.bat을 사용해야 함)

 

 

 

* command line tool의 상세 사용방법은 아래 참조글을 확인하면 됨

 

 

Reference

https://codechacha.com/ko/how-to-decompile-android-apk/

 

 

 

728x90
728x90

 

해당 에러 로그

 

Fatal Exception: android.view.WindowManager$BadTokenException

 

 

Fatal Exception: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@66e8c4 is not valid; is your activity running?
       at android.view.ViewRootImpl.setView(ViewRootImpl.java:1056)
       at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:381)
       at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
       at android.app.Dialog.show(Dialog.java:470)
       at 에러난 액티비티.onRequestComplete(ProductionManagementActivityRe.java:406)
       at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:715)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:214)
       at android.app.ActivityThread.main(ActivityThread.java:7063)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)

 

 

원인1:

BadTokenException이 발생한 원인을 파악하기 위해 오류를 재현하던 중, 같은 코드라도 쓰레드 위치나 라이프 사이클 상의 시점에 따라 간헐적으로 발생하는 것을 발견했다. 쓰레드 위치는 Main Thread가 아닌 Background Thread에서, 주로 AsyncTask의 onPostExecute() 메소드에서 다이얼로그 창을 통해 사용자에게  무엇인가를 알려주려고 시도하는 경우 간헐적으로 발생한다. 발생하는 시점은 Background Thread의 작업이 모두 종료되기 전에 뒤로가기 버튼을 누르거나 명시적으로 finish()메소드를 호출할 때이다. BadTokenException의 이유를 한문장으로 정리하면 , 예외 메시지에 ”is your activity running?” 이라고 명시되어 있듯 종료된 Activity의 context를 인자로 다이얼로그 창을 표시하려고 할 때 발생한다. 다이얼로그 창을 표시할 Activity가 없기 때문에 안드로이드 런타임이 나쁜 토큰(Bad Token1))이라는 예외를 던진다.

 

해결방법1:

해당 UI들을 사용할 때, Activity가 종료되었는 지를 확인하면된다. 만약 종료되었다면 다이얼로그 창을 열지 않으면 그만이다. 다음과 같이 isFinishing() 메소드를 사용하면 Activity의 종료 여부를 확인할 수 있다.

if (! ThisActivity.this.isFinishing()) {
    AlertDialog.builder dialog  = new AlertDialog.builder(ThisActivity.this);
    dialog.setTitle(status);
    dialog.setMessage(message);
    dialog.show();
}

 

원인2: 아래와 같이 activity 하위에 fragment가 있고, 그 중 한 곳에서 dialog를 사용할 때,

AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);

getActvitiy()가 아니라, activity로 했을 경우

 

 

해결방법2:

activity 일때와 fragment 일때 구분 해서 parameter 값을 넣어주는게 좋은거 같음

activity 대신에 getActivity() 로 하기

final AlertDialog.Builder alertDialog = new AlertDialog.Builder(getActivity());

 

 

원인3: (그런데 위의 2가지 케이스와 달리) 액티비티가 아닌 곳에서 발생한다면? 위 방법을 사용 할 수 없다. 참으로 희한하게도 context는 분명 들어 있는데 다이얼로그를 띄우면 죽는다. 액티비티를 종료 한 것도 아닌데... 보통 해당 프리퍼런스에서 다이얼로그를 띄운뒤 앱을 back키로 디스트로(destroy)이 한 뒤 다시 들어와서 해당 프리퍼런스의 다이얼로그를 띄우면 100% 죽는다. 이 경우에는 context를 static으로 만들어 주면 해결 된다. 


 

 

Reference

https://blog.sangyoung.me/2016/12/28/BadTokenException/

https://cishome.tistory.com/71

https://comoi.io/164

 

728x90
728x90

해당 에러로그

Fatal Exception: java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131296938, class android.widget.ListView) with Adapter (~)

 

 

Fatal Exception: java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131296938, class android.widget.ListView) with Adapter()
       at android.widget.ListView.layoutChildren(ListView.java:1715)
       at android.widget.AbsListView.onTouchUp(AbsListView.java:4129)
       at android.widget.HwAbsListView.onTouchUp(HwAbsListView.java:535)
       at android.widget.AbsListView.onTouchEvent(AbsListView.java:3909)
       at android.view.View.dispatchTouchEvent(View.java:11788)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2647)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2974)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2661)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2974)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2661)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2974)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2661)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2974)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2661)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2974)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2661)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2974)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2661)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2974)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2661)
       at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:549)
       at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1953)
       at android.app.Activity.dispatchTouchEvent(Activity.java:3559)
       at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:502)
       at android.view.View.dispatchPointerEvent(View.java:12027)
       at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5278)
       at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5067)
       at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4581)
       at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4634)
       at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4600)
       at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4727)
       at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4608)
       at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4784)
       at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4581)
       at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4634)
       at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4600)
       at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4608)
       at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4581)
       at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7169)
       at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7143)
       at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7104)
       at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7325)
       at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:192)
       at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
       at android.os.MessageQueue.next(MessageQueue.java:379)
       at android.os.Looper.loop(Looper.java:144)
       at android.app.ActivityThread.main(ActivityThread.java:7529)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)

 

 

상황원인: 디바이스 성능이 낮은 경우에 잘 발생하는 에러로, adapter의 콘텐츠를 UI 쓰레드로 처리해야하는데, 백그라운드에서 하려고 했기 때문에 발생하는 에러. 디바이스 성능이 좋으면 잘 나타나지 않는다고 함. (케바케인 것)

해결방법 : UI 쓰레드로 처리하도록 코드를 수정하면 되는데, 로그를 찍는 포인트가 어정쩡한지 대체 어느 부분인가...

 

 


Reference

https://devuryu.tistory.com/132

https://tigerwoods.tistory.com/26

 

 

 

 

 

 

728x90
728x90

 

https://www.youtube.com/watch?v=2F8K9BLgvjE&list=PLPvokKzUkaLeiLUDKpqRdP8jtLU8lLKgR&index=9

 

신입SW인력을 위한 실전 자바(Java) 스프링(Spring) 동영상과정 제 09강 AOP-I

신입SW인력을 위한 실전 자바(Java) 스프링(Spring) 동영상과정 제 09강 AOP-I 이번 강의는 AOP-I편입니다. PC로 보실때는 서울산업진흥원( http://www.sba.kr )에서 제작한 유튜브 동영상( http://www.youtube.com/seouliotcenter ) 에서 HD 동영상을 보시는 것이 좋습니다. 1080p로 설정해서 보시면 글자가 잘 보입니다. 오른쪽 하단 톱니모양에서 1080p를 선택하세요. 그리고 모바일로

www.youtube.com

 

https://wizcenter.tistory.com/239

 

9. AOP(Aspect Oriented Programming)-I: 관점지향 프로그래밍

공통 기능을 모든 모듈에 적용하기 위한 방법으로 상속을 통한 방법이 존재.

==> 상속의 문제점

 1) 우선 JAVA에서는 다중 상속이 불가하므로 다양한 모듈에 상속기법을 통한 공통 기능 부여는 한계가 있습니다.

 2) 기능 구현부분에 핵심 기능 코드와 공통 기능 코드가 섞여 있어 효율성이 떨어집니다.

 

==> 위의 상속을 통한 방법에 한계 개선으로 AOP 등장

AOP방법은

1) 핵심 기능과 공통 기능을 분리 시켜놓고,

2) 공통 기능을 필요로 하는 핵심 기능들에서 사용하는 방식 입니다.

 

 

ex) 아침에 밥을 짓는다고 생각해 봅니다.

핵심 기능은 쌀을 씻고, 깨끗한 물을 적당히 넣고, 전자밥솥에 내솥을 넣고, 취사 버튼을 누르는 기능들 일 것입니다

공통 기능은 수도 꼭지를 열어 물을 받고, 쌀이 깨끗이 씻겼는지 눈으로 판단하고, 물을 적당한지 판단하는 기능들 일 것입니다.

이러한 기능이 공통 기능인 것은 밥을 짓는 행동이 아닐 때도 우리는 수도 꼭지를 열고, 눈으로 사물을 보고 적절한 판단을 하기 때문에 공통 기능이라고 하였습니다.

어쨌든, 이렇게 핵심 기능과 공통 기능을 분리해 놓고, 추후에 밥을 짓는 행동 말고 팥을 쑬 때도 핵심 기능은 변화지만, 공통 기능은 다시 적용할 수 있을 것입니다.

 

 

 

AOP 관련 용어

 - Aspect : 공통 기능

 - Advice : Aspect의 기능 자체

 - Jointpoint : Advice를 적용해야 되는 부분( ex, 필드, 메소드 ) (스프링에서는 메소드만 해당)

 - Pointcut : Jointpoint의 부분으로 실제로 Advice가 적용된 부분

 - Weaving : Advice를 핵심 기능에 적용 하는 행위

 

...

 

JoinPoint는 핵심기능 메소드를 의미함

 

 

 

- XML 기반의 AOP구현 작업 순서 (spring_9_2_ex1_springex)

 1) 존 설정(pom.xml)

 2) 공통 기능의 클래스 제작 – Advice 역할 클래스

 3) XML설정 파일에 Aspect 설정

 

- Advice의 종류

<aop:before> : 메소드 실행 전에 advice실행

<aop:after-returning> : 정상적으로 메소드 실행 후에 advice실행

<aop:after-throwing> : 메소드 실행중 exception 발생시 advice실행

<aop:after> : 메소드 실행중 exception 이 발생하여도 advice실행

<aop:around> : 메서드 실행 전/ exception 발생시 advice실행

 

 

728x90

+ Recent posts