며ㅇ어어어엋시간을 날린지 모르겠다. 나눈 리눅스고 firebase때매 sha1이 필요한데 허구한날 오류만 내뱉음

 

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android 
keytool 오류: java.lang.Exception: 키 저장소 파일이 존재하지 않음: /home/내이름/.android/debug.keystore

 

구글문서에는 /.android에 debug.keystore이 있다는데 개뿔 없다 없어서 자꾸 메시지를 내뿜는다

윈도우에서 해결법은 있던데 리눅스에선 못찾겠음ㅇㅇ 포기하려다가 되서 넘 죠음

 

keytool -genkey -v -keystore ~/.android/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"

 

없으면 만들면 된다

 

을 터미널에 다시 입력해주면 SHA1값이 뜬다. 많은 사람들에게 도움이 되길 바람,,

 

https://stackoverflow.com/questions/8576732/there-is-no-debug-keystore-in-android-folder

 

There is no debug.keystore in .android folder

Someone I'm helping with an application needs to locate her debug.keystore - mine is in my .android folder, but when I navigate there on her computer it is not there. Does something need to be don...

stackoverflow.com

 


1. 작업스레드에서 메인스레드로 작업 전달하기




안드로이드에서 작업스레드는 UI작업을 할 수 없으므로 메인 스레드로 작업을 전달하여 작업스레드에서 UI를 변경하는 것처럼 만들어야 합니다.



그 방법으로는 4가지가 있습니다. 


1. Handler.post()

2. Activity.runOnUiThread()

3. view.post()

4. AsyncTask 클래스



이 4가지의 공통점은 작업스레드가 메인스레드로 메시지를 전달한다는 것 입니다.



메인스레드는 내부적으로 Looper을 가지며 그 안에는 메시지큐가 포함됩니다.



메시지큐는 다른 스레다나 혹은 자기 자신으로부터 전달받은 Message를 기본적으로 선입선출형식으로 보관하는 큐입니다.



Looper는 메시지큐에서 메시지나 Runnable객체를 차례로 꺼내 Handler가 처리하도록 전달합니다. 

Handler는 Looper로 부터 받은 메시지를 실행, 처리, 다른스레드로부터 메시지를 전달받아 메시지큐에 넣는 역할을 하는 스레드간의 통신 장치입니다.












2. 구현하기(Handler.post(),Activity.runOnUiThread())




2.1. Handler.post()


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.example.user.myapplication;
 
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
 
public class MainActivity extends AppCompatActivity {
    Handler handler;                //메인 스레드로 작업을 전달할 핸들러
    TextView myThreadText;          //작업스레드의 이름을 출력할 텍트스뷰
    TextView mainThreadText;        //메인스레드의 이름을 출력할 텍트스뷰
 
    String myThreadStr;             //작업스레드의 이름을 출력할 문자열
    String mainThreadStr;           //메인스레드의 이름을 출력할 문자열
 
    boolean flag;                   //스레드 내부의 while문을 제어할 flag
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);     //레이아웃 연결
 
        myThreadText = (TextView) findViewById(R.id.myThreadText);              //출력할 텍스트뷰 연결
        mainThreadText = (TextView) findViewById(R.id.mainThreadText);          //출력할 텍스트뷰 연결
 
        handler = new Handler();        //메인 스레드로 작업을 전달할 핸들러
 
        myThreadStr = "";
        mainThreadStr = "";
        flag = true;
 
        Thread th = new Thread(new Runnable() {
            @Override
            public void run() {
 
                Thread.currentThread().setName("하릐's thread");      //작업스레드의 이름 변경
 
                while(flag){
                    try {
                        myThreadStr += Thread.currentThread() + "\n";
 
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                //메인스레드가 처리한 작업의 번호
                                mainThreadStr += Thread.currentThread() + "\n";
                                mainThreadText.setText(mainThreadStr);
                                myThreadText.setText(myThreadStr);
 
                            }
                        });
 
                        Thread.sleep(1000);         //스레드 대기 (메인스레드 처리)
 
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                 }
            }
        });
 
        th.start();
    }
}
 
cs


핸들러의 post()를 사용해 작업스레드에서 메인스레드로 작업을 전달하고 있습니다.


36번째 줄 Thread.currentThread().setName("하릐's thread"); 는 작업스레드의 이름을 하릐's thread로 변경합니다.


42-48번째 줄에서 작업스레드의 이름과 post내부에서 스레드의 이름을 호출하면 두개의 스레드의 이름이 출력되는 것을 확인할 수 있습니다.




