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

안드로이드 스튜디오 DB 데이터 불러오기 질문

0 추천
제가 지금 DB에서 1분마다 측정되는 데이터를 7일 양을 불러와 PHP에서 1시간 평균을 내고 안드로이드에서 값을 받아 MPAndroidChart에 나타내고 있습니다.

근데 이 부분에서 렉이 좀 심하게 걸리는데 불러오는 데이터 양이 많아서 일까요?

혹시 그렇다면 렉을 줄일 수 있는 방법은 없을까요?
뱅이주인 (120 포인트) 님이 2022년 1월 5일 질문
처리하시는 데이터의 사이즈와 어떻게 구현하셨는지 구체적인 정보가 없으면 말씀드리기가 힘들어요.
제일 중요한 부분이 쓰레드에 관한 것인데, DB핸들링, PHP 호출과 비지니스 로직은 백그라운드 쓰레드에서 처리하셨나요?
그리고 어떻게 DB에 데이터를 집어넣고 가져오는지, 1분마다 어떻게 데이터를 처리하는지 대한 관련 코드도 함께 있으면 좋을 것같네요.
1분 마다 측정되는 값을 넣는건 아두이노에서 처리하게 하였구요!
DB값을 읽어 평균값을 처리하는건 PHP에서 작동하게 하고 안드로이드 스튜디오에서 그 값을 읽도록 하였습니다
쓰레드나 이런 것들은 제가 초보라 잘 모르겠습니다...ㅠㅠㅠㅠ
<?php

    error_reporting(E_ALL);
    ini_set('display_errors',1);

    $conn = mysqli_connect(
        'localhost',
        'tngusdl98',
        'anwlro8533!',
        'tngusdl98'
    );

    $sql = "SELECT date, time, illu FROM Illu WHERE
                            (date = '".date("Y-m-d")."'
                            OR date='".date("Y-m-d", strtotime("-1 days"))."'
                            OR date='".date("Y-m-d", strtotime("-2 days"))."'
                            OR date='".date("Y-m-d", strtotime("-3 days"))."'
                            OR date='".date("Y-m-d", strtotime("-4 days"))."'
                            OR date='".date("Y-m-d", strtotime("-5 days"))."'
                            OR date='".date("Y-m-d", strtotime("-6 days"))."') ORDER BY num";
    
    $result = mysqli_query($conn, $sql);


    $data = array();
    $date = array();
    $time = array();
    $illu = array();

    while($row = mysqli_fetch_array($result)) {
        array_push($date, $row['date']);
        array_push($time, $row['time']);
        array_push($illu, $row['illu']);
    }

    $avg = array();
    $sum = 0;
    $cnt = 0;
    for($i=0; $i<count($date); $i+=1) {
        if($i == 0) {
            $sum += (int)$illu[$i];
            $cnt += 1;
            if($i == count($date)-1) {
                if($sum == 0)
                    array_push($avg, $sum);
                else{
                    $n = strval(round($sum / $cnt));
                    array_push($avg, $n);
                }
            }
        }
        else {
            if($date[$i]===$date[$i-1] && substr($time[$i],0,2)===substr($time[$i-1],0,2)) {
                $sum += (int)$illu[$i];
                $cnt += 1;
                if($i == count($date)-1) {
                    if($sum == 0) {
                        array_push($avg, $sum);
                    }
                    else {
                        $n = strval(round($sum / $cnt));
                        array_push($avg, $n);    
                    }
                }
            }
            else {
                if($sum == 0) {
                    array_push($avg, $sum);
                }
                else {
                    $n = strval(round($sum / $cnt));
                    array_push($avg, $n);
                }
                $sum = 0;
                $cnt = 0;
                $sum += (int)$illu[$i];
                $cnt += 1;
                if($i == count($date)-1) {
                    if($sum == 0) {
                        array_push($avg, $sum);
                    }
                    else{
                        $n = strval(round($sum / $cnt));
                        array_push($avg, $n);
                    }
                }
            }
        }
    }

    for($j=0; $j<count($avg); $j+=1) {
        array_push($data,
            array('avg'=>$avg[$j]));
    }


    header('Content-Type: application/json; charset=utf8');
    $json = json_encode(array("tngusdl98" => $data), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE);
    echo $json;




?>

