1

내 응용 프로그램에서 서버에서 많은 데이터 (약 3000-4000 레코드)를 다운로드 한 다음 데이터베이스에 삽입합니다. 프로세스는 매우 오랜 시간이 걸리기 때문에 전체 프로세스가 실행되는 동안 진행률 대화 상자를 표시하려고합니다. AsyncTask 클래스 내부에 진행 대화 상자를 구현하여 데이터를 다운로드하고 데이터베이스에 삽입합니다. 여기에 AsyncTask를의 코드는 다음과 같습니다 데이터를 다운로드하는 수행새 스레드에서 데이터베이스에 값을 삽입하면 진행 대화 상자가 닫힙니다.

@Override 
     protected void onPreExecute() { 
      super.onPreExecute(); 
      a.runOnUiThread(new Runnable(){ 
       @Override 
       public void run() { 
        pd.setTitle("Загрузка необходимых данных"); 
        pd.setMessage("Пожалуйста подождите"); 
        pd.setIndeterminate(true); 
        pd.setProgressStyle(ProgressDialog.STYLE_SPINNER); 
        pd.setProgress(0); 
        pd.setCancelable(false); 
        pd.show(); 
       } 
      }); 

     } 

     protected Map<String, String> doInBackground(String... strs) { 
        return getMaterials(); 
     } 

     @Override 
     protected void onPostExecute (Map<String, String> map) { 
      a.runOnUiThread(new Runnable(){ 
       @Override 
       public void run() { 
        pd.dismiss(); 
       } 
      }); 
     } 

public Map<String,String> getMaterials() { 
     int maxNum = getMaxIndex("materials"); 
     Map<String,String> materials = null; 
     DBConnection db = new DBConnection(context); 
     Date end = new Date(System.currentTimeMillis()); 
     String exml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + 
       "<REQUEST format=\"json\" client=\"exstroy\" action=\"get\" enddate=\""+ end.toString() + "\" " + 
       "startdate=\"2000-01-28\" POINT_ID=\"3\" session=\"" + session_id + "\" catalogname=\"nomenclature\" type=\"cataloglist\">" + 
       "<LIST firstmrid = \"0\" lastmrid=\""+ maxNum + "\"></LIST>" + 
       "</REQUEST>"; 
     try{ 
      PrintWriter writer = new PrintWriter(Environment.getExternalStorageDirectory().getPath() + "/data.xml", "UTF-8"); 
      writer.println(exml); 
      writer.close(); 
     } catch (IOException e) { 
     } 

     String charset = "UTF-8"; 
     File uploadFile1 = new File(Environment.getExternalStorageDirectory().getPath() + "/data.xml"); 
     String requestURL = "blahblah.com"; 

     try { 
      MultipartUtility multipart = new MultipartUtility(requestURL, charset); 

      multipart.addFilePart("datafile", uploadFile1); 

      List<String> response = multipart.finish(); 


      materials = new HashMap<String, String>(); 
      String s = "{ " + response.get(1) + "}"; 
      JSONObject json = new JSONObject(s); 
      JSONObject cataloglist = json.getJSONObject("cataloglist"); 

      JSONArray array = cataloglist.names(); 
      //db.clearNomenclature(); 
      ArrayList<Map<String, Object>> data = new ArrayList<Map<String, Object>>(5000); 
      int max = 0; 
      for(int n = 0; n < array.length(); n++) 
      { 
       if (n > max) 
        max = n; 
       JSONObject object = cataloglist.getJSONObject(array.getString(n)); 
       Map<String, Object> map; 
       map = new HashMap<String, Object>(); 
       if (object.has("version")) 
        map.put("version", object.getInt("version")); 
       else 
        map.put("version", 0); 
       if (object.has("name")) 
        map.put("name", object.getString("name")); 
       else 
        map.put("name", ""); 
       if (object.has("uuid")) 
        map.put("uuid", object.getString("uuid")); 
       else 
        map.put("uuid", ""); 
       if (object.has("uuid")) 
        map.put("measure", object.getString("measure")); 
       else 
        map.put("measure", ""); 

       data.add(map); 

       } 
      db.insertNom(data); 
     } catch (IOException ex) { 
      System.err.println(ex); 
     } catch (JSONException e) { 
      e.printStackTrace(); 
     } 
     ArrayList<Map<String, String>> measures = getMeasures(); 
     db.measures(measures); 
     return materials; 
    } 

동안 진행 대화 상자가 나타났다되어 있지만 데이터베이스 삽입에 도달 할 때 진행 대화 상자가 그라운드를 떠납니다.

