-
안드로이드 멀티스레드안드로이드 2020. 5. 9. 17:34728x90
2020/05/09 - [Android & Kotlin] - 안드로이드 스레드에 이어서 본격적인 멀티스레드에 대해서 알아볼게요
지난 글에서 스레드간에 자원을 공유하는것이 가능은 하나 원하는대로 되지는 않는다는것은 보았어요.
메인 스레드와 작업 스레드(UI-Thread and Worker Thread)
메인 스레드 혹은 ui 스레드라고 불리우는 이 스레드는 우리가 앱을 실행시키면 프로세스가 자동으로 만들어줘요
따라서 개발자가 별도의 작업 스레드를 만들지 않는 한 모든 코드는 메인 스레드에서 동작한다. 라고 보면 됩니다.
메인스레드가 처리할 수 없는 작업이 있기 때문에 우리는 작업 스레드에 대해 배워야 하는데요.
<layout/activity_main.xml>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <Button android:id="@+id/btn" android:text="버튼" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
<MainActivity.java>
package kr.co.sample; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn = findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "버튼 클릭!", Toast.LENGTH_SHORT).show(); } }); } @Override protected void onResume() { super.onResume(); for (int i = 0; i < 1000; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
이 상태에서 Run 하고, 버튼을 두 번 클릭해보면 ANR 이 발생합니다. (SOS 아이콘은 무시해주세요)
ANR
Application Not Responding 의 약자로 위 사진처럼 경고 메시지가 뜨는 것을 ANR 이라고 불러요
안드로이드는 앱의 반응성을 되게 자주 검사합니다.
ANR 발생 조건
- 액티비티가 5초 이상 사용자의 입력에 반응하지 않을 때
- 브로드캐스트 리시버가 10초 또는 60초 내로 리턴되지 않을 때
- 서비스가 20초 동안 메인 스레드를 잡고 있을 때
지금 같은 경우에는 버튼을 클릭하면 for 문으로 인해 1000초뒤에 onClick이 리턴되므로 1000초 동안은 메인 액티비티는 클릭 이벤트를 처리할 수 없어요
그래서 재밌는 실험으로 버튼을 두 번 클릭하지 않고 한 번만 클릭하거나 1000초 뒤에 클릭하게 되면 ANR 이 발생하지 않아요
스트릭트 모드(Strict mode)
안드로이드에서는 다음 세 가지를 메인스레드에서 할 수 없는 일로 정의했습니다.
- 디스크에 파일 쓰기
- 디스크에 파일 읽기
- 네트워크 사용
이들을 스트릭트 모드라고 부릅니다.
스트릭트 모드를 위반하게 되면 ANR이 발생합니다.
스트릭트 모드는 모두 시간이 오래 걸리는 작업들입니다.
실습
메니페스트 파일에 <uses-permission android:name="android.permission.INTERNET"/> 를 추가해줍니다.
<AndroidManifest.xml>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="kr.co.sample"> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
<MainActivity.java>
package kr.co.sample; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); try { URL url = new URL("https://m.naver.com"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(10000); connection.setRequestMethod("GET"); connection.setDoInput(true); connection.setDoOutput(true); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line = null; while (true) { line = reader.readLine(); if (line == null) break; Log.d("네이버~~", line); } reader.close(); connection.disconnect(); } } catch (Exception e) { e.printStackTrace(); } } }
결과
정리하자면 메인 스레드에서는 시간이 오래 걸리는 작업을 해서는 안됩니다.
해결하려면 시간이 오래 걸리는 작업은 작업 스레드에서 하면 됩니다.
작업 스레드 만들기
<MainActivity.java>
package kr.co.sample; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Toast; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 스레드 정의 Thread workerThread = new Thread(new Runnable() { @Override public void run() { try { URL url = new URL("https://m.naver.com"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(10000); connection.setRequestMethod("GET"); connection.setDoInput(true); connection.setDoOutput(true); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line = null; while (true) { line = reader.readLine(); Log.d("네이버~~", line); if (line == null) break; } reader.close(); connection.disconnect(); } } catch (Exception e) { e.printStackTrace(); } } }); // 스레드 실행 workerThread.start(); } }
결과
Runnable 인터페이스에 스레드 실행 시 실행되고자 하는 코드를 적어두고, start() 메소드를 통해 스레드를 실행시키면
Runnable.run() 메소드가 동작하여 내부 코드가 작업스레드로서 처리됩니다.
2020/05/09 - [Android & Kotlin] - 안드로이드 멀티스레드(2)
'안드로이드' 카테고리의 다른 글
안드로이드 CountDownTimer (0) 2020.05.13 Android AsyncTask (0) 2020.05.10 안드로이드 Looper, Message Queue, Handler (0) 2020.05.09 안드로이드 핸들러 (0) 2020.05.09 안드로이드 스레드 (0) 2020.05.09