--PHP 코드 입니다--
PHP코드보다는 안드로이드 쪽 코드가 어떻게 1분마다 데이터를 보내고 받는지가 중요합니다. 화면을 업데이트하는 쓰레드를 메인 쓰레드라고 하는데, 네트워크, 파일 처리와 같은 동작을 메인쓰레드에서 실행하게 되면 메인쓰레드를 블락시켜서 화면에 말씀하시는 프레임 스킵현상이 발생해서 딜레이가 발생할 확률이 높아집니다. 모바일앱에서는 메인쓰레드와 백그라운드 쓰레드를 구분해서 처리해주는 게 아주 중요합니다.
안드로이드에서 1분마다 데이터를 처리하는 것이 아니라 아두이노 기기에서 1분마다 DB에 데이터를 보내는 것이고, 그 저장된 DB를 가지고 어플을 켰을 때 PHP에서 데이터를 평균값을 내서 안드로이드 스튜디오에서 값을 가져오는 것입니다!
class GetIlluAll extends AsyncTask<String, Integer, String> {
        @Override
        protected String doInBackground(String... params) {
            StringBuilder jsonHtml = new StringBuilder();

            String serverURL = (String) params[0];
            String postParameters = "&model=" + model;

            try {
                URL phpUrl = new URL(params[0]);
                HttpURLConnection conn = (HttpURLConnection) phpUrl.openConnection();

                if (conn != null) {
                    conn.setConnectTimeout(10000);
                    conn.setReadTimeout(5000);
                    conn.setRequestMethod("POST");
                    conn.connect();

                    OutputStream outputStream = conn.getOutputStream();
                    outputStream.write(postParameters.getBytes("UTF-8"));
                    outputStream.flush();
                    outputStream.close();

                    if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

                        while (true) {
                            String line = br.readLine();
                            if (line == null)
                                break;
                            jsonHtml.append(line + "\n");
                        }
                        br.close();
                    }
                    conn.disconnect();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return jsonHtml.toString();
        }

        protected void onPostExecute(String str) {
            String TAG_JSON = "tngusdl98";
            String illu = "";

            ArrayList<Entry> standardEntry = new ArrayList<>();
            ArrayList<Entry> entries = new ArrayList<>();

            try {
                JSONObject jsonObject = new JSONObject(str);
                JSONArray jsonArray = jsonObject.getJSONArray(TAG_JSON);

                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject item = jsonArray.getJSONObject(i);

                    illu = item.getString("avg");

                    entries.add(new Entry(i, Float.valueOf(illu)));

                    for (int j = 16000; j <= 27000; j++) { // 최소, 최댓값 설정.
                        standardEntry.add(new Entry(i, j));
                    }
                }

                // 조도 그래프 구현.
                XAxis xAxis = illuGraph.getXAxis();
                xAxis.setDrawGridLines(true);
                xAxis.setDrawLabels(false);
                xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
                xAxis.setAxisLineWidth(1.5f);

                YAxis yAxisLeft = illuGraph.getAxisLeft(); // Y축 오른쪽면 라벨과 선만 그려지게.
                yAxisLeft.setDrawGridLines(true);
                yAxisLeft.setAxisMinimum(0f);
                yAxisLeft.setAxisMaximum(70000f);
                yAxisLeft.setAxisLineWidth(1.5f);

                YAxis yAxisRight = illuGraph.getAxisRight(); // Y축 왼쪽면 비활성
                yAxisRight.setDrawLabels(false);
                yAxisRight.setDrawAxisLine(false);
                yAxisRight.setDrawGridLines(false);

                LineData illuData = new LineData();

                LineDataSet standardSet = new LineDataSet(standardEntry, ""); // 선은 초록색, 선만 그려지게.
                standardSet.setColor(Color.parseColor("#1AB2EBF4"));
                standardSet.setLineWidth(3f);
                standardSet.setDrawCircles(false);
                standardSet.setDrawCircleHole(false);
                standardSet.setDrawValues(false);
                LineDataSet dataSet = new LineDataSet(entries, "조도 그래프"); // 선은 노란색, 원&선만 그려지게.
                dataSet.setColor(Color.parseColor("#FFBB00"));
                dataSet.setLineWidth(1.5f);
                dataSet.setDrawCircles(false);
                dataSet.setDrawCircleHole(false);
                dataSet.setDrawValues(false);

                Legend legend = illuGraph.getLegend(); // Legend 비활성화.
                legend.setEnabled(false);

                SimpleDateFormat todayF = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); // 오늘 날짜 구하기.
                Calendar toCalendar = Calendar.getInstance();
                String today = todayF.format(toCalendar.getTime());

                SimpleDateFormat weekF = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); // 일주일 전 날짜 구하기.
                Calendar weCalendar = Calendar.getInstance();
                weCalendar.add(Calendar.DATE, -6);
                String week = weekF.format(weCalendar.getTime());

