2012-11-27 6 views
2

Android 용 행맨 앱을 작성 중이며 몇 가지 로딩 문제가 있습니다. 내 앱이 시작되면 txt 파일에서 임의의 단어가 선택됩니다. 문제는이 파일이 무겁다는 것입니다 : 거의 360'000 단어 (4000 kB)를 가지므로 한 단어를 선택하는 데 10-20 초의 시간이 걸립니다. 파일을 읽고 매번 단어를 선택하기 때문에 나는 Generate를 클릭한다.android app에서 파일을 읽는 데 너무 많은 시간이 걸립니다.

일단 앱이 시작된 후 파일을 읽고 해당 내용을 String Array에 넣으면 좋을까요? 나는 배열이 이것을 많이 처리 할 수 ​​있는지 정말로 모른다. 그렇지 않으면 좋은 패턴은 무엇입니까?

읽어 주셔서 감사합니다.

+0

피킹 코드를 게시하면 거기에 최적화 할 것이 많습니다. (하나의 옵션, 예를 들면 : sqlite db 만들기, 시작시 복사, 무작위로 선택 순서 만들기, 다른 옵션 : 라인을 고정 폭으로 만들고 단어를 선택하려면 건너 뛰기 (길이 * rand())하십시오) – njzk2

+0

배열은 8000kb (각 문자는 2 바이트) + 360000 * 문자열 개체의 몇 바이트가 될 것이므로 대략 10MB로 반올림하여 메모리에 보관하는 것이 좋습니다. 더하기, 로딩은 여전히 ​​10-20 초 걸릴 것입니다. – njzk2

답변

0

더 많은 속도를 위해 AsyncTask에서 콘텐츠 형식 json/db를 구문 분석 /로드하는 코드를 실행하십시오. 난 행당 ~ 400 문자로 5000 행을로드합니다. 그것은 AsyncTask없이 훨씬 오래 걸립니다. 를 CSV로

AsyncTask developer Guide

+0

나의 늦은 응답에 대해 죄송합니다.이 솔루션이 마침내 나왔습니다.하지만 여전히 문제가 있습니다. 사용자에게 파일로드 중 알리는 progressbar를두고 싶습니다. 그러나 개체를 unserialize 할 때 처리하는 방법은 무엇입니까? 내 생각은 직렬화가 준비되지 않은 동안 카운터를 증가시킬 스레드를 시작하는 것입니다. – onizukaek

0

단어 데이터베이스를 생성하고 임의의 단어를 쿼리 할 수 ​​있습니다. 읽는 것으로 시작할 수 있습니다 Saving Data in SQL Databases

0

전체 파일을 문자열 배열로 읽는 것은 좋은 전략이 아닙니다. 많은 메모리를 소비하기 때문에. 한 가지 간단한 해결책은 대용량 파일을 여러 개의 단일 파일로 분할하는 것입니다 (words1.txt, words2.txt 등의 파일 이름 패턴을 사용). 단어를 그릴 때 먼저 파일을 선택한 다음 파일에서 실제 단어를 선택합니다.

0

파일 읽기는 비용이 많이 드는 작업이며 일반적으로 오래 걸릴 수 있습니다. 아마 하나의 파일 대신 파일 그룹을 만들어야하고 앱을 시작할 때마다 임의의 파일과 임의의 단어를 선택할 수 있습니다. 그러면 시간이 절약됩니다.

또한/res/values ​​/ folder로 이동하는 App 리소스로 XML 파일에 단어 이름을 저장할 수 있습니다. String Array Resources를 생성하고 파일 열기/닫기/읽기에 대해 걱정할 필요없이 코드에서 쉽게 가져올 수 있습니다. 그것은 꽤 간단합니다. 그러나 모든 단어를 다른 XML 파일 (또는 적어도 문자열 배열 그룹)로 분할하는 것이 중요합니다. 자세한 내용은 여기를 참조하십시오. http://developer.android.com/guide/topics/resources/string-resource.html#StringArray

또는 대안은 파일에서 파일을 읽음으로써 DB에 모든 것을 저장하는 것입니다. 이렇게하면 앱을 처음 실행하는 데에만 시간이 걸립니다. "준비 중 ..."또는 이와 비슷한 메시지를 표시 할 수 있습니다.

1

스토어를, (쉼표로 구분 된 값) :

여기
new YourTask().execute(""); 

당신이 AsyncTasks에 대해 자세히 알아볼 수 있습니다 :

