안드로이드에서는 오디오 재생을 위해 android.media API를 제공합니다.

기본적인 플레이만 필요하다면 패키지 안에 있는 미디어플레이어 클래스를 활용하면 됩니다.


하지만 기본적인 미디어플레이어를 사용할 경우 레이턴시가 존재하기 때문에 빠른 반응속도를 요구하는 앱을 개발하기 위해서는 NDK를 사용해 볼 필요가 있어 보입니다.


NDK에 대한 내용은 아래 링크를 클릭하면 됩니다.

https://developer.android.com/ndk/guides/?hl=ko


이 글을 읽고 과연 NDK가 필요할지에 대한 고민은 직접 해보시기 바랍니다.


NDK에서 재공되는 기본 샘플 "native-audio" 를 실행해 보기 위해 NDK를 설치해 보고 안드로이드 스튜디오에서 실행해 보겠습니다.


우선 NDK를 다운로드 받아 봅니다.


아래 링크에서 자신의 컴퓨터 사양에 맞는 버전을 다운로드 합니다.

https://developer.android.com/ndk/downloads/?hl=ko


설치 방법은 Apache Maven 설치 방법과 비슷합니다.

1) zip 파일을 다운로드 받아서 프로그램 폴더에 압축을 해제합니다.

ex) "C:\Program Files\android-ndk-r17"

2) 해당 경로를 환경변수 path에 추가합니다.


설치가 완료되면 샘플 파일을 다운로드 받습니다.

아래 링크를 클릭해서 zip 파일을 다운로드 받은 후 적당한 폴더에 풀어주세요.

https://github.com/googlesamples/android-ndk


안드로이드 스튜디오에서 native audio 프로젝트를 열어봅니다.


열어보면 아래와 같은 오류 메시지가 나타나면서 실행이 되지 않습니다.


Migrate Project to Gradle?

This project does not use the Gradle build system.

We recommend that you migrate to using the Gradle build system.

More Information about migrating to Gradle

Don't show this message again.


인터넷으로 찾아보니 Gradle 형식이 아니기 때문에 나타나는 문제라고 하네요.

프로젝트를 닫고 open project가 아닌 import project로 해당 폴더를 선택해서 열어봅니다.


이번엔 다른 메시지가 나타납니다.


Error:Could not find com.android.tools.build:gradle:3.1.2.

Searched in the following locations:

https://jcenter.bintray.com/com/android/tools/build/gradle/3.1.2/gradle-3.1.2.pom

https://jcenter.bintray.com/com/android/tools/build/gradle/3.1.2/gradle-3.1.2.jar

Required by:

project :

<a href="add.google.maven.repository">Add Google Maven repository and sync project</a><a href="openFile:P:\Programming2018\AndroidStudioProjects\AIJTestProjects\native-audio\build.gradle">Open File</a>

<a href="enable.embedded.maven.repository">Enable embedded Maven repository and sync project</a>


위에 있는 Add Google Maven repository and sync project 글씨를 클릭하면 다시 빌드가 되면서 오류메시지가 사라집니다.


이제 앱 실행이 가능하게 됬네요.


하지만 실행하면 다른 오류가 발생합니다.


Error: Your project contains C++ files but it is not using a supported native build system.

Consider using CMake or ndk-build integration. For more information, go to:

 https://d.android.com/r/studio-ui/add-native-code.html

Alternatively, you can use the experimental plugin:

 https://developer.android.com/r/tools/experimental-plugin.html


SDK Manager 에서 SDK Tools 탭에 있는 CMake LLDB NDK 3가지를 설치해야 된다고 나와있네요. 3가지를 선택하고 OK 버튼을 클릭하면 안드로이드 스튜디오에 해당 Tool이 설치됩니다.


그리고 마지막으로 "Link C++ Project with Gradle" 옵션을 선택해 줘야 합니다.

새 프로젝트 생성때는 체크박스를 선택하면 되지만 기존 예제를 가져온 경우에는 

상단메뉴 File - Link C++ Project with Gradle 메뉴에서 Build System을 ndk-build를 선택한 후에 cpp 파일이 있는 폴더안에 있는 "Android.mk" 파일을 선택하고 OK버튼을 클릭하면 선택이 완료됩니다.