                illuGraph.getDescription().setText("조도 데이터 (" + week + " ~ " + today + ")");
                illuGraph.getDescription().setTextSize(8f);
                illuGraph.getDescription().setTextAlign(Paint.Align.RIGHT);
                int width = illuGraph.getWidth();
                int height = illuGraph.getHeight();
                illuGraph.getDescription().setPosition(width - 50, height - 8);

                illuData.addDataSet(standardSet);
                illuData.addDataSet(dataSet);

                illuGraph.setTouchEnabled(false);
                illuGraph.setData(illuData);
                illuGraph.invalidate();
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

-- 이게 안드로이드 스튜디오에서 값을 가져오는 과정이구요! --
어플 켰을 때  한 번만 실행되도록 하였습니다
아두이노와 안드로이드 디바이스는 어떻게 통신을 하나요?
일단 한가지 눈에 먼저 띄는 점은 AsyncTask에서 onPostExecute에서 너무 많은 작업을 하고 있는 것 같이 보입니다. AsyncTask가 doInBackground는 백그라운드 쓰레드에서 동작을 하지만  onPostExecute는 메인 쓰레드에서 동작을 합니다. 그런데 사이즈가 큰 JSON 파싱을 메인쓰레드에서 하게 되면 화면을 블락할 가능성이 있습니다.

for (int j = 16000; j <= 27000; j++) { // 최소, 최댓값 설정.
                        standardEntry.add(new Entry(i, j));
                    }
위와 같은 코드를 보면, 11000개 정도의 데이터를 추가하고 있는데, 상황에 따라 무거운 동작이 될 수 있으므로, 순수하게 화면에 데이터를 업데이트 하는 동작 외에는 백그라운드 쓰레드에서 처리하도록 변경해 보세요.
AsyncTask가 Android 11부터 deprecated 되어서 플레이스토어에 앱을 배포하실 거면 올해까지만 사용하셔야 하긴 합니다만, 이건 나중에 처리하시고 우선은 onPostExecute에서 JSON 파싱하는 부분만 분리해서 doInbackground로 옮기세요.

아래와 같은 개념으로 분리해 보세요. 현재 사용하시고 계신 코드가  복잡한데다 MPChart를 사용하고 계셔서 구체적으로 도와드리가 좀 쉽지않네요.

public class GetIllResult {
   private final List<Entry> standards;
   private final List<Entry> others;
   
   public GetIllResult(List<Entry> standards, List<Entry> others) {
      this.standards = standards;
      this.others = others;
   }

   public List<Entry>  getStandards() {
       return this.standards;
   }

   public List<Entry> getOthers() {
       return this.others;
   }
}


class GetIlluAll extends AsyncTask<String, Integer, GetIllResult>  {

protected GetIIIResult doInBackground(String... params) {
   // 기존코드
   return parseJson(jsonHtml.toString());
}

private GetIllResult parseJson(String str) {
    List<Entry> standardEntry = new ArrayList<>();
    List<Entry> entries = new ArrayList<>();
 
   try {
                JSONObject jsonObject = new JSONObject(str);
                JSONArray jsonArray = jsonObject.getJSONArray(TAG_JSON);

                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject item = jsonArray.getJSONObject(i);

                    illu = item.getString("avg");

                    entries.add(new Entry(i, Float.valueOf(illu)));

                    for (int j = 16000; j <= 27000; j++) { // 최소, 최댓값 설정.
                        standardEntry.add(new Entry(i, j));
                    }
                }
   } catch (JSONException e) {
         e.printStackTrace();
  }

  return new GetIllResult(standardEntry, entries);
}

protected void onPostExecute(GetIllResult result)  {
     List<Entry> standardEntries = result.getStandards();
     List<Entry> entries = result.getOthers();

      //나머지 기존 그래프 그리는 코드
}

}

3개의 답변

0 추천