<결과 화면>






2.2. Activity.runOnUiThread()



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.example.user.myapplication;
 
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
 
public class MainActivity extends AppCompatActivity {
    Handler handler;                //메인 스레드로 작업을 전달할 핸들러
    TextView myThreadText;          //작업스레드의 이름을 출력할 텍트스뷰
    TextView mainThreadText;        //메인스레드의 이름을 출력할 텍트스뷰
 
    String myThreadStr;             //작업스레드의 이름을 출력할 문자열
    String mainThreadStr;           //메인스레드의 이름을 출력할 문자열
 
    boolean flag;                   //스레드 내부의 while문을 제어할 flag
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);     //레이아웃 연결
 
        myThreadText = (TextView) findViewById(R.id.myThreadText);              //출력할 텍스트뷰 연결
        mainThreadText = (TextView) findViewById(R.id.mainThreadText);          //출력할 텍스트뷰 연결
 
        handler = new Handler();        //메인 스레드로 작업을 전달할 핸들러
 
        myThreadStr = "";
        mainThreadStr = "";
        flag = true;
 
        Thread th = new Thread(new Runnable() {
            @Override
            public void run() {
 
                Thread.currentThread().setName("하릐's thread");      //작업스레드의 이름 변경
 
                while(flag){
                    try {
                        myThreadStr += Thread.currentThread() + "\n";
 
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                //메인스레드가 처리한 작업의 번호
                                mainThreadStr += Thread.currentThread() + "\n";
                                mainThreadText.setText(mainThreadStr);
                                myThreadText.setText(myThreadStr);
 
                            }
                        });
 
                        Thread.sleep(1000);         //스레드 대기 (메인스레드 처리)
 
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                 }
            }
        });
 
        th.start();
    }
}
 
cs




runOnUiThread의 사용 방법은 handler.post와 유사합니다.




<결과 화면>






3. Handler.post 와 Activity.runOnUiThread의 차이



https://medium.com/@yossisegev/understanding-activity-runonuithread-e102d388fe93































0. 개요



스레드 개념은 아래 링크를 참고하세요.


http://gsgdvxhx.tistory.com/7






1. 스레드 구현하기



자바로 스레드를 만드는 방법은 두가지가 있습니다.


1. Thread 클래스 사용


2. Runnable 인터페이스 사용





1.1. Thread 클래스 사용



스레드는 Thread클래스를 상속받아 구현할 수 있습니다. 단, 자바는 다중상속을 지원하지 않으므로 다른 클래스를 상속 받을 수 없다는 특징이 있습니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class myThread extends Thread{
    
    String myName;
 
    myThread(String myName){
        this.myName = myName;
    }
 
    public static void main(String[] args)
    {
        myThread a = new myThread("첫번째");
        myThread b = new myThread("두번째");
 
        a.start();
        b.start();
    }
 
    @Override
    public void run(){
        for(int i = 0; i < 10; i++){
            try{
                System.out.println(myName + " : " + i);
                Thread.sleep(100);
            }catch(Exception e){e.printStackTrace();}
        }
    }
 
}
cs



1번째 줄 :  myThread 클래스는 Thread를 상속받습니다.


14., 15 번째 줄 : 오버라이딩 된 run함수를 수행 합니다.


19번째 줄 : run함수를 오버라이딩합니다.



start()는 run()을 동작시킵니다. start()를 직접 구현하지 않았지만 Thread를 상속받았기 때문에 start()를 호출하면 run()이 호출됩니다.

start()는 스레드를 실행시키기 전의 환경설정등의 기능을 수행하므로 run()을 호출해서 사용하면 안되고 start()를 사용하여 간접적으로 실행해야 합니다.








1.2. Runnable 인터페이스 구현하여 실행



Runnable 인터페이스를 이용하여 스레드 구현이 가능합니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class myRunnable implements Runnable{
    
    String myName;
 
    myRunnable(String myName){
        this.myName = myName;
    }
 
    public static void main(String[] args)
    {
        myRunnable a = new myRunnable("첫번째");
        myRunnable b = new myRunnable("두번째");
 
        Thread th1 = new Thread(a);
        Thread th2 = new Thread(b);
 
        th1.start();
        th2.start();
    }
 
    @Override
    public void run(){
        for(int i = 0; i < 10; i++){
            try{
                System.out.println(myName + " : " + i);
                Thread.sleep(100);
            }catch(Exception e){e.printStackTrace();}
        }
    }
 
cs





두 예제의 결과는 같습니다.









org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:processDebugResources'.

at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:100)

