마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

액티비티 간 데이터 전송과 xml 파일 연결

0 추천

pdf 뷰어 앱을 하나 만들고 있습니다.

앱에서 pdf 파일을 찾아 여는 건 문제가 없는데, 반대로 pdf 파일을 눌러 "사용할 애플리케이션" 목록에서 제 앱을 실행하면 해당 파일이 열리도록 하는 것이 잘 되지 않네요.

 

아래는 sd카드에 저장된 pdf 파일을 목록으로 보여주는 MainActivity.java 파일의 일부입니다.

    private void init() {
        lv_pdf = (ListView)findViewById(R.id.lv_pdf);
        dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
        fn_permission();

        lv_pdf.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                Intent intent = new Intent(MainActivity.this, PdfActivity.class);
                intent.putExtra("position", i);
                startActivity(intent);
                Log.e("Position", i + "");
            }
        });
    }

init()의 setOnTimeClickListener() 메소드 내에서 pdf 파일 목록 중 하나를 클릭하면, 그 데이터가 PdfActivity.java 파일로 전송되도록 하였습니다.(position은 파일의 위치 값입니다)

 

아래는 클릭한 pdf 파일의 내용을 표시하는 PdfActivity.java 파일의 일부입니다.

    private void init() {
        Intent intent = getIntent();
        pdfView = (PDFView)findViewById(R.id.pdfView);
        position = intent.getIntExtra("position",-1);
        displayFromSdcard();
    }

위의 MainActivity.java 파일에서 전송한 데이터를 이곳의 getIntent()가 받습니다.

 

문제는 이게 앱에서 파일에 접근했을 때를 기준으로 만들다 보니 파일에서 앱으로 접근할 때는 어떻게 해야 할지 모르겠다는 점입니다. 인터넷을 찾아보니 "사용할 애플리케이션 목록"에 앱을 띄울 때는 보통

Intent intent = new Intent(Intent.ACTION_VIEW);

이렇게 선언한 다음 manifest 파일에서

action android:name="android.intent.action.VIEW"

로 처리하더라구요. 그런데 저는 ACTION_VIEW를 사용하지 않았기 때문에 어떻게 해야 할지 모르겠습니다.

 

    <com.github.barteksc.pdfviewer.PDFView
        android:id="@+id/pdfView"
        android:layout_margin="10dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

PdfActivity.java가 받은 데이터를 가지고 pdf 파일 내용을 출력하는 xml 파일입니다. 제가 pdf 뷰어의 기본적인 기능은 외부 라이브러리에서 가져왔기 때문에 위와 같이 GitHub의 주소를 사용하고 있습니다.

 

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.pdffilefromsdcard">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity
            android:name=".MainActivity"
            android:screenOrientation="portrait">
            <intent-filter>
                <category android:name="android.intent.category.LAUNCHER" />
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>

        <activity
            android:name=".PdfActivity"
            android:screenOrientation="portrait"
            android:parentActivityName=".MainActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.pdffilefromsdcard.MainActivity" />
            <intent-filter >
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="application/pdf" />
            </intent-filter>
        </activity>

    </application>

</manifest>

이렇게 라이브러리 주소를 이용해 manifest 파일을 작성했는데 pdf 파일을 눌렀을 때 나오는 "사용할 애플리케이션" 목록에는 제 앱이 전혀 뜨지 않습니다.

 

해결 방법 좀 부탁드리겠습니다.

LinCass (320 포인트) 님이 2017년 11월 10일 질문
LinCass님이 2017년 11월 13일 수정

1개의 답변

+1 추천
찾아 보니, 다음과 같습니다.

Manifest.xml 파일에 해당하는 Activity 안에 아래를 정의합니다. 그러면 PDF를 외부 파일 브라우저 같은 곳에서 열었을 때, 뷰어 중의 하나로 뜹니다.

<intent-filter >
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="application/pdf" />
</intent-filter>

그리고 다른 곳에서 부르려면 다음과 같이 해야 합니다.