안드로이드 스튜디오는 안드로이드 개발을 편하게 해주는 프로그램입니다.
개발을 더욱 편하게 해주는 옵션을 설정해 주면 개발 속도가 더욱 빨라집니다.

개인적으로 편하다고 생각하는 옵션 2가지를 소개하겠습니다.


옵션1. 코드를 입력했을 때 자동으로 import 되도록 할 수 있습니다.

기본 옵션은 이 기능이 활성화 되어 있지 않습니다.
자바 코드에서 코드를 입력했을 때 새로운 내용을 import 해야 할 경우 직접 파일 상단에 import를 추가해 주거나 alt + enter 키를 쳐서 하나하나 추가해 줘야 합니다.
초반에 공부할 때는 도움이 되지만 프로젝트를 진행할 때, 파일을 만들때 마다 하나하나 추가해 줘야하는 불편함이 있습니다.
그래서 옵션에서 설정해 주면 그 다음부터는 자동으로 필요한 import를 생성해 줍니다.

설정 방법은 다음과 같습니다.

안드로이드 스튜디오 상단 메뉴에 있는 File - Settings... 를 클릭합니다.

Setting 화면 왼쪽 메뉴에서 Editor - General - Auto Import 메뉴를 클릭합니다.
오른쪽 화면에서 Java 하위 메뉴의 Add unambiguous imports on the fly 옵션과 Optimize imports on the fly (for current project) 옵션을 활성화 시켜 줍니다.


옵션2. 대소문자 구분없이 자동완성 가능하게 하기

Visual Studio 를 사용하다가 안드로이드 스튜디오를 사용하면서 불편했던 점이 대소문자가 틀리면 자동완성이 되지 않는 점이었습니다.

Visual Studio에서는 스펠링만 맞으면 자동완성이 되어 대소문자는 나중에 생각하면 됬는데 여기선 코드 작성할때 대소문자의 위치도 신경써서 작성해야 자동완성이 됩니다. 아래 옵션을 수정하면 이제 대소문자가 틀려도 스펠링만 맞으면 자동완성 옵션에서 원하는 코드를 쉽게 찾을 수 있습니다.

설정 방법은 다음과 같습니다.

안드로이드 스튜디오 상단 메뉴에 있는 File - Settings... 를 클릭합니다.

Setting 화면 왼쪽 메뉴에서 Editor - General - Code Completion 메뉴를 클릭합니다.
Case sensitive completion 을 First Letter 에서 None로 변경합니다.

감사합니다.

안녕하세요. 윈도우 폼에서 폴더를 선택했을 때 파일 목록을 가져오는 방법에 대해 알아보겠습니다.

우선 프로그래밍을 하기 전에 어떤 내용을 만들지 정리해 볼께요.

1. 윈도우 폼에 하위폴더 포함 여부를 선택할 수 있는 체크박스를 추가한다
2. 버튼을 추가하여 버튼을 클릭하면 폴더를 선택할 수 있는 창이 나타나도록 설정한다.
3. 폴더 선택을 완료하면 하위폴더 포함 여부에 따라 파일 리스트를 출력한다.

그럼 위 내용대로 진행해 보겠습니다.

1. Visual Studio(2017 기준) 를 실행하고 새로운 프로젝트를 생성합니다.
상단 메뉴의 파일(F) - 새로 만들기(N) - 프로젝트(P) 를 선택합니다.

좌측 메뉴에 Visual C# - Windows 클래식 바탕화면을 선택하고 가운데 메뉴에 Windows Forms 앱(,net Framework)를 선택합니다.
앱 이름은 WindowsFormsFileList 로 정하겠습니다. 폴더는 원하는 위치를 지정해 주세요. 아래 그림과 같이 설정이 끝났으면 확인 버튼을 클릭합니다.

그러면 다음과 같은 화면이 나타납니다.(Visual Studio 설정여부에 따라 화면이 다르게 나타납니다.)

폼 이름 및 크기를 바꿔볼께요.
폼을 선택하고 속성 도구를 열고 Text와 Size 속성을 바꿉니다.
(Name): Form1 - Text: 선택 폴더의 파일 목록 가져오기 / Size: 800, 600

다음에 컨트톨을 추가해 보겠습니다.
도구 상자탭을 선택하고 원하는 도구 상자를 드래그해서 폼 안에 넣으면 됩니다.

저는 아래와 같이 넣었습니다.

각 도구의 주요 속성은 다음과 같습니다.