at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)

at org.gradle.api.internal.tasks.execution.OutputDirectoryCreatingTaskExecuter.execute(OutputDirectoryCreatingTaskExecuter.java:51)

at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)

at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)

at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:60)

at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:97)

at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:87)

at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)

at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)

at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)

at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)

at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)

at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:248)

at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)

at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)

at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)

at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)

at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)

at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)

at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:123)

at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:79)

at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:104)

at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:98)

at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:626)

at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:581)

at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:98)

at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)

at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)

at java.lang.Thread.run(Thread.java:745)

Caused by: org.gradle.tooling.BuildException: Failed to process resources, see aapt output above for details.

at com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask.invokeAaptForSplit(LinkApplicationAndroidResourcesTask.java:512)

at com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask.doFullTaskAction(LinkApplicationAndroidResourcesTask.java:249)

at com.android.build.gradle.internal.tasks.IncrementalTask.taskAction(IncrementalTask.java:106)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:498)

at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)

at org.gradle.api.internal.project.taskfactory.IncrementalTaskAction.doExecute(IncrementalTaskAction.java:46)

at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:39)

at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:26)

at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:121)

at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)

at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)

at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)

at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)

at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:110)

at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:92)

... 32 more

Suppressed: java.lang.RuntimeException: Some file processing failed, see logs for details

at com.android.builder.internal.aapt.QueuedResourceProcessor.waitForAll(QueuedResourceProcessor.java:121)

at com.android.builder.internal.aapt.QueuedResourceProcessor.end(QueuedResourceProcessor.java:141)

at com.android.builder.internal.aapt.v2.QueueableAapt2.close(QueueableAapt2.java:104)

at com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask.doFullTaskAction(LinkApplicationAndroidResourcesTask.java:293)

... 48 more

Caused by: com.android.ide.common.process.ProcessException: Failed to execute aapt

at com.android.builder.core.AndroidBuilder.processResources(AndroidBuilder.java:809)

at com.android.builder.core.AndroidBuilder.processResources(AndroidBuilder.java:797)

at com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask.invokeAaptForSplit(LinkApplicationAndroidResourcesTask.java:491)

... 49 more

Caused by: java.util.concurrent.ExecutionException: java.util.concurrent.ExecutionException: com.android.builder.internal.aapt.v2.Aapt2Exception: AAPT2 error: check logs for details

at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:503)

at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:482)

at com.google.common.util.concurrent.AbstractFuture$TrustedFuture.get(AbstractFuture.java:79)

at com.android.builder.internal.aapt.AbstractAapt.link(AbstractAapt.java:34)

at com.android.builder.core.AndroidBuilder.processResources(AndroidBuilder.java:807)

... 51 more

Caused by: java.util.concurrent.ExecutionException: com.android.builder.internal.aapt.v2.Aapt2Exception: AAPT2 error: check logs for details

at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:503)

at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:462)

at com.google.common.util.concurrent.AbstractFuture$TrustedFuture.get(AbstractFuture.java:79)

at com.android.builder.internal.aapt.v2.QueueableAapt2.lambda$makeValidatedPackage$1(QueueableAapt2.java:166)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

... 1 more

Caused by: com.android.builder.internal.aapt.v2.Aapt2Exception: AAPT2 error: check logs for details

at com.android.builder.png.AaptProcess$NotifierProcessOutput.handleOutput(AaptProcess.java:443)

at com.android.builder.png.AaptProcess$NotifierProcessOutput.err(AaptProcess.java:395)

at com.android.builder.png.AaptProcess$ProcessOutputFacade.err(AaptProcess.java:312)

at com.android.utils.GrabProcessOutput$1.run(GrabProcessOutput.java:104)




에러 내용 엄청 길다. 




여러 원인중 두가지는 아래와 같다.



1.  buildTools의 버전이 맞지 않을 경우.


참고 : https://stackoverflow.com/questions/20737200/execution-failed-appprocessdebugresources-android-studio




2. xml의 내용에 이상이 있는 경우


황당하게도 나는 이 경우에 속한다.


컴포넌트의 이름을 null이라고 해버렸다.. ㅋㅋㅋㅋ 공간차지용이라 딱히 이름에 애정을 갖지 않고 만들어서 아무생각이 없었다.

