안드로이드 애플리케이션(성능 등등) 분석 툴

2022. 7. 1. 18:19모바일프로그래밍

728x90

https://www.vogella.com/tutorials/AndroidTools/article.html

 

안드로이드 성능 이슈들에 대한 분석

 

 튜토리얼은 안드로이에서 안드로이드 애플리케이션들의 성능 분석을 수행할  있는 가용한 툴에 대해서 설명하는 튜토리얼입니다.

 

목차

 

1. 개요
2. 안드로이드 기본
3. StrictMode
4. 개발자 세팅
5. Lint
6. Traceview
   6.1. 소개
   6.2. 안드로이드 스튜디오에서 Traceview사용하기
   6.3. 커맨드 라인에서 Traceview사용하기
7. Traceview 연습 :
   7.1. 예제 프로젝트 생성
7.2. 성능 추적
7.3. 성능 문제 해결
8. 상속계층 뷰
9. 연습 : 상속계층뷰어
10. 레이아웃 최적화
11. 메모리 덤프
12. Systrace
13. 픽셀 density 시뮬레이션
14. 안드로이드 템플릿
15. GPU 랜더링 프로파일
16. Overdraw 분석하기
17. 애플리케이션 분석을 위한 유용한 오픈 소스 툴들
17.1. Leak Canary 를 이용한 메모리 누수 찾기
17.2. AndroidDevMetrics 를 사용한 성능 데이터 표출
18. 이 웹사이트에 대해서
19. Links and Literature
19.1. 안드로이드 애니메이션 리소스들
19.2. vogella GmbH training and consulting support

 

1. 개요

 

안드로이드 애플리케이션이 모든 오퍼레이션들 가능한 빠르게 처리하게 만드는 것은 매우 중요한 문제이다 문서는 안드로이드 애플리케이션을 최적화하고 추적이 가능한 툴들을 설명하는 리스트입니다.

 

2. 안드로이드 기본

안드로이드 개발 대한 기본적인 지식을 이미 갖고 있다는 전제에서 이문서는 출발합니다기본을 배우고 싶다면 다음 안드로이드 개발 튜토리얼  사이트를 참고 하십시요

 

3. StrictMode

UI 쓰레드 상에서 시간이 오래 걸리는 동작을 수행하는 것은 피해야 합니다이는 파일과 네트워크 접근 관련한 사항을 포함해서 말하는 것입니다.

StrictMode  사용 해야만 합니다. StrictMode  API 9 (Android 2.3.3) 에서 사용가능하며 애플리케이션의 쓰레드 정책을 설정   있도록 해줍니다.

 

사용자 인터페이스 쓰레드 내의 I/O 같은  수행 시간을 가지는 기능이 있다면StrictMode 통해서 안드로이드 시스템이 해당 애플리케이션의 탈락 (혹은 충돌) 지시   있다.

 