버튼(Button) - (Name): button1 / Location: 20, 20 / AutoSize: False / Size: 70, 20 / Text: 폴더 선택
확인상자(CheckBox) - (Name): checkBox1 / Location: 100, 22 / AutoSize: True / Size: 104, 16(자동으로 설정됨) / Text: 하위 폴더 포함
라벨(Label) - (Name): label1 / Location: 20, 50 / AutoSize: True / Size: 73, 12(자동으로 설정됨) / Text: 선택된 폴더:
라벨(Label) - (Name): label2 / Location: 100, 50 / AutoSize: True / Size: 29, 12(자동으로 설정됨) / Text: 없음
자료보기창(DataGridView) - (Name): dataGridView1 / Location: 20, 80 / AutoSize: False / Size: 750, 460

외형을 완성했으면 이제 프로그래밍을 해보겠습니다.
폴더 선택 버튼을 더블클릭하면 아래 그림과 같이 자동으로 이벤트가 추가되고 코드보기 화면으로 전환됩니다.

버튼 클릭 이벤트에 추가하기 전에 필요한 함수를 미리 만들어 보겠습니다.

시작하기 전에... 아래 코드를 작성하기 위해서 아래 클래스를 추가로 불러와야 합니다.

using System.IO;
using Microsoft.WindowsAPICodePack.Dialogs;

using Microsoft.WindowsAPICodePack.Dialogs; 을 불러오는 방법은 아래 글을 참고해 주세요.
글 제목: FolderBrowserDialog 보다 괜찮은 폴더 선택 화면 - CommonOpenFileDialog
링크: http://ilbbang.tistory.com/22

매서드1: 선택한 목록의 파일 및 정보를 DataTable 형식으로 보낼 수 있는 매서드를 아래와 같이 추가합니다.

        /// <summary>
        /// 선택한 폴더의 파일 목록을 DataTable형식으로 내보냅니다.
        /// </summary>
        /// <param name="FolderName">선택한 폴더의 전체 경로를 입력합니다.</param>
        /// <returns></returns>
        private DataTable GetFileListFromFolderPath(string FolderName)
        {
            DirectoryInfo di = new DirectoryInfo(FolderName); // 해당 폴더 정보를 가져옵니다.

            DataTable dt1 = new DataTable(); // 새로운 테이블 작성합니다.(FileInfo 에서 가져오기 원하는 속성을 열로 추가합니다.)
            dt1.Columns.Add("Folder", typeof(string)); // 파일의 폴더
            dt1.Columns.Add("FileName", typeof(string)); // 파일 이름(확장자 포함)
            dt1.Columns.Add("Extension", typeof(string)); // 확장자
            dt1.Columns.Add("CreationTime", typeof(DateTime)); // 생성 일자
            dt1.Columns.Add("LastWriteTime", typeof(DateTime)); // 마지막 수정 일자
            dt1.Columns.Add("LastAccessTime", typeof(DateTime)); // 마지막 접근 일자

            foreach (FileInfo File in di.GetFiles()) // 선택 폴더의 파일 목록을 스캔합니다.
            {
                dt1.Rows.Add(File.DirectoryName, File.Name, File.Extension, File.CreationTime, File.LastWriteTime, File.LastAccessTime); // 개별 파일 별로 정보를 추가합니다.
            }

            if(checkBox1.Checked == true) // 하위 폴더 포함될 경우
            {
                DirectoryInfo[] di_sub = di.GetDirectories(); // 하위 폴더 목록들의 정보 가져옵니다.
                foreach (DirectoryInfo di1 in di_sub) // 하위 폴더목록을 스캔합니다.
                {
                    foreach (FileInfo File in di1.GetFiles()) // 선택 폴더의 파일 목록을 스캔합니다.
                    {
                        dt1.Rows.Add(File.DirectoryName, File.Name, File.Extension, File.CreationTime, File.LastWriteTime, File.LastAccessTime); // 개별 파일 별로 정보를 추가합니다.
                    }
                }
            }
            
            return dt1;
        }

FileInfo 클래스에서 가져올 수 있는 속성은 아래 링크를 확인해 주세요.
https://msdn.microsoft.com/ko-kr/library/system.io.fileinfo(v=vs.110).aspx