올리신 코드를 가지 일단 읽기가 좀 편한 구조로 만들어 봤습니다.  그런 다음에 잘 동작하지 않거나 맘에 들지 않는 곳이 있다면 수정하기가 훨씬 쉬워집니다. 일단 역할별로 클래스를 쪼갰습니다.

데이터 응답 클래스

public class HttpResponse<T> {
    private final boolean isSuccess;
    private final T data;
    private final Exception error;

    public HttpResponse(boolean isSuccess, T data, Exception error) {
        this.isSuccess = isSuccess;
        this.data = data;
        this.error = error;
    }

    public HttpResponse(Exception error) {
        this.isSuccess = false;
        this.data = null;
        this.error = error;
    }

    public HttpResponse(T data) {
        this.isSuccess = true;
        this.data = data;
        this.error = null;
    }

    public boolean isSuccess() {
        return isSuccess;
    }

    public T getData() {
        return data;
    }

    public Exception getError() {
        return error;
    }
}

HttpResponse는 Generic를 사용해서 다른 응답에서도 재사용이 가능하도록 했습니다. T는 아직을 어떤 녀석인지 모르지만,
HttpResponse<IlluminanceChartData>처럼 구체적인 클래스를 대입해서 사용하면 컴파일시 T가 사용된 곳들을를 IlluminanceChartData로 대체해 줍니다.

public class IlluminanceChartData {
    private final List<Entry> standards;
    private final List<Entry> illuminances;

    public IlluminanceChartData(List<Entry> standards, List<Entry> illuminances) {
        this.standards = standards;
        this.illuminances = illuminances;
    }

    public List<Entry> getStandards() {
        return standards;
    }

    public List<Entry> getIlluminances() {
        return illuminances;
    }
}

IlluminanceChartData는 standard와 illuminance Entry를 리스트로 갖는 클래스입니다.  AsyncTask 에서 JSON 을 파싱한 결과를 여기에 담을 겁니다.

 

public class IlluminateChartResponse extends HttpResponse<IlluminanceChartData> {
    public IlluminateChartResponse(boolean isSuccess, IlluminanceChartData data, Exception error) {
        super(isSuccess, data, error);
    }

    public IlluminateChartResponse(Exception error) {
        super(error);
    }

    public IlluminateChartResponse(IlluminanceChartData data) {
        super(data);
    }
}

IlluminanceChartResponse는 HttpResposne<IlluminateChartData>와 같습니다. HttpResposne<IlluminateChartData>를 직접 사용해도 되지만 IlluminanceChartResponse를 만들어 사용하는 것이 코드를 읽기가 좀 더 좋을 것같아 만들었습니다.

위의 세 클래스는 PHP에 요청을 보내고 난뒤 파싱결과를 집어넣는데 사용됩니다.

spark (227,830 포인트) 님이 2022년 1월 6일 답변
0 추천

 다음은 Http 요청과 응답을 받는 부분만 분리해서 별도의 클래스로 뺏습니다. 이 클래스역시 약간만 손보시면 다른데서도 재사용이 쉽게 가능합니다.

public class HttpClient {

    public String sendRequest(String endpoint, String postParameters) throws Exception {
        StringBuilder jsonHtml = new StringBuilder();

        URL url = new URL(endpoint);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        if (conn != null) {
            conn.setConnectTimeout(10000);
            conn.setReadTimeout(5000);
            conn.setRequestMethod("POST");
            conn.connect();

            OutputStream outputStream = conn.getOutputStream();
            outputStream.write(postParameters.getBytes(StandardCharsets.UTF_8));
            outputStream.flush();
            outputStream.close();

            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

                while (true) {
                    String line = br.readLine();
                    if (line == null) {
                        break;
                    }
                    jsonHtml.append(line).append("\n");
                }
                br.close();
            }
            conn.disconnect();
        }

        return jsonHtml.toString();
    }
}

 

핵심적인 코드는 이미 사용하신 코드를 그대로 복사했습니다. sendRequest메소드는 예외처리를 직접하지 않고 예외를 밖으로 던집니다. 이 클래스를 사용하는 곳에서 예외처리를 최종적으로 할 겁니다.

다음은 AsyncTask 클래스입니다.

public class GetIlluminanceChartDataTask extends AsyncTask<String, Integer, IlluminateChartResponse> {
    // 외부와는 리스너를 사용하여 통신함.
    interface Listener {
        void onResponse(IlluminateChartResponse response);
    }