다음 코드는 StrictMode 사용하기 위한 예를 보여 준다. .액티비티는 해당 설정을 위반 하는 경우에 탈락(충돌시킵니다.

package de.vogella.android.strictmode;

import java.io.BufferedWriter;
import java.io.OutputStreamWriter;

import android.app.Activity;
import android.os.Bundle;
import android.os.StrictMode;

public class TestStrictMode extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Activate StrictMode
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectAll()
                .detectDiskReads()
                .detectDiskWrites()
                .detectNetwork()
                 // alternatively .detectAll() for all detectable problems
                .penaltyLog()
                .penaltyDeath()
                .build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .detectLeakedSqlLiteObjects()
                .detectLeakedClosableObjects()
                // alternatively .detectAll() for all detectable problems
                .penaltyLog()
                .penaltyDeath()
                .build());

        // Test code
        setContentView(R.layout.main);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        String eol = System.getProperty("line.separator");
        try {
            BufferedWriter writer =
                    new BufferedWriter(
                            new OutputStreamWriter(
                            openFileOutput("myfile",
                            MODE_WORLD_WRITEABLE)));
            writer.write("This is a test1." + eol);
            writer.write("This is a test2." + eol);
            writer.write("This is a test3." + eol);
            writer.write("This is a test4." + eol);
            writer.write("This is a test5." + eol);
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

StrictMode  개발 기간 중에 사용하는 것이지 실제 애플리케이션에서 사용하지 말아야 한다.

 

4. 개발자모드 세팅

 

안드로이드 폰에서 애플리케이션 분석을 단순화   있는 환경 설정이 가능하도록 개발자 모드 세팅(Developer Settings) 을 할  있습니다예를 들어 터치 영역이 활성화가 가능하도록 할 수 있습니다.

 

안드로이드 4.2 폰을 가지고 있다면 “Settings” 내의 “About” 섹션으로 가서 “Build number” 엔트리를 7 태핑  보도록 합니다

만약  옵션(개발자 옵션) 활성화   없으면 에뮬레이터를 사용하도록 합니다.

세팅이 적용되려면 애플리케이션을  시작 해야 하는 경우도 있습니다.

5. Lint

Android Lint tutorial  참조 하도록 합니다.

6. Traceview

6.1. Introduction 소개

 

Traceview 안드로이드 애플리케이션이 생성한 로그들을 보기 위한 그래픽 뷰어이다 뷰어를 통해서 성능 문제를 일으키는 애플리케이션에 대한 성능을 측정할  있게 됩니다.

 

Traceview  안드로이드 SDK 설치폴더내에 tools  폴더 내에 있는 자체구동 툴이다. 툴은 안드로이드 개발자 (ADT) 통해서 이클립스와 통합되어 있습니다..

 

6.2. 안드로이드 스튜디오에서 Traceview 사용하기

안드로이드 스튜디오는 Android Device Monitor  통해서 추적을 지원합니다.

Tools → Android → Android Device Monitor 순으로 선택 실행하여 사용하십시오

Devices 뷰의 애플리케이션 프로세스들 중에서 추적할 애플리케이션을 선택하셔 추적   있으며아래 스크린샷에서 처럼 Start Method Profiling   선택 합니다.

 

 

애플리케이션을 사용하고 같은 버튼을 다시 누르면 프로파일링이 멈춥니다해당 추적 결과물을 보여 주는 새로운 에디터 창에 활성화  것입니다.

 

 

 

 

해당 그림을 확대하면   세세한 내용을   있습니다축소하기 위해서는 타임라인을 더블 클릭하면 됩니다.

 

6.3. 커맨드라인에서 TraceView 사용하기

다음 코드 조각을 추적하기 위한 코드에 둘러  주면 추적이 시작됩니다.

android.os.Debug.startMethodTracing("yourstring");

// ... your code is here

android.os.Debug.stopMethodTracing();

 

"yourstring" 파라메터는 "/sdcard/yourstring.trace" 디렉토리 안에 데이터를 저장해야만 한다는 것을 시스템에 알려주는 역할을 합니다. sdcard에 데이터를 저장하기 위해서는 WRITE_EXTERNAL_STORAGE 권한이 필요 합니다. 애플리케이션이 구동된 후에는 기기에서 나온 결과치를 adb 커맨드라인 툴 명령으로 복사 할 수 있습니다.

adb pull /sdcard/yourstring.trace
traceview yourstring

 

그래픽적인 요소를 통해서 애플리케이션 성능 데이터를 분석할  있도록 해주는 Traceview 위의 명령을 통해서 수행이 가능합니다. DDMS 뷰에서 trace 버튼을 사용할  있습니다이렇게 해서 구동 중인 애플리케이션의 성능추적을   있으며추가적인 인증 작업은 없습니다.

7. 연습: Traceview

7.1. 예제 프로젝트 생성하기

 

com.vogella.android.traceview 라는 최상위 패키지 이름을 가진 안드로이드 애플리케이션을 생성합니다.

 

values/strings.xml  파일에 다음  값을 추가합니다.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Traceview Example</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    <string name="number_template"><b>Random number: %1$s</b></string>

</resources>

 

다음 rowlayout.xml 이름의 레이아웃 파일을 생성합니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:orientation="horizontal" >

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

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

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Entry"
                android:textAppearance="?android:attr/textAppearanceListItem" />

            <TextView
                android:id="@+id/textView2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Stub"
                android:textAppearance="?android:attr/textAppearanceListItemSmall" />
        </LinearLayout>
    </LinearLayout>

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="10dp"
        android:layout_height="?android:attr/listPreferredItemHeight"
        android:background="@android:color/black" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="Medium Text"
        android:textAppearance="?android:attr/textAppearanceMedium" />

</LinearLayout>

 

 ListView  다음 adapter   구현합니다.

package com.vogella.android.traceview;

import java.util.Collections;
import java.util.List;

import android.content.Context;
import android.content.res.Resources;
import android.os.Debug;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class MyArrayAdapter extends ArrayAdapter<String> {

    private List<String> values;
    private Context context;

    public MyArrayAdapter(Context context, List<String> values) {
        super(context, R.layout.rowlayout);
        this.context = context;
        this.values = values;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Debug.startMethodTracing("getViewOfTrace");
        // Ensure sorted values
        Collections.sort(values);
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.rowlayout, parent, false);
        Resources res = context.getResources();
        String text = String.format(res.getString(R.string.number_template),
                values.get(position));
        CharSequence styledText = Html.fromHtml(text);
        TextView textView = (TextView) view.findViewById(R.id.textView3);
        textView.setText(styledText);
        Debug.stopMethodTracing();
        return view;
    }
}

 