public void insertNom(final ArrayList<Map<String, Object>> data) { 
     dbOpen(); 
     database.execSQL("CREATE TABLE IF NOT EXISTS "+"nomenclature"+ 
       " ("+"ID"+" INTEGER PRIMARY KEY AUTOINCREMENT, "+ 
       "name TEXT, version INTEGER, measure UUID, uuid UUID)"); 
     dbClose(); 
     Runnable runnable = new Runnable() { 
      @Override 
      public void run() { 
       for (int i = 0; i < data.size(); i++) { 
        dbOpen(); 
        Map<String, Object> map = data.get(i); 
        ContentValues cv = new ContentValues(); 
        cv.put("name", (String) map.get("name")); 
        cv.put("version", (int) map.get("version")); 
        cv.put("uuid", (String) map.get("uuid")); 
        cv.put("measure", (String) map.get("measure")); 
        database.insert("nomenclature", null, cv); 
        dbClose(); 
       } 
      } 
     }; 
     new Thread(runnable).start(); 

    } 

가 나는 또한 나는 단지의 doInBackgroung 방법에 그것을 할 시도, 위의 코드에서 볼 수 있듯이 별도의 스레드에서 작업을 수행하려고 다음은 데이터베이스 삽입 코드의 일부입니다 AsyncTask. 두 방법 모두 진행 대화 상자를 닫습니다. 또한 서버에서 데이터를 다운로드하는 데 3-4 초가 걸리며 데이터베이스에 삽입하는 데 약 20 초 정도 걸립니다. 더 빨리 할 수있는 방법이 있습니까? 진행 대화 상자를 닫는 원인은 무엇입니까?

+0

코드 품질 힌트 : 문자열 리터럴을 모든 곳에서 반복하는 대신 소스 코드에서 ** 상수 **를 사용하는 것이 좋습니다. 그건 ** 슈퍼 나쁜 ** 연습입니다! – GhostCat

+0

@GhostCat 고마워 젠장, 안드로이드에 좀 초보자 오전, 그 나쁜 습관을 없애려고 노력할 것입니다 – Sanzhar

답변

1

테이블에 삽입하려면 약 3000-4000 개의 레코드가 필요합니다. 삽입 속도를 높이기 위해 다음 chnages을 수행 데이터가 다음 테이블에 JSON에서 직접 HashMap으로 된 JSONObject의를 개최 할 필요가 삽입되지 않은 경우

1.합니다. JsonReader을 사용하면 JSON으로 인코딩 된 값을 토큰 스트림으로 읽습니다. 모든 개체에 대해 insert 메서드를 호출합니다. (선택하지만 현재 코드에서 할 경우 다음 또한 컬렉션에서 읽기와 포장 데이터의 시간을 줄일 수)

2. 만 사용 doInBackgroundinsertNom 방법에서 나사를 제거합니다.

doInBackground의 Android db 거래를 사용하여 일괄 삽입합니다. like :

protected Map<String, String> doInBackground(String... strs) { 
     // 1. Open DB 
     // 2. Create Table 

     Map<String, String> materials=getMaterials(); 

     // 3. 
     // START Transaction 
      database.beginTransaction(); 

     //call insertNom method 
      insertNom(materials); 

     // set Successful 
     database.setTransactionSuccessful(); 

      // END Transaction 
     database.endTransaction(); 

     return materials; 
    } 
+0

나는 대량 삽입을 구현하고 그것은 더 빠른 방법이되었다. , 그러나 데이터베이스 삽입이 시작되면 즉시 대화 상자가 닫힙니다. – Sanzhar

+0

@Sanzhar :'onPreExecute'와'onPostExecute'에서'runOnUiThread'를 사용할 필요가 없습니다. bez 두 메소드는 이미 메인 UI에서 실행됩니다. 스레드 : –

+0

@Sanzhar : 또한'onPreExecute'에'pd' 객체를 생성하고 업데이트 된 코드를 보여줍니다. 'insertNom' 메소드에서 스레드를 제거했는지 확인하십시오. –

0

db 삽입이 이미 다른 스레드를 실행중인 AsyncTaskdoInBackground()에 있기 때문에 다른 Runnable 스레드가 필요하지 않습니다.

실행 가능한 블록 제거 :이 작품

//Runnable runnable = new Runnable() { 
//  @Override 
//  public void run() { 
      for (int i = 0; i < data.size(); i++) { 
       dbOpen(); 
       Map<String, Object> map = data.get(i); 
       ContentValues cv = new ContentValues(); 
       cv.put("name", (String) map.get("name")); 
       cv.put("version", (int) map.get("version")); 
       cv.put("uuid", (String) map.get("uuid")); 
       cv.put("measure", (String) map.get("measure")); 
       database.insert("nomenclature", null, cv); 
       dbClose(); 
      } 
//  } 
// }; 
// new Thread(runnable).start(); 

희망을!

+0

내가 이런 식으로 시도했다, 불행히도 그것은 작동하지 않았다 – Sanzhar