코드를 직접 짰다면 이런 실수는 안했을텐데, 디자인에서 이름을 짓다보니 의식을 못했다. (핑계중..) 













앱 개발 도중 알게된건 제 핸드폰이 엄청 따뜻해 진다는 것 이였습니다....



평소 29도였던 핸드폰이 앱 구동 시 35도까지 올라가는걸 확인했습니다.



핸드폰이 따뜻해 지는 원인은 크게 네가지가 있습니다.


1. 많은 계산량 (특히 부동 소수점 계산)


2. 무겁고 끝이 없는 루프


3. 큰 파일 다운로드


4. 애니메이션 및 그래픽 (백그라운드에서 많은 연산을 합니다)



사실 저 아직 해결 못봤습니다.. 흑흑



핸드폰이 몇도까지 올라가야 문제가 있는건가요? 35도면 정상이라고 우기고싶어요..



0.5초 단위로 아두이노로부터 문장 하나를 블루투스로 전달받고 핸드폰에서 연산을 하는데, 이때 한번에 전달받은 문장은 35글자 정도입니다.



문장 하나에 5개의 정수가 전달되고 앱에서 정수 뺄셈을 하는게 연산 끝입니다.

(부동소수점 연산도 있긴 하지만 최초실행시 30여개 변수의 평균을 구하는 것이 끝입니다. )



노트4를 사용하고있는데 ... 네가지에 포함되는 것 같지 않아 블루투스 전송량이나 전송 속도를 의심중입니다.. 해결하면 바로 내용 추가해서 글 쓸게요.



+2018-06-16 추가


감을 못잡아서 생코에 올렸더니 많은 분들이 도와주셨습니다 ㅜㅜ


원인은.. 바보같지만 블루투스로 값을 받아오는 스레드에 딜레이가 없었다는.. 사실.. 으.


메모리 누수쪽으로 알아보라는 조언을 듣고 열심히 찾아봤는데 사실 아직 보는법을 잘 모르겠습니다. 월요일에 교수님 찾아가려구요.


해결했따 :) 흐흐 이제 잔버그좀 잡고 팀원이 센서 납땜해 주는대로 다음 기능을 추가해야겠습니다!

 





0. 개요


안드로이드 앱은 5초 이내 아무런 응답을 하지 않을 시 실행 중인 앱을 강제로 종료시킵니다.

이러한 현상을 ANR 현상이라고 합니다.



앱을 만들다 보면 액티비티에서 많은 작업을 수행해야 하는 경우가 있습니다.

이 때 기본적으로 생성되는 main스레드에서 처리를 담당할 경우 ANR현상이 발생할 수 있습니다. 



이를 방지하기 위하여 main스레드의 작업을 작업 스레드를 생성하여 분산시켜야 합니다.



주의해야 할 점은 작업스레드는 화면을 변경하는 작업을 수행할 수 없으며 main스레드만이 화면을 변경할 수 있습니다.

만약 작업스레드에서 UI를 변경할 시 예외가 발생하면서 앱이 중지되게 됩니다.







1. 시작하기 전에


시작하기 전에 스레드 및 멀티스레딩 개념을 이해하고 있어야 합니다.



스레드의 사전적 의미는 '실', '실타래' 입니다. 



컴퓨터 용어로는 ..


1. CPU 제어의 흐름


2. 실행 단위


3. 한 프로세스 내부에서 스케줄링이 가능한 개체


라고 정의할 수 있습니다.



프로세스는 실행되면서 프로세스 내부의 명령어들이 CPU에 의해 처리되는 모습을 상상할 수 있습니다.



프로세스가 실행되는 동안 CPU제어의 흐름을 따라가다 보면 마치 실타래의 실처럼 보일 수 있습니다.

즉, CPU 제어의 흐름이라고 볼 수 있는 것 입니다.



C언어로 만드는 간단한 프로그램들 (심지어 main만 정의된 프로그램들)조차도 결국 하나의 메인 스레드를 갖고 있는 것 입니다.



이와 같이 스레드는 프로세스 내부에 존재하며 프로세스 내부에는 기본적으로 하나의 스레드가 존재하고 있는 것 입니다.



이러한 스레드들은 여러개가 수행될 수 있습니다.



간단한 그림으로 보겠습니다.





한 프로세스 내부에서 두개의 스레드가 동시에 수행되고 있는 것을 확인할 수 있습니다.



이 것을 멀티 멀티 스레딩 이라고 합니다.