1000개의 랜덤 생성 문자열들을 보여주는  ListView 액티비티 내에 다음과 같이 구현합니다.

package com.vogella.android.traceview;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;

import android.app.ListActivity;
import android.os.Bundle;

public class MainActivity extends ListActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        List<String> list = createValues();
        MyArrayAdapter adapter = new MyArrayAdapter(this, list);
        setListAdapter(adapter);
    }

    private static List<String> createValues() {
        SecureRandom random = new SecureRandom();
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 1000; i++) {
            String string = new BigInteger(130, random).toString(32);
            list.add(string);
        }
        return list;
    }

}

애플리케이션의 외장 스토리지 퍼미션을 추가해 줍니다.

7.2. 성능 추적

애플리케이션을 구동합니다그런 다음 디바이스에 adb 통해서 연결한 다음드라이브의 성능추적결과를  복사하고  결과를 분석 합니다.

7.3.  성능 문제 해결하기

 

Traceview  측정결과를 기반으로 성능을 향상 시킬  있습니다다음은 성능 향상을 위한  포인트를 설명입니다.

 

  • getView() 내에 볼드 스타일을 레이아웃 내의 이에 상응하는 android:textStyle="bold  바꾸어Html.fromHtml()메서드 호출을 하지 않도록 합니다.
  • 소팅 부분을 다른 곳을 옮깁니다.
  • null 널이 아닌 경우어댑터의 convertView 재사용 합니다.
  • ListView 내에 HolderPattern 사용하기 위한 findViewById() 메서드 호출을 피해야 합니다.

 

8. 상속 계층 뷰어

 

Hierarchy View perspective   안드로이드 애플리케이션의 View  상속구조를 그래픽적으로 보여   있으며 상속구조 상에서 필요없는 레이어들을 찾아   있도록 도와 줍니다.

 

Window → Open Perspective → Other... → Hierarchy View 순으로 선택해서 Hierarchy View  윈도우를 활성화   있습니다.

 

Windows  뷰내의 상속 뷰에서 분석하기를 원하는 프로세스를 선택   있습니다.

 

 

현재 활성화  레이아웃이 분석되고 화면에 표시 되어 있는 것을 확인   있습니다.

 

Tree View  뷰는 뷰들을 위해서3개의 전구 모양 아이콘을 보여 줍니다첫번째 아이콘은 뷰의 크기를 계산한 시간을 나타냅니다두번째 아이콘은 레이아웃을 생성한 시간을 나타내고 마지막 세번째 아이콘은 뷰를 그리는 시간을 나타냅니다성능 향상이 필요한 작업은 노란색이나 빨간 색으로 표시됩니다.

9. 연습 : 상속 계층 Viewer

 

Hierarchy View perspective  열고  레이어를 분석해 보도록 하겠습니다.

 

 레이아웃 레이어들에 대해 성능적인 측면에 대한 고려는  필요가 없어 보이지만많은 레이어들과 필요없는 뷰들은 성능 향상이 매우 필요해 보입니다.

