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

오디오 플레이어 앱 개발, 외부 파일 로드 질문입니다.

0 추천

음악 파일 재생시키는 앱을 만드는 중입니다.
외부 파일 불러오기 버튼을 하나 만들어서, 그 버튼을 누르면 다운로드 폴더에 있는 파일을
내 앱에 설정한 폴더로 복사 한 후 플레이 시키려고 합니다.

문제는 외부 파일 불러오기 버튼을 누르면

java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
at android.database.CursorWindow.nativeGetString(Native Method)
at android.database.CursorWindow.getString(CursorWindow.java:451)
at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51)
at android.database.CursorWrapper.getString(CursorWrapper.java:137)
at kr.co.work.cordplayer.tools.Utilities.getPath(Utilities.java:34)

이와 같은 오류가 발생하고 있습니다.
액티비티 쪽 소스 입니다.

  public boolean onOptionsItemSelected(MenuItem item) {
      switch (item.getItemId()) {
          case R.id.btnLoadFile :
              Intent intent = new Intent(Intent.ACTION_GET_CONTENT) ;
              intent.setType("audio/*") ;
              startActivityForResult(Intent.createChooser(intent, "재생 파일 불러오기"), 0) ;
              return true ;
          default :
              return super.onOptionsItemSelected(item) ;
      }
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      if (resultCode == RESULT_OK) {
          try {
              Uri selectedDataFileUri = data.getData();
              String selectedDataFilePath = Utilities.getPath(getApplicationContext(), selectedDataFileUri);
              if (Utilities.isAllowFileExtention(selectedDataFilePath)) {
                  InputStream is = null;
                  OutputStream os = null;
                  try {
                      File selectedDataFile = new File(selectedDataFilePath);
                      File destFile = new File(recorderUtilities.getStoragePath(), selectedDataFile.getName());
                      is = new FileInputStream(selectedDataFile);
                      os = new FileOutputStream(destFile);
                      byte[] buffer = new byte[1024];
                      int length;
                      while ((length = is.read(buffer)) > 0) {
                          os.write(buffer, 0, length);
                      }
                  } catch (FileNotFoundException fnfe) {
                      throw new Exception(fnfe);
                  } finally {
                      try {
                          if (is != null) is.close();
                      } catch (IOException ioe) {
                          ioe.printStackTrace();
                      }
                      try {
                          if (os != null) os.close();
                      } catch (IOException ioe) {
                          ioe.printStackTrace();
                      }
                  }
                  initRecordingFilesList();
              } else {
                  toast = Toast.makeText(this, getString(R.string.list_load_file_not_support), Toast.LENGTH_SHORT) ;
                  toast.show() ;
              }
          }
          catch (Exception e) {
              toast = Toast.makeText(this, getString(R.string.list_load_file_not_use), Toast.LENGTH_SHORT) ;
              toast.show() ;
              e.printStackTrace();
          }
      }
  }

아래는 유틸리티의 소스 입니다.

public class Utilities {
    private static final String[] LIST_ALLOW_FILE_EXT = { "wav", "mp3", "m4a" } ;
    public static boolean isAllowFileExtention(String fileName) {
        if (fileName == null || fileName.trim().length() == 0) return false ;
        String fileExt = fileName.substring(fileName.length() - 3) ;
        return fileExt.trim().length() != 0 && Arrays.asList(LIST_ALLOW_FILE_EXT).contains(fileExt.toLowerCase()) ;
    }

    public static String getPath(final Context context, final Uri uri) {
        Cursor cursor = null ;
        String path = null ;
        try {
            cursor = context.getContentResolver().query(uri, null, null, null, null) ;
            cursor.moveToFirst() ;
            path = cursor.getString( cursor.getColumnIndex( "_data" ) );
        } finally {
            cursor.close() ;
        }
        return path;
    }
}

위 붉은 글씨 부분에서 오류가 발생하고 있습니다.

파일을 복사해서 가져오는 이유는 재생 시간 표시나 파일명 변경등을 하기 위해서 원래 저장된 곳을 알아 낸 후, 내 앱에 설정한 폴더로 복사해오는것입니다.

혹시 위와 같은 오류나, 혹은 외부 파일의 저장경로를 가져오는 코드등을 알고계시면 좀 도와주세요. ㅠㅠ
3일을 검색했는데 원하는 답변은 없습니다.
이렇게 하면 될거다~ 해서 소스만 열심히 고쳐서 테스트 하고 있습니다만 해결될 기미는 보이지 않네요 ㅠㅠ

 그리고 제가 만든 앱에서 파일을 지웠는데 (탐색기에서 임의로 넣은 파일) 외부파일 불러오기에서 내 앱 폴더를 선택하면, 지운 파일이 있는건 왜 그런건가요??

초보어플러 님이 2016년 11월 21일 질문

1개의 답변

0 추천
쿼리결과 카운트가 0이어서 발생하는 오류입니다. cursor.getCount 함수로 예외처리 해주셔야합니다.

그리고 지운파일이 보이신다는것이 혹시 파일사이즈가 0인상태로 남는것을 말씀하시는거면 파일핸들을 닫아주지 않았을때 발생하는것이고 위 방식처럼 미디어스토어 쿼리했을때 남는거면 미디어스캔이 이루어지지 않아서 남는거일거에요
Development Guy (70,570 포인트) 님이 2016년 11월 22일 답변
답변 감사합니다!

그런데 다운로드 받아서 폴더에 있는 파일인데 왜 카운트가 0이 나오는건가요?;;

그리고 내 앱애서 저장한 파일을 삭제할때도 미디어 스캔을 해서 갱신해줘야하나요?
파일시스템과 안드로이드 운영체제상의 미디어스토어가 반드시 일치 하지는 않습니다. 파일시스템상에 저장되어도 미디어스토어에 저장을 해주지 않는다면 충분히 발생할 수 있는 문제입니다. 상용 어플리케이션들(카메라, 탐색기 등)도 이를 지켜야지만 미디어스토어 쿼리시에 조회가 가능합니다.

만약 미디어스토어에 관계 없이 무결성을 보장 받으려면 미디어스토어가 아니라 실제 파일 시스템으로 접근하셔야 합니다.

삭제도 마찬가지로 삭제 이후 명시적으로 미디어 스캔을 해주지 않으면 미디어스토어 프로바이더에서는 이를 모르기 때문에 존재하는 파일로 간주하고 있지도 않은 파일을 있는것처럼 결과를 내려줍니다.
...