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

안드로이드 MVC Model 클래스 데이터 등록/수집 관련 질문

0 추천

메인 스레드가 아닌 스레드에서 Model 클래스에 데이터를 저장하고, 저장한 그 데이터를 다시 메인 스레드에서 불러오려면 어떤 방법을 사용해야 할까요?

 

Thread

public class WeatherThread extends Thread {

    // 태그
    private static final String TAG = "WeatherThread";

    // Weather 데이터 클래스
    Weather weather;

    // 데이터를 가져올 URL
    private String URL = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=%EB%8C%80%EC%A0%84+%EB%82%A0%EC%94%A8";

    @Override
    public void run() {
        try {

            // 온도를 담을 String, 기본값 null
            String tem = null;

            // URL의 html을 가져와 저장하는 Document 변수
            Document doc = Jsoup.connect(URL).get();
            // 가져온 html을 담고 있는 doc에서 온도를 표시하는 "temperature_text" 클래스의 값 습득
            Elements temele = doc.select(".temperature_text");
            // 온도 값(temele)의 null 유무 확인
            Boolean isEmpty = temele.isEmpty();

            if (isEmpty != true) { // 온도 값이 존재할 경우(null이 아닐 경우) 실행

                // temele에서 가져온 온도를 tem에 저장
                tem = temele.get(0).text().substring(5);
                weather.setTem(tem); // 여기
}

            // null 유무 및 가져온 온도 값(temele) 로그 출력
            Log.d(TAG, "isEmpty : " + isEmpty + ", tem " + tem);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 

 

Weather Model class

public class Weather {

    public Weather(String tem) {
        this.tem = tem;
    }

    // 온도
    String tem;

    public String getTem() {
        return tem;
    }

    public void setTem(String tem) {
        this.tem = tem;
    }
}

위와 같은 방법으로 저장하고 메인 스레드나 WeatherThread에서 호출하면 NPE가 발생하는데.. 

JunJaBoy (150 포인트) 님이 2022년 8월 15일 질문

1개의 답변

0 추천
 
채택된 답변

콜백을 사용하세요.

public interface WeatherListener {
     void onSuccess(String temperatrue);
     void onError(Exception e);
}

// 액티비티나 프레그먼트에서 라이프사이클에 따라 리스너를 등록/헤제해주어야 하기 때문에
// 간단한 wrapper클래스가 하나 필요할 것 같습니다.
public class WeatherManager {
    
    private WeatherListener listener;

    public void setListener(WeatherListener listener) {
         this.listener = listener;
    } 
    
    public void fetchTemperature() {
         WeatherThread weatherThread = nw WeatherThread(listener);
         weatherThread.run();
    }

}

public class WeatherThread extends Thread {
    
   private WeatherListener listener;

   public WeatherThread(WeatherListener listener) {
        this.listener = listener;
   }

    ...

    @Override
    public void run() {
        try {
 ...
             if (listener != null) listener.onSuccess(tem);
        } catch (Exception e) {
             if (listener != null) listener.onError(e);
        }
    }
}

 

위에서 리스너가 백그라운드 쓰레드에서 호출되기 때문에 화면을 업데이트하려면 호출한 쪽의 리스너의 메소드 처리는 메인쓰레드에서 호출해야 합니다.

public class WeatherActivity extends AppCompatActivity implements WeatherListener {

    private WeatherManager weatherManager;

   public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState);

         weatherManager = new WeatherManager();
       
        button.setOnClickListener{v -> {
            weatherManager.fetchTemperature();
       });
  }

   override fun onStart() {
        super.onStart()
        weatherManager.setListener(this);
    }

    override fun onStop() {
        super.onStop()
        weatherManager.setListener(null)'
    }

   @Override
   public void onSuccess(String temperature) {
     runOnUiThread(...)
   }

   @Override
  public void onError(Exception e) {
      runOnUiThread(...)
 }
}

runOnUiThread: https://developer.android.com/reference/android/app/Activity#runOnUiThread(java.lang.Runnable)

테스트는 안된 코드이긴 하지만, 콜백을 등록하고 메세지를 주고 받는 다은 부분이 핵심입니다.콜백은 사용 후 해제하면 되구요.

spark (227,830 포인트) 님이 2022년 8월 16일 답변
JunJaBoy님이 2022년 8월 16일 채택됨
...