    private static final String TAG_JSON = "tngusdl98";

    private final String endpoint;
    private final String postParameters;
    private Listener listener;

    public GetIlluminanceChartDataTask(String endpoint, String postParameters) {
        this.endpoint = endpoint;
        this.postParameters = postParameters;
    }

    public void setListener(Listener listener) {
        this.listener = listener;
    }

    @Override
    IlluminateChartResponse doInBackground(String... params) {
        HttpClient httpClient = new HttpClient();

        try {
            String jsonString = httpClient.sendRequest(endpoint, postParameters);
            IlluminanceChartData chartData = parseJson(jsonString);
            return new IlluminateChartResponse(chartData);
        } catch (Exception e) {
            e.printStackTrace();
            return new IlluminateChartResponse(e);
        }
    }

    private IlluminanceChartData parseJson(String str) throws JSONException {
        List<Entry> standardEntries = new ArrayList<>();
        List<Entry> illuminanceEntries = new ArrayList<>();

        JSONObject jsonObject = new JSONObject(str);
        JSONArray jsonArray = jsonObject.getJSONArray(TAG_JSON);

        for (int i = 0; i < jsonArray.length(); i++) {
            JSONObject item = jsonArray.getJSONObject(i);

            String illuminance = item.getString("avg");
            illuminanceEntries.add(new Entry(i, Float.valueOf(illuminance)));

            for (int j = 16000; j <= 27000; j++) { // 최소, 최댓값 설정.
                standardEntries.add(new Entry(i, j));
            }
        }

        return new IlluminanceChartData(standardEntries, illuminanceEntries);
    }

    @Override
    void onPostExecute(IlluminateChartResponse response) {
        if (listener != null) {
            listener.onResponse(response);
        }
    }
}

 

잘 보시면 Listener 인터페이스가  추가되었습니다. 이 클래스는 View.OnClickListener와 같은 용도로 생각하시면 됩니다. 내가 원하는 작업이 완료되면 이 리스너를 통해 통보를 받기위한 게 주된 목적입니다. onPostExecute에서 모든 처리가 끝나고 결과를 리스너를 통해 알려주게 됩니다. 따라서 이 AsyncTask를 호출하는 곳에서는 Listener 인터페이스를 구현하여 넘겨주면 작업이 끝나고 onResponse를 통해 결과를 받게 됩니다. onResponse를 구현하는 쪽에서는 응답결과를 받고나서 뭘할지 작성하면 됩니다. 님의 경우는 차트를 만드는 코드가 위치하겠죠.

 

다음은 챠트를 만드는 클래입니다. 이 클래스는 제가  MPChart를 사용하지 않는 관계로 에러가 있을 수 있습니다. 뼈대가 되는 구조만 가져다 사용하시면 됩니다. 이 클래스에는 기존에 onPostExecute안의 챠트 만드는 코드를 모두 옮기시면 됩니다.

// 조도 그래프 구현.
public class IlluminanceChartBuilder {
    private final IlluminanceChartData chartData;
    private final Graph illuGraph;

    public ChartRenderer(Graph illuGraph, IlluminanceChartData chartData) {
        this.illuGraph = illuGraph;
        this.chartData = chartData;
    }

    private void buildXAxis() {
        XAxis xAxis = illuGraph.getXAxis();
        xAxis.setDrawGridLines(true);
        xAxis.setDrawLabels(false);
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setAxisLineWidth(1.5f);    
    }

    private void buildYAxis() {
        buildYAxisLeft();
        buildYAxisRight();
    }

    // Y축 오른쪽면 라벨과 선만 그려지게.
    private void buildYAxisLeft() {
        YAxis yAxisLeft = illuGraph.getAxisLeft(); 
        yAxisLeft.setDrawGridLines(true);
        yAxisLeft.setAxisMinimum(0f);
        yAxisLeft.setAxisMaximum(70000f);
        yAxisLeft.setAxisLineWidth(1.5f);
    }

    // Y축 왼쪽면 비활성
    private void buildYAxisRight() {
        YAxis yAxisRight = illuGraph.getAxisRight(); 
        yAxisRight.setDrawLabels(false);
        yAxisRight.setDrawAxisLine(false);
        yAxisRight.setDrawGridLines(false);
    }