매서드2: 위의 결과를 컨트롤에 보여줄 수 있는 매서드를 아래와 같이 추가합니다.

        /// <summary>
        /// 선택한 폴더의 파일 목록을 가져와서 DataGridView 도구에 보여줍니다.
        /// </summary>
        /// <param name="dt1">선택한 폴더의 파일 목록이 들어있는 DataTable을 입력합니다.</param>
        /// <param name="dgv1">결과를 출력할 DataGridView를 선택합니다.</param>
        private void ShowDataFromDataTableToDataGridView(DataTable dt1, DataGridView dgv1)
        {
            dgv1.Rows.Clear(); // 이전 정보가 있을 경우, 모든 행을 삭제합니다.
            dgv1.Columns.Clear(); // 이전 정보가 있을 경우, 모든 열을 삭제합니다.

            foreach (DataColumn dc1 in dt1.Columns) // 선택한 파일 목록이 들어있는 DataTable의 모든 열을 스캔합니다.
            {
                dgv1.Columns.Add(dc1.ColumnName, dc1.ColumnName); // 출력할 DataGridView에 열을 추가합니다.
            }

            int row_index = 0; // 행 인덱스 번호(초기 값)
            foreach(DataRow dr1 in dt1.Rows) // 선택한 파일 목록이 들어있는 DataTable의 모든 행을 스캔합니다.
            {
                dgv1.Rows.Add(); // 빈 행을 하나 추가합니다.
                foreach (DataColumn dc1 in dt1.Columns) // 선택한 파일 목록이 들어있는 DataTable의 모든 열을 스캔합니다.
                {
                    dgv1.Rows[row_index].Cells[dc1.ColumnName].Value = dr1[dc1.ColumnName]; // 선택 행 별로, 스캔하는 열에 해당하는 셀 값을 입력합니다.
                }
                row_index++; // 다음 행 인덱스를 선택하기 위해 1을 더해줍니다.
            }

            foreach(DataGridViewColumn drvc1 in dgv1.Columns) // 결과를 출력할 DataGridView의 모든 열을 스캔합니다.
            {
                drvc1.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells; // 선택 열의 너비를 자동으로 설정합니다.
            }
        }

위 두개의 매서드가 포함된 버튼 클릭 이벤트를 다음과 같이 추가합니다.

        private void button1_Click(object sender, EventArgs e)
        {
            CommonOpenFileDialog dialog = new CommonOpenFileDialog(); // 새로운 폴더 선택 Dialog 를 생성합니다.
            dialog.IsFolderPicker = true; // 
            if (dialog.ShowDialog() == CommonFileDialogResult.Ok) // 폴더 선택이 정상적으로 되면 아래 코드를 실행합니다.
            {
                label2.Text = dialog.FileName; // 선택한 폴더 이름을 label2에 출력합니다.
                DataTable dt_filelistinfo = GetFileListFromFolderPath(dialog.FileName);
                ShowDataFromDataTableToDataGridView(dt_filelistinfo, dataGridView1);
            }
        }

전체 코드가 포함된 화면은 다음과 같습니다.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using Microsoft.WindowsAPICodePack.Dialogs;
using System.IO;

namespace WindowsFormsFileList
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            CommonOpenFileDialog dialog = new CommonOpenFileDialog(); // 새로운 폴더 선택 Dialog 를 생성합니다.
            dialog.IsFolderPicker = true; // 
            if (dialog.ShowDialog() == CommonFileDialogResult.Ok) // 폴더 선택이 정상적으로 되면 아래 코드를 실행합니다.
            {
                label2.Text = dialog.FileName; // 선택한 폴더 이름을 label2에 출력합니다.
                DataTable dt_filelistinfo = GetFileListFromFolderPath(dialog.FileName);
                ShowDataFromDataTableToDataGridView(dt_filelistinfo, dataGridView1);
            }
        }

        private DataTable GetFileListFromFolderPath(string FolderName)
        {
            생략(매서드1)
        }

        private void ShowDataFromDataTableToDataGridView(DataTable dt1, DataGridView dgv1)
        {
            생략(매서드2)
        }
    }
}

실행하면 다음과 같이 나타납니다.

우선 하위 폴더 포함이 안되어 있을 경우에는 아래 그림과 같이 결과가 출력됩니다.

파위폴더 포함된 경우에는  아래 그림과 같이 결과가 출력됩니다.

감사합니다.

+ Recent posts