왜 소켙을 직접 구현하시는지 여쭤봐도 될까요? 대신할 수 있는 방법이 있다면 굳이 소켙을 직접 구현하지 않는 편이 골치가 많이 덜 아픕니다.
제가 테스트 해 본 결과로는 일단 AndroidManifest.xml에 다음 두가지 permission 을 선언하셔야 합니다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="....">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
.... >
...
</application>
</manifest>
소켙의 핸들링은 올리신 소스코드 처럼 백그라운드 쓰레드에서 하셔야 합니다.
그리고 애뮬레이터에서 테스트를 하신다면, 애뮬레이터는 실제 디바이스와 같은 방식으로 동작하도록 되어 있어서 loopback, 즉 localhost, 127.0.0.1 의 주소로는 외부와 연결을 할 수 없습니다. 즉, 앱을 작업하는 동일 컴퓨터에 서버소켙을 띄워놓고 얘뮬레이터에서 접속하려면 공용IP나 내 라우터에서 제공하는 근거리 네트워주소를 사용하셔야 합니다. 아니면 애뮬레이터 자체에 서버 소켙을 띄우셔야 겠죠.
그리고 올리신 코드처럼 MainActivity.socket과 같이 액티비티 안에 있는 멤버를 밖에서 직접 참조해서 사용하는 것 바람직한 방법이 아닙니다. 특히 static 은 상수가 아니라면 더더욱 그렇습니다. 모바일의 특성상 Configuration chnage와 process death라는 게 있습니다. Configuration changes는 디바이스회전, 폰트 변경, 다크모드 세팅, 키보드 설정, 언어 변경 등등 이 발생할 시 현재 실행 중인 액티비티를 종료하고 새로 생성을 해줍니다. 이 때 핸들링이 필요한 부분을 하지 않으면 화면에 변경되었던 정보가 사라지는 경우가 생깁니다.
Process death는 안드로이드가 앱이 백그라운드에 있을 때 상황에 따라 아무 신호없이 앱을 죽일 수 있습니다. 사용자가 task manager에서 앱을 시작하면, 안드로이드 시스템은 앱 전체를 복구해주는 것이 아니라 마지막에 화면에 있던 액티비티만 복구를 해줍니다. 이 경우 Bundle이란 걸 통해서 저장된 것이 아니면, static으로 선언된 글로별 변수까지도 값이 초기화 되게 됩니다.
안드로이드에서 MainActivity.socket과 같은 접근 방법은 좋지않은 접근방법으로 권장하지 않습니다. 필요하면 MainActivity의 멤버나 Connect의 멤버로 사용하시는 것이 낫습니다.
마지막으로, 제가 간단히 테스트해 본 클라이언트 소켙 샘플을 올립니다. 클라이언트 소켙을 안드로이드에서는 사용해 본적이 없어서 좀 급조가 되었습니다. 하지만 테스트 해보시는데 지장은 없을 겁니다.