    // 선은 초록색, 선만 그려지게.
    private LineDataSet buildStandardDataSet() {    
        LineDataSet dataSet = new LineDataSet(chartData.getStandards(), ""); 
        dataSet.setColor(Color.parseColor("#1AB2EBF4"));
        dataSet.setLineWidth(3f);
        dataSet.setDrawCircles(false);
        dataSet.setDrawCircleHole(false);
        dataSet.setDrawValues(false);
        return dataSet;
    }

    private LineDataSet buildIlluminanceDataSet() {
        LineDataSet dataSet = new LineDataSet(chartData.getIlluminances(), "조도 그래프"); // 선은 노란색, 원&선만 그려지게.
        dataSet.setColor(Color.parseColor("#FFBB00"));
        dataSet.setLineWidth(1.5f);
        dataSet.setDrawCircles(false);
        dataSet.setDrawCircleHole(false);
        dataSet.setDrawValues(false);
        return dataSet;
    }

    // Legend 비활성화.
    private void buildLegend() {
        Legend legend = illuGraph.getLegend(); 
        legend.setEnabled(false);
    }

    private void buildCharTitle() {
        SimpleDateFormat todayF = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); // 오늘 날짜 구하기.
        Calendar toCalendar = Calendar.getInstance();
        String today = todayF.format(toCalendar.getTime());

        SimpleDateFormat weekF = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); // 일주일 전 날짜 구하기.
        Calendar weCalendar = Calendar.getInstance();
        weCalendar.add(Calendar.DATE, -6);
        String week = weekF.format(weCalendar.getTime());

        illuGraph.getDescription().setText("조도 데이터 (" + week + " ~ " + today + ")");
        illuGraph.getDescription().setTextSize(8f);
        illuGraph.getDescription().setTextAlign(Paint.Align.RIGHT);
        int width = illuGraph.getWidth();
        int height = illuGraph.getHeight();
        illuGraph.getDescription().setPosition(width - 50, height - 8);
    }

    public void build() {
        buildCharTitle();
        buildLegend();

        buildXAxis();
        buildYAxis();

        illuData.addDataSet(buildStandardDataSet());
        illuData.addDataSet(buildIlluminanceDataSet());

        illuGraph.setTouchEnabled(false);
        illuGraph.setData(illuData);
        illuGraph.invalidate();
    }

}

 

spark (227,830 포인트) 님이 2022년 1월 6일 답변
0 추천

마지막으로

이제 액티비티에서는, 아래처럼 해주시면 됩니다.

public class MyActivity extends AppCompatActivity implments GetIlluminanceChartDataTask.Listener {

    @Override
    public void onCreate(Bundle savedInstances) {
        super.onCreate(savedInstances);
        setContentView(...);

        fetchIlluminateChartData();
    }

    private GetIlluminanceChartDataTask task;

    private void fetchIlluminateChartData() {
        String serverURL = ...
        String postParameters = "&model=" + model;

       task = new GetIlluminanceChartDataTask(
            serverURL, 
            postParameters
        );
        task.setListener(MyActivity.this); // <-- GetIlluminanceChartDataTask.Listener의 instance. MyActivity가 GetIlluminanceChartDataTask.Listener구현하고 있슴.
        task.execute();
    }
    
    @Override
    public void onResponse(IlluminateChartResponse response) {
        if (!response.isSuccess) {
           // showError();
           return; 
        }      

        IlluminanceChartBuilder chartBuilder = new IlluminanceChartBuilder(illuGraph, response.data);
        chartBuilder.build();
    }

   // 라이프사이클 처리가 필요하다면 아래처럼 액티비티가 멈출 때 AsyncTask취소.
   protected void onStop () {
        super.onStop();
        if (task != null) { 
            task.setListener(null);
            task. cancel(true);
        }
   }
}

 위에서 보듯이 AsyncTask와 Activity는 GetIlluminanceChartDataTask.Listener 인터페이스를 통해 데이터를 주고 받을 뿐 서로의 내부적인 부분에 대해서는 신경을 쓸 필요가 없습니다. 이런 콜백 기법은 모바일 개발에서는 아주 빈번하게 사용되니 알아두시면 좋을 것 같습니다.

spark (227,830 포인트) 님이 2022년 1월 6일 답변
spark님이 2022년 1월 6일 수정
...