프로그램 실행 도중 새로운 스레드가 생성되면 이 스레드는 탄생한 코드로 부터 독립적으로 실행을 진행하게 됩니다.



멀티 스레딩을 왜 사용해야 하는지는 금방 이해할 수 있습니다.



컴퓨터가 단일 스레딩으로 구현되어있다면 재밌는 일이 생길겁니다.


한글로 파일을 수정하고 프린트버튼을 누르면 프린터가 진행되는 동안 아무런 작업을 할 수 없습니다.

웹 서버는 한개의 클라이언트가 요청을 할 경우 그 클라이언트를 전담하는 한개의 스레드를 생성하여 요청을 처리합니다. 

만약 웹 서버가 단일 스레딩으로 구현되어 있다면 100개의 클라이언트가 요청 결과를 받기 위해 한명씩 줄서서 처리받는 구조가 되어 버릴 것 입니다.



멀티 스레딩은 응용프로그램이 다수의 스레드를 가지고 다수의 작업을 동시에 처리함으로써, 시간지연과 자원의 비 효율적 사용을 개선할 수 있습니다.



자바로 스레드를 만드는 방법은 두가지가 있습니다.


1. Thread 클래스 사용


2. Runnable 인터페이스 사용




사용 방법은 다음장에서 설명하겠습니다.


[JAVA] 2. 스레드 사용하기[1]. 스레드 구현하기  


http://gsgdvxhx.tistory.com/10




앱 빌드 도중 gradle build running.. 이 끝나지를 않았다.


gradle파일을 건든적은 있지만 종속성 추가밖에 하지 않았는데.. 방금 전까지 잘 되다가 갑자기 안돼서 당황했다.

차라리 에러라도 뱉으면 어디가 어떻게 잘못되었는지 생각해볼텐데, 에러없이 계속 빌드중이어서 해결하는데 애먹었다.


결론부터 말하자면 이 구문때문이였음..


byte[] buffer = {'h', 'e', 'l', 'l', 'o'};


문자가 자동으로 형변환 될 것이라 생각해서 짰고, 에러도 안떴다.




<해결하기>

아래와 같이 수정해주어야 한다.


string str1 = "hello";

bytes[] buffer = str1.getBytes();


더불어 이 코드도 안된다.


int[] buffer = {'h', 'e', 'l', 'l', 'o'};


int buffer[] = {'h', 'e', 'l', 'l', 'o'};  이렇게 쓰면 c나 c++에선 된다.


근데 자바에서 이건 또 된다.


int a = 'g';



c나 c++에선 int형 배열 선언하고 문자로 초기화시 아스키코드가 넘어오는데, java는 그게 안되는 것 같다.

그 외에 다른 방식으로 변환해 주는 것은 되었다. 안되는 이유를 찾아보았으나 적당한 글을 찾지 못했다.


에러를 뱉어야지 왜 빌드가 안되는거니. 덕분에 미루던 jdk, 안드로이드 스튜디오 업데이트도 해보고 다른 컴퓨터에서도 돌려보고 시간 엄청 날렸다.


0. 딴소리



제 주력 언어는 C++ 입니다. 졸업작품을 만드느라 급하게 안드로이드 프로그래밍을 하고 있습니다. JAVA를 하다가 생소한 것들만 골라서 포스팅 할 예정입니다. 


그리고 오늘의 생소한 것은 중첩 클래스 입니다.


각막염에 걸렸습니다. 앞이 잘 안보여요. 초점이 잘 안잡히니 작업하기가 시원치않네요.




0. 개요


오늘 다룰 내용은 중첩 클래스입니다.


하나의 자바 소스파일에는 여러 개의 클래스를 작성할 수 있지만, 하나의 클래스 파일(.class)에는 반드시 하나의 컴파일된 자바 클래스만이 포함되어야 합니다.


만약 하나의 클래스 파일에 여러개의 클래스를 정의한 경우 컴파일러가 별도의 파일을 생성합니다. 


다음과 같이 생성되는 것을 확인할 수 있습니다.




총 4개의 클래스 파일이 생성되게 됩니다.


1. ClassA.class

2. ClassB.class

3. ClassC.class

4. ClassC$ClassD.class


이때 ClassD는 ClassC 내에 작성된 내부 클래스입니다.


하나의 자바 소스 파일에 작성된 클래스 중 오직 한 클래스만 public으로 선언할 수 있습니다. public으로 선언한 클래스의 이름은 소스파일의 이름과 동일하게 작성해야 합니다.