File pdfFile = new File(Environment.getExternalStorageDirectory(),"namePdfFile.pdf");//File path
if (pdfFile.exists()) //Checking for the file is exist or not
{
    Uri path = Uri.fromFile(pdfFile);
    Intent objIntent = new Intent(Intent.ACTION_VIEW);
    objIntent.setDataAndType(path, "application/pdf");
    objIntent.setFlags(Intent. FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(objIntent);//Staring the pdf viewer
} else {
    Toast.makeText(getActivity(), "The file not exists! ", Toast.LENGTH_SHORT).show();
}
Will Kim (43,170 포인트) 님이 2017년 11월 10일 답변
이걸 MainActivity.java에 추가해야 하나요, 아니면 데이터를 받는 PdfActivity.java 파일에 추가해야 하나요?
그리고 intent-filter 부분에서 Missing URL 오류가 납니다. 전 웹 브라우저 URL을 쓰지 않는데 이건 어떻게 바꿔야 하는 건지 모르겠네요.
Main에서 받아서 다시 호출해 줘도 되고요. (이런 경우 뭐 Splash 화면을 보여주어야 한다면..) 직접 PDFAct.도 보내도 되고요. 상관없습니다. 앱의 구조에 따라서 달려 있을 것 같습니다. 어찌 되었던 사용자의 입장에서는 바로 PDF가 보이는게 낫겠죠.
Missing URL 오류를 좀 정확하게 알려 주세요. 로그캣에서 나오는 메시지 등, 똑같이 작성해 주세요. 화면 캡쳐가 더 도움이 될 수도 있겠네요.
일단 PdfActivity.java 파일의 init() 메소드에 추가를 했습니다. 그랬더니 "사용할 애플리케이션" 목록에 앱은 뜨는데, 실행시키면 "앱이 중단됨"이라면서 강제종료되네요.

로그캣을 보니 좀 길긴 한데 아래 메시지가 나옵니다.

11-10 16:10:49.305 2728-2728/? E/BoostFramework: BoostFramework() : Exception_1 = java.lang.ClassNotFoundException: Didn't find class "com.qualcomm.qti.Performance" on path: DexPathList[[],nativeLibraryDirectories=[/system/lib64, /vendor/lib64]]

11-10 16:11:22.228 2728-2728/? E/AndroidRuntime: FATAL EXCEPTION: main
                                                 Process: com.pdffilefromsdcard, PID: 2728
                                                 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.pdffilefromsdcard/com.pdffilefromsdcard.PdfActivity}: java.lang.ArrayIndexOutOfBoundsException: length=10; index=-1
                                                     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2917)
                                                     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2978)
                                                     at android.app.ActivityThread.-wrap14(ActivityThread.java)
                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1628)
                                                     at android.os.Handler.dispatchMessage(Handler.java:102)
                                                     at android.os.Looper.loop(Looper.java:154)
                                                     at android.app.ActivityThread.main(ActivityThread.java:6646)
                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
                                                  Caused by: java.lang.ArrayIndexOutOfBoundsException: length=10; index=-1
                                                     at java.util.ArrayList.get(ArrayList.java:413)
                                                     at com.pdffilefromsdcard.PdfActivity.displayFromSdcard(PdfActivity.java:84)
                                                     at com.pdffilefromsdcard.PdfActivity.init(PdfActivity.java:80)
                                                     at com.pdffilefromsdcard.PdfActivity.onCreate(PdfActivity.java:42)
                                                     at android.app.Activity.performCreate(Activity.java:6912)
                                                     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
                                                     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2870)
                                                     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2978) 
                                                     at android.app.ActivityThread.-wrap14(ActivityThread.java) 
                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1628) 
                                                     at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                     at android.os.Looper.loop(Looper.java:154) 
                                                     at android.app.ActivityThread.main(ActivityThread.java:6646) 
                                                     at java.lang.reflect.Method.invoke(Native Method) 
                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468) 
                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358) 
t com.pdffilefromsdcard.PdfActivity.displayFromSdcard(PdfActivity.java:84)
상기를 보며 PdfActivity.java의 84번째 줄에서,
아래와 같은 OutOfBoundsException이 났습니다. -1번째 인덱스를 접근할 수는 없습니다.
java.lang.ArrayIndexOutOfBoundsException: length=10; index=-1

디버깅 해 보세요.
그리고 가장 좋은 방법은 동자하는 오픈소스를 찾아서 구동해 보고 동작하면, 그 샘플에서 기능들을 뜯어와서 붙이는 방법입니다.
자주하면 더 빨리 할 수 있습니다. 남의 코드를 보는 눈도 훈련이 되어야 하니까요.
답변 감사합니다. 사실 오픈소스 프로그램도 찾아보긴 했는데 썩 만족스럽진 않아서요. 일단 직접 디버깅 해보겠습니다.
java.lang.ArrayIndexOutOfBoundsException: length=10; index=-1
디버깅하면 알겠지만, length가 10이면 정상적으로 데이터가 들어가 있는데요.
소스에서 해당 객체의 index -1을 참조하면서 Out of bound 에러가 난 겁니다.
객체의 length가 10이면, 정상적인 index는 0에서 9 사이에서 접근해야 합니다.
뭔가 계산을 잘못했을 겁니다.
그런데 Manifest.xml 파일에서 <intent-fitler> 부분에 Missing URL 에러가 뜨는 건 어떻게 해야 할까요...
 <action android:name="android.intent.action.VIEW" />
이 녀석이 url을 필요로 하는 것 같은데 Uri path = Uri.fromFile(pdfFile); 에서 url을 넣어준 것 아닌가요?
intent 함수 참 어렵네요;
missing url이 뜨는 오류 메세지를 캡쳐해야 할 것 같네요.
그리고 Manifest 파일도 있어야겠네요.
Manifest 파일의 전문을 수정해서 올려놓았습니다.
그리고 missing url 오류 메시지는 이렇게만 뜨네요.

Ensure the URL is supported by your app, to get installs and traffic to your app from Google Search.

앱이 지원하는 URL을 확실하게 적고 설치 위치와 트래픽 정보를 가져와라? 라는 소리 같은데 무슨 소리인지 모르겠네요;; 웹 URL 같은 건 쓰지 않는데...
App Link를 제공하기 위해서는 관련 정보가 웹 사이트로부터 제공이 되어야 하나 보내요. 그건 사용자에게 해당 앱의 정보를 제공하자 하는 목적이 있는 것 같습니다.

아래의 내용을 정독해야 할 필요가 있어 보입니다. 아무나 앱을 만들어서 등록 할 수 있으므로 절차를 좀 더 둔 것 같네요. (그냥 제 느낌임.)

https://stackoverflow.com/questions/34367875/android-adding-at-least-one-activity-with-an-action-view-intent-filter-after-u
...