10. 레이어웃 최적화

 

레이어웃은 최적화 해야만 하는 과제 입니다다음은 다음에 설명할 결과 스크린샷을 생성할 ImageView   하나의 TextView   가진  FrameLayout   사용하는 방법을 나타냅니다레이아웃 내의 TextView  상대 위치를 사용하고 해당 텍스트 콘텐츠의 서로 다른 스타일을 사용합니다..

 

 

com.vogella.android.textview.spannablestring 이라는 프로젝트를 생성합니다.

 

styles.xml  파일에 두개의 새로운 스타일을 추가합니다.

<resources xmlns:android="http://schemas.android.com/apk/res/android">

    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="android:Theme.Light">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.
        -->
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a API-level are here. -->
    </style>

    <style name="textHeader">
        <item name="android:padding">4dip</item>
        <item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
        <item name="android:textColor">#000000</item>
        <item name="android:fontFamily">sans-serif-condensed</item>
    </style>

    <style name="textbody">
        <item name="android:padding">4dip</item>
        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
        <item name="android:textSize">16sp</item>
        <item name="android:textColor">#c0c0c0</item>
    </style>

</resources>

 

다음과 같이 레이아웃을 생성한다.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/FrameLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <TextView
        android:id="@+id/input"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:layout_margin="16dp"
        android:text="@string/hello_world"
        android:textSize="32sp" />

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:contentDescription="image"
        android:src="@drawable/vogella" />

</FrameLayout>

 

아래 코드에서 보여주듯이 분리된 TextAppearanceSpan  통해서 TextView 문자 텍스트에 스타일을 적용한다.

package com.vogella.android.textview.spannablestring;