1. 중첩 클래스 란?


클래스 내부에 선언된 클래스입니다. 


중첩 클래스를 사용함으로써 얻을 수 있는 장점들 입니다.


① 한 곳에서만 사용되는 클래스를 그룹화 한다.


     클래스가 다른 클래스를 사용할 때(= 기능하나를 구현하면서 필요한 클래스들) 유용하다면, 클래스에 그 클래스를 포함시켜 함께 유지하는 것이 논리적입니다.

또한, 패키지가 간결해 질 수 있습니다.


② 내부 클래스에서 외부 클래스에 쉽게 접근할 수 있다.


    내부 클래스에서 외부 클래스에 쉽게 접근할 수 있습니다. 단, 외부클래스에서 내부 클래스를 접근 할 때에는 직접 객체를 만들어 접근해야 합니다.


③ 읽기 쉽고 유지 보수가 쉬운 코드를 작성할 수 있다.


    최상위 클래스와 하위 클래스는 사용되는 위치에 가깝게 배치됩니다.




중첩 클래스는 두가지로 나뉩니다.


중첩된 클래스 (클래스 내부의 클래스) 는 정적인지, 비 정적인지에 따라 다른 멤버가 엑세스할 수 있는 지가 정해집니다.


1. 정적 클래스 (static class)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ClassA {
    int a;
    
    ClassA(){}
    
    public static void main(String[] args){
    }
 
    static private class InnerClass{
        InnerClass(){a = 4;}    //오류 발생
    }
}
cs




2. 비 정적 클래스 (inner class)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ClassA {
    int a;
    
    ClassA(){}
    
    public static void main(String[] args){
    }
 
    private class InnerClass{
        InnerClass(){a = 4;}
    }
}
cs





2. 정적 중첩 클래스


객체 클래스 또는 객체 클래스에 정의돈 메소드를 직접 참조할 수 없으며, 객체 참조를 통해서만 사용할 수 있습니다.


정적 중첩 클래스는 다른 최상위 클래스와 마찬가지로 외부 클래스 (및 다른 클래스)의 인스턴스 멤버와 상호 작용합니다. 실제로, 정적 중첩 클래스는 행동 상으로는 패키징 편의를 위해 다른 최상위 클래스에 중첩 된 최상위 클래스입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package example;
 
public class ClassA {
    
    ClassA(){}
    
    public static void main(String[] args){
    }
 
    static class InnerClass{
    }
}
 
class ClassC{
    ClassC(){}
    
    void run(){
        
        ClassA.InnerClass inner = new ClassA.InnerClass();
    }
}
 
cs








3. 비 정적 클래스(내부 클래스/Inner class)



비 정적 클래스는 두가지 종류가 있습니다.


1. 익명 클래스


  이름이 없다는 것을 제외하고는 로컬 클래스와 같습니다. 한번만 사용해야 하는 경우에 사용하세요.


2. 로컬 클래스


   메서드 내부에 정의된 클래스입니다.



1. 익명 클래스


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
public class ClassA {
    
    interface HelloWorld{
        public void say();
    }
    
    ClassA(){}
    
    public static void main(String[] args){
        HelloWorld hello = new HelloWorld(){
            public void say(){
                System.out.println("hi");
            }
        };    
        
        hello.say();
    }
}
 
cs




2. 로컬 클래스


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ClassA {
    
    ClassA(){}
    
    public void fun(){
        class LocalClass{
 
        }
    }
 
    public static void main(String[] args){
 
    }
}
cs



지역 클래스는 modifier가 default이거나 final 또는 abstract로만 선언될 수 있습니다.

지역클래스를 포함하는 메소드 안에서만 객체를 생성할 수 있고, 메서드의 실행이 끝나면 해당 지역 클래스가 메모리에서 사라지게 됩니다.






4. 정리



내부 클래스의 종류


내부클래스 

선언위치 

비고 

멤버 내부 클래스

클래스 안에 선언(필드와 동일한 위치) 

사용 빈도 높음 

로컬 내부 클래스 

메서드 안에 선언 (메서드 내에 위치)

사용 빈도 낮음 

정적 내부 클래스 

클래스 안에 선언(필드와 동일한 위치) 

사용 빈도 낮음 

익명 클래스 

클래스 또는 메서드 안에 둘 다 가능 

AWT, Swing 이벤트에 사용 빈도 높음 





+ Recent posts