private class YourTask extends AsyncTask<String, Void, String> { 
     @Override 
     protected String doInBackground(String... s) { 

      //Here you have to make the loading/parsing tasks 
      //Don't call any UI actions here. For example a Toast.show() this will couse Exceptions 
      // UI stuff you have to make in onPostExecute method 

     } 

     @Override 
     protected void onPreExecute() { 
      // This method will called during doInBackground is in process 
      // Here you can for example show a ProgressDialog 
     } 

     @Override 
     protected void onPostExecute(Long result) { 
      // onPostExecute is called when doInBackground finished 
      // Here you can for example fill your Listview with the content loaded in doInBackground method 

     } 

} 

는 전화가 당신을 실행하려면 . ','을 두 번 칠 때까지 읽기 스트림을 열고 임의의 위치를 ​​찾아 작은 문자 덩어리를 읽습니다. 이제 읽은 문자열에서 쉼표로 단어를 추출하십시오. 또한 '#'또는 '|'와 같은 사용자 정의 구분 기호를 사용할 수 있습니다. 쉼표 대신.

업데이트 : RandomAccessFile을 사용하십시오.

업데이트 2 : readLine()은 한 줄에 한 단어를 저장하면 훨씬 쉽게 만듭니다. 나는.여기의 메모를 취할 \n

+0

기존의 구분 기호 (아마도 '\ n')를 사용하지 않는 이유는 무엇입니까? '\ n'을 ','로 바꾸면 실제로 아무것도 변경되지 않으며 파일을 더 쉽게 편집 할 수 있습니다. 그것 이외에, 나는 위치 N을 찾은 다음 단어의 시작을 앞으로 검색한다는 생각을 좋아합니다. (즉, 긴 단어는 짧은 단어보다 통계적으로 더 많이 선택 될 수 있지만 여기서는 중요하지 않을 수 있음을 의미합니다.) – fadden

0

몇 가지로 구분 :

  1. 를 앱이 SD 카드에서 읽어 경우, SD 카드의 품질은 실제로 요인이다 - 따라 서로 다른 읽기/쓰기 속도가 당신이 사용하고있는 SD 카드의 종류에 - 그것을보세요.

  2. 생성을 클릭 할 때마다 파일에서 임의의 행을 선택한다고 언급했는데 사용자가 두 번 이상 생성을 클릭 할 것이라는 확신을 가질 수 있으므로 해당 파일을 한 번 읽는 것이 좋습니다. 내용을 어딘가에 저장하고 (sqlite) 다음에 임의의 단어를 가져올 필요가있을 때 저장된 데이터에서 가져옵니다. 이렇게하면 외부 저장소 (모바일 표준에있는 무거운 작업)에서 응용 프로그램 시작 당 하나의 작업으로 읽는 횟수를 제한 할 수 있습니다.

  3. 내용이 변경되었는지 여부를 알려주기 위해 파일에 마커를 추가 할 수도 있습니다. 임의의 문자열에서 현재 날짜, md5 체크섬까지의 모든 항목은 파일을 다시 읽을 필요가 없다는 것을 알려야합니다. 이미 전에 읽었 기 때문에 내용을 sqlite db에 저장했기 때문입니다. 이 파일을 파일의 첫 번째 줄에 넣으려고합니다.

  4. 이제는 다른 사람들이 sqlite db에 쓰거나 심지어는 별도로 생성 할 수있는 .db 파일을 복사하는 것을 고려해 보았습니다. 임의의 항목을 선택하는 것은 사소한 일입니다. 오히려 데이터베이스에 360,000 개의 항목을 쓰는 것에 대해 경고하고 싶습니다. 기본 ContentProvider insert(Uri, ContentValues) 메서드를 사용하면 효과가 있지만 실제로 파일 자체를 파싱하는 것보다 시간이 오래 걸리면 놀랄 일은 아닙니다. 여기서 트릭은 ContentProvider의 bulkInsert(Uri, ContentValues[]) 구현을 대신 컴파일 된 명령문을 사용하여 재정의하는 것입니다. 기본 구현은 insert 메서드를 여러 번 호출하므로 SqliteDatabase 개체를 열 때마다 열고 닫을 수 있습니다. 당신이하고 싶은 일은 beginTransaction을 맨 위에두고, for 루프를 가지고 insert 각각의 ContentValues에있는 아이템 들인 setTransactionSuccessful을 호출 한 다음 endTransaction으로 전화하십시오.

관련 문제