ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 안드로이드 멀티스레드
    안드로이드 2020. 5. 9. 17:34
    728x90

    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

    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)

     

    안드로이드 멀티스레드(2)

    2020/05/09 - [Android & Kotlin] - 안드로이드 스레드 2020/05/09 - [Android & Kotlin] - 안드로이드 멀티스레드 이전 글들을 통해서 메인스레드에서 할 수 없는 일을 알아봤으니 이번에는 메인스레드만 할 수..

    bubble-dev.tistory.com

     

    '안드로이드' 카테고리의 다른 글

    안드로이드 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

    댓글

Designed by Tistory.