import android.app.Activity;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.TextAppearanceSpan;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = (TextView) findViewById(R.id.input);
        String header = "This is the header";
        String description = "This is the description";

        Spannable styledText = new SpannableString(header + "\n" + description);
        TextAppearanceSpan span1 = new TextAppearanceSpan(this,
                R.style.textHeader);
        TextAppearanceSpan span2 = new TextAppearanceSpan(this,
                R.style.textbody);
        styledText.setSpan(span1, 0, header.length(),
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        styledText.setSpan(span2, header.length() + 1, header.length() + 1
                + description.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        textView.setText(styledText);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

 

결과 레이아웃은 RelativeLayout 기반의 레이아웃 보다   빠른 레이아웃이다 또한 HTML 파서를 사용하는 것은 비교적 비싼 오퍼레이션이므로 HTML 스타일링은 피했다.

11. Memory Dumps 메모리 덤프

 

Eclipse Memory Analyzer 사용해서 메모리 스냅샷을 생성하고 분석   있다.

12. Systrace

 

Systrace   커널 레벨에서 직접 성능을 측정하게 해준다. Systrace  활성화 하기 위해스는 개발자 옵션을 선택하고Enable traces 엔트리를 선택해 준다 다음 다이얼로그박스에서 어떤 타입의 이벤트를 프로파일 해야만 할지를 정의해야만 한다. (그래픽이나 )

 

 

 

 

Systrace 사용하기 위해서는터미널을 열고 android_sdk_installdir/tools/systrace  디렉토리에서 systrace.py   구동합니다 파일에 실행 권한을 주어야 할 수도 있습니다.(리눅스에서는 chmod a+x systrace.py)

 

이클립스의DDMS perspective  통해서 Systrace   직접 구동  수도 있습니다.

 

 

 

Systrace   5 동안 이벤트를 캡쳐하고, 결과물로 Systrace   기본적인 문제들을 분석하게 해주는 HTML 파일을 생성합니다.

 

13. 픽셀 density 시뮬레이션

 

상이한 기기 density 스크린 리졸루션을 커맨드라인을 이용해서 사용   있습니다.

 

이렇게 되면 다른 기기를 시뮬레이션 하기 위한 높은 디스플레이 해상도와 기기 density 가지도록 해줍니다.

// Set the display size
adb shell am display-size 600x800

// Set the display density
adb shell am display-density 80

 

14. 안드로이드 템플릿

.

안드로이드 프로젝트 생성 위저드를 위해서 자신만을 템플릿을 정의   있다다음의 링크에   많을 정보를 얻을  있습니다.

 

Roman Nurik:

https://plus.google.com/113735310430199015092/posts/XTKTamk4As8

 

Official documentation:

https://dl.dropbox.com/u/231329/android/templatedocs/index.html

 

Additional code templates -

https://github.com/jgilfelt/android-adt-templates

 

15. 랜더링 프로파일

 

Setting   Developer options  내에 혹은 안드로이드 디바이스 에서 Profile GPU rendering   있습니다.  이 옵션을 사용하면 마지막 128 프레임을 그리기 위해서 걸린 시간을 시스템이 추적   있도록 해줍니다.

 

활성화 하고   다음 명령을 통해서 앱을  구동  주면 정보를 얻을  있을 것입니다.

adb shell dumpsys gfxinfo your_package 

 

애플리케이션의 리스트 뷰를 스크롤 하는 등의 프레임 율을 측정하기 위해서많은 경우에는 기기 자체를 새롭게 그리기 위한 트리거를 조정    있어야만 합니다.

 

결과 로그 내에서 Profile data in ms 라는 섹션을 살펴   있습니다.

 

16. Overdraw 분석하기

 

Overdraw  뭔가의 최상위에 뭔가를 그릴  발생한다예를 들어 activity  Window   백그라운드로 가진다만약 애플리케이션에 TextView  추가되어야 한다면  TextView   Window 위에 그려지게 됩니다.

 

그러므로 Overdrawn 일어난다는 것입니다하지만 불필요한 overdraw 최상의 성능을 얻기 위해서는 피해야만 합니다.

 

불필요한 overdraw 복잡한  상속을 야기할 수도 있습니다일반적으로   overdraw(픽셀이 세번 그려지는 ) 표준이며 예상   있는 결과 이나  이상은 피해야만 합니다.

 

Development Settings  Show GPU overdraw 세팅 Overdraw 표현이 가능하게   있습니다 섹션은 . overdraw들의 개수를 기반인 스크린에 색깔을 추가   있습니다다음 테이블은 사용되어지는 색상 스키마를 설명 합니다.

 

Table 1. Overdrawn colors

Color Meaning
No color No overdraw
Blue 1x overdraw, pixel was painted twice
Green 2x
Light red 3x, might indicate a problem, small red areas are still ok
Dark red 4x, pixel was pained 5 times or more, indicates a problem.

 

 

기본 문제영역의 표현 후에Hierarchy Viewer  View  상속구조를 분석   있습니다.

17. 애플리케이션 분석을 위한 유용한 오픈소스 

17.1.  사용한 메모리 누수 찾기

 

Leak Canary  안드로이드 애플리케이션에 통합 되어질  있으며 자동으로 액티비티들이나 프레그먼트들의 메모리 릭을 찾아   있습니다사용법은 매우 단단하며, Gradle 빌드 파일에 dependency  추가 해주고 애플리케이션 클래스에서 라이브러리를 초기화 해줍니다이렇게 하면 액티비티들에 대한 생명주기 리스너들을 등록하게 되고  적절한 시점에 destroy 메서드를 호출하면 추적되게 됩니다.

 

Leak Canary 오픈소스 프로젝트이며 아주 빨리 변화하는 측면이 강한 프로젝트입니다.

어떻게 사용하는 지에 대한 가이드는 Leak Canarys Github page 보십시오.

17.2. 성능데이터를 표출하기 위한 AndroidDevMetrics 사용하기

 

AndroidDevMetrics 오브젝트 초기화나 액티비티 생명주기 메서드들(onCreate(), onStart(), onResume()) 생성  가장 일반적인 동작이 얼만큼 빨리 일어나는    있게 해주거나, (in Dagger 2 graph)

AndroidDevMetrics 오픈소스 프로젝트이며어떻게 사용하는 지에 대한 가이드는 AndroidDevMetrics Github page 활용 하십시오.

 

19. Links and Literature

19.1. Android Animation Resources

Traveview homepage

 

이상.

 

 

728x90