2017-01-19 1 views
0

ArrayAdapter를 사용하여 항목 목록을 표시하고 HttpURLConnection을 통해 이러한 항목을로드하는 AsyncTask 스레드가 있습니다. 이 항목 목록을 사용자가 앱을 실행하는 첫 번째 것으로보고 싶습니다. 로드가 비동기 태스크 (AsyncTask)로 된 이유는이로드가 완료 될 때까지 실행을 기다리는 것이 나쁜 습관이라는 것입니다. 그 동안 표시되는 SharedPreferences에 저장된 로컬 데이터가 있습니다.백그라운드에서 데이터로드 중, 어댑터 업데이트 중?

아쉽게도 AsyncTask에서 직접 어댑터를 수정할 수 없습니다.

java.lang.IllegalStateException: Make sure the content of your adapter is not modified from a background thread, but only from the UI thread.

난 그냥 배경 작업이 이루어집니다 UI 스레드를 통지 신호를 필요로 가정; 어댑터가 아닌 다른 데이터 구조에 데이터를로드하도록 코드를 수정할 수 있으며, UI 스레드는 작업이 완료되었음을 알게되면 어댑터에 추가 할 수 있습니다. AsyncTask가 완료 될 때까지 기다리지 않고이 작업을 수행하는 방법을 알지 못합니다.이 작업은 기본 UI 스레드에서 데이터가로드 될 때까지 기다리는 것과 같습니다.

어떻게해야합니까?

public class MainActivity extends AppCompatActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main_activity); 
     ... 
     LoadAnnouncementDataFromAPI announcementAPIQuery = new LoadAnnouncementDataFromAPI(); 
     announcementAPIQuery.execute(); 
     ... 
    } 

    ... 

    private class LoadAnnouncementDataFromAPI extends AsyncTask<String, String, String> { 

     private String announcementAPI = "http://10.0.2.2:3000/announcements"; 

     @Override 
     protected String doInBackground(String... params) { 
      try { 
       URL url = new URL(announcementAPI); 
       HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); 
       BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); 

       StringBuilder stringBuilder = new StringBuilder(); 
       String line; 
       while ((line = bufferedReader.readLine()) != null) { 
        stringBuilder.append(line).append("\n"); 
       } 
       bufferedReader.close(); 
       return stringBuilder.toString(); 
      } catch (IOException e) { 
       return ""; 
      } 
     } 

     @Override 
     protected void onPostExecute(String queryResponse) { 
      if (queryResponse != null && !queryResponse.equals("")) { 
       try { 
        JSONArray apiResponse = new JSONArray(queryResponse); 
        for (int i = 0; i < apiResponse.length(); i++) { 
         JSONObject announcementJSON = apiResponse.getJSONObject(i); 
         if (!announcementJSON.getString("id").equals("")) { 
          mAnnouncementAdapter.items.add(new AnnouncementBlock(announcementJSON)); 
         } 
        } 
        mAnnouncementAdapter.notifyDataSetChanged(); 
       } catch (JSONException e) { 
        return; 
       } 
      } 
     } 
    } 
} 
+0

사용 publishProgress – Submersed

+0

이해가 안 돼요? – Divers

답변

1

그냥 asynTask에 리스너를 추가하는 것입니다. 콜백을 받으면 업데이트 코드가 UI 스레드에서 실행되는지 확인하십시오.

일부 코드

1 - 콜백 인터페이스

interface OnAddListener { 
    void onAdd (AnnouncementBlock announcementBlock); 
} 

2 - 클래스 변경합니다

class LoadAnnouncementDataFromAPI extends AsyncTask<String,String,String> { 
    OnAddListener listener; 

    public void setOnAddListener(OnAddListener listener) { 
     this.listener = listener; 
    } 

    LoadAnnouncementDataFromAPI(OnAddListener listener) { 
     this.listener = listener; 
     // Or may be pass it to the constructor... 
    } 

    protected String doInBackground(String... params) { 
     // Your logic 
     // And then! 
     if(listener!=null){ 
      listener.onAdd(new AnnouncementBlock(announcementJSON)); 
     } 
     // ... 
    } 
} 

3 - 당신은 당신의 콜백 활동을 형성 얻을 수 있습니다. 나는 액티비티가 인터페이스를 직접적으로 구현하는 접근 방식을 좋아하지만 (아마도 final 키워드를 피하기 위해) 그렇지 않으면 할 수있다. 당신이 그것을 표시하기 전에 데이터를 가져옵니다 때까지 기다려야 함을 궁금해하는 이유

// Notice that the activity is implementing the OnAddListener interface. 
class YourActivity extends Activity implements OnAddListener { 

    // ... Some logic life cycle callbacks 

    // I suppose you're doing something similar 
    private void startUpdating(){ 
     mLoadAnnouncementDataFromAPI.setListener(this); // set the listener. 
    } 

    // Your callback. 
    @Override 
    public void onAdd(final AnnouncementBlock announcementBlock) { 
     runOnUiThread(new Runnable() { 
      @Override 
      public void run() { 
       // Now you're sure it's running in the UI thread ;) 
       mAnnouncementAdapter.items.onAdd(announcementBlock); 
      } 
     }); 
    } 
} 
+0

'runOnUiThread'를 사용하면 효과가있는 것 같습니다. 감사! –

0

시도하면 다음과 같은 설정 새로운 데이터를 전달 어댑터의 새로운 인스턴스 생성 기능 setListAdapter로 만들려면 : 당신의 postExecute에

public void setListAdapter (AnnouncementBlock listdata) 
    { 
     If (listAdapter != null){ 
      listAdapter = null; 
     } 
    listAdapter = new MyListAdapter (listdata); 
} 

그리고 전화하여 운전 방식을

당신이 할 수있는