안드로이드 스튜디오 프래그먼트안에서 소켓통신 오류
조회수 2711회
안녕하세요 제가 맨처음에는 노트북을 통해서 파이썬 으로 서버를 만들고
안드로이드 스튜디오를 통해서는 클라이언트어플을 만들어서 서로 데이터를 주고 받게 만들었습니다.
https://m.blog.naver.com/cosmosjs/220834751822 이 블로그를 보면서 만들었습니다.
만들었더니 잘 되었습니다.
제가 뷰 페이저를 활용해서 한쪽에는 데이터 통신하는 곳 다른한쪽에는 또 다른 화면(해결 하고 웹뷰)을 구성하려고 합니다.
프래그먼트안에다가
이렇게 만들어서 Send message 에다가 "left" 라는 데이터를 적고 SEND 버튼을 누르면 파이썬 서버(노트북)로 제가 지정한 문자열이 호출되게 하려고 합니다. (프래그먼트 안에 만들지 않고 저 블로그 통해서 MainActivity 만 사용했을 때는 통신이 잘 되었습니다.)
이제 프래그먼트를 사용해서 해보려고 하는데 SEND버튼을 눌러서 데이터를 전송하면 서버로는 데이터가 전송이 되어서 동작을 하는데 어플이 죽습니다.(튕깁니다) 왜이러는지 모르겠어서 올립니다.
먼저 MainActivity.java 입니다
package com.example.pager1;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.app.ActionBar;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
ViewPager pager;
TextView recieveText;
Socket socket = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pager = findViewById(R.id.pager);
pager.setOffscreenPageLimit(2); //3개의 프래그먼트를 추가한다
//adapter라는것을 이용해서 거기다가 프래그먼트를 추가할 것임
MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager());
//프래그먼트3개 가지고 객체생성
Fragment1 fragment1 = new Fragment1(); //프래그먼트1 객체 생성
adapter.addItem(fragment1); //addItem 매소드를 이용해서 ArrayList<Fragment> 리스트에 프래그먼트1을 넣어줌
Fragment2 fragment2 = new Fragment2();
adapter.addItem(fragment2);
pager.setAdapter(adapter); //adapter 객체를 페이저 쪽에 등록을해야 뷰 페이저라는게 화면에 보임
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { // 버튼이 클릭 되었을 때 실행하는 매소드
pager.setCurrentItem(1); //페이저의 2번째 화면을 보여줌
}
});
}
class MyPagerAdapter extends FragmentStatePagerAdapter {
ArrayList<Fragment> items = new ArrayList<Fragment>();
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
public void addItem(Fragment item) {
items.add(item);
}
@NonNull
@Override
public Fragment getItem(int position) {
return items.get(position);
}
@Override
public int getCount() {
return items.size();
}
}
public static class MyClientTask extends AsyncTask<Void, Void, Void> { //MyClientTask 라는 class를 만들어줌
String dstAddress;
int dstPort;
String response = "";
String myMessage = "";
private ActionBar.Tab recieveText;
MyClientTask(String addr, int port, String message) { //생성자를 통해서 MyClientTask() 에 입력되는 ip주소, 포트, 메세지
dstAddress = addr;
dstPort = port;
myMessage = message;
}
@Override
protected Void doInBackground(Void... arg0) {
Socket socket = null;
myMessage = myMessage.toString();
try {
socket = new Socket(dstAddress, dstPort);
//송신
OutputStream out = socket.getOutputStream();
out.write(myMessage.getBytes());
//수신
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
byte[] buffer = new byte[1024];
int bytesRead;
InputStream inputStream = socket.getInputStream();
while ((bytesRead = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
response += byteArrayOutputStream.toString("UTF-8");
}
response = "서버의 응답 : " + response;
} catch (UnknownHostException e) {
e.printStackTrace();
response = "UnknownHostException : " + e.toString();
} catch (IOException e) {
e.printStackTrace();
response = "IOException : " + e.toString();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
@Override
protected void onPostExecute(Void result) {
recieveText.setText(response);
super.onPostExecute(result);
}
}
}
그리고 Fragment1.java 입니다.
package com.example.pager1;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.net.Socket;
public class Fragment1 extends Fragment {
private View view;
TextView recieveText;
EditText editTextAddress, editTextPort, messageText;
Button connectBtn, clearBtn;
Socket socket = null;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment1, container, false);
//앱 기본 스타일 설정
((MainActivity) getActivity()).getSupportActionBar().setElevation(0);
connectBtn = (Button) view.findViewById(R.id.buttonConnect);
clearBtn = (Button) view.findViewById(R.id.buttonClear);
editTextAddress = (EditText) view.findViewById(R.id.addressText);
editTextPort = (EditText) view.findViewById(R.id.portText);
recieveText = (TextView) view.findViewById(R.id.textViewReciev);
messageText = (EditText) view.findViewById(R.id.messageText);
//connect 버튼 클릭
connectBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
MainActivity.MyClientTask myClientTask = new MainActivity.MyClientTask(editTextAddress.getText().toString(),
Integer.parseInt(editTextPort.getText().toString()), messageText.getText().toString());
myClientTask.execute();
} catch (NumberFormatException e) {
} catch (Exception e) {
}
}
});
clearBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
recieveText.setText("");
messageText.setText("");
}
});
return view;
}
}
이제 실행을하고 "left"라는 데이터를 전송하면 전송은 되는데 어플이 죽어버립니다. 오류는
//05/15 14:56:20: Launching 'app' on Pixel 2 API 29.
$ adb shell am start -n "com.example.pager1/com.example.pager1.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 12175 on device 'Pixel_2_API_29 [emulator-5554]'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
W/RenderThread: type=1400 audit(0.0:50): avc: denied { write } for name="property_service" dev="tmpfs" ino=6878 scontext=u:r:untrusted_app:s0:c133,c256,c512,c768 tcontext=u:object_r:property_socket:s0 tclass=sock_file permissive=0 app=com.example.pager1
D/libEGL: Emulator has host GPU support, qemu.gles is set to 1.
W/libc: Unable to set property "qemu.gles" to "1": connection failed; errno=13 (Permission denied)
D/libEGL: loaded /vendor/lib64/egl/libEGL_emulation.so
loaded /vendor/lib64/egl/libGLESv1_CM_emulation.so
D/libEGL: loaded /vendor/lib64/egl/libGLESv2_emulation.so
W/.example.pager: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (greylist, reflection, allowed)
Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (greylist, reflection, allowed)
D/HostConnection: HostConnection::get() New Host Connection established 0x7e1d39fe3160, tid 12223
D/HostConnection: HostComposition ext ANDROID_EMU_CHECKSUM_HELPER_v1 ANDROID_EMU_native_sync_v2 ANDROID_EMU_native_sync_v3 ANDROID_EMU_native_sync_v4 ANDROID_EMU_dma_v1 ANDROID_EMU_direct_mem ANDROID_EMU_host_composition_v1 ANDROID_EMU_host_composition_v2 ANDROID_EMU_vulkan ANDROID_EMU_deferred_vulkan_commands ANDROID_EMU_vulkan_null_optional_strings ANDROID_EMU_vulkan_create_resources_with_requirements ANDROID_EMU_YUV_Cache ANDROID_EMU_async_unmap_buffer ANDROID_EMU_vulkan_ignored_handles ANDROID_EMU_vulkan_free_memory_sync GL_OES_EGL_image_external_essl3 GL_OES_vertex_array_object GL_KHR_texture_compression_astc_ldr ANDROID_EMU_gles_max_version_3_1
W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
D/EGL_emulation: eglCreateContext: 0x7e1d39fe3480: maj 3 min 1 rcv 4
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
E/eglCodecCommon: glUtilsParamSize: unknow param 0x000082da
glUtilsParamSize: unknow param 0x000082da
W/Gralloc3: mapper 3.x is not supported
D/HostConnection: createUnique: call
HostConnection::get() New Host Connection established 0x7e1d39fe3de0, tid 12223
D/HostConnection: HostComposition ext ANDROID_EMU_CHECKSUM_HELPER_v1 ANDROID_EMU_native_sync_v2 ANDROID_EMU_native_sync_v3 ANDROID_EMU_native_sync_v4 ANDROID_EMU_dma_v1 ANDROID_EMU_direct_mem ANDROID_EMU_host_composition_v1 ANDROID_EMU_host_composition_v2 ANDROID_EMU_vulkan ANDROID_EMU_deferred_vulkan_commands ANDROID_EMU_vulkan_null_optional_strings ANDROID_EMU_vulkan_create_resources_with_requirements ANDROID_EMU_YUV_Cache ANDROID_EMU_async_unmap_buffer ANDROID_EMU_vulkan_ignored_handles ANDROID_EMU_vulkan_free_memory_sync GL_OES_EGL_image_external_essl3 GL_OES_vertex_array_object GL_KHR_texture_compression_astc_ldr ANDROID_EMU_gles_max_version_3_1
D/eglCodecCommon: allocate: Ask for block of size 0x1000
D/eglCodecCommon: allocate: ioctl allocate returned offset 0x3ffff4000 size 0x2000
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
I/AssistStructure: Flattened final assist data: 2680 bytes, containing 2 windows, 16 views
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
D/EGL_emulation: eglMakeCurrent: 0x7e1d39fe3480: ver 3 1 (tinfo 0x7e1dcb7674e0)
E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
W/System.err: java.net.SocketException: socket failed: EPERM (Operation not permitted)
at java.net.Socket.createImpl(Socket.java:492)
at java.net.Socket.<init>(Socket.java:446)
W/System.err: at java.net.Socket.<init>(Socket.java:218)
at com.example.pager1.MainActivity$MyClientTask.doInBackground(MainActivity.java:107)
at com.example.pager1.MainActivity$MyClientTask.doInBackground(MainActivity.java:88)
at android.os.AsyncTask$3.call(AsyncTask.java:378)
W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:266)
W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
W/System.err: at java.lang.Thread.run(Thread.java:919)
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.pager1, PID: 12175
java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.ActionBar$Tab android.app.ActionBar$Tab.setText(java.lang.CharSequence)' on a null object reference
at com.example.pager1.MainActivity$MyClientTask.onPostExecute(MainActivity.java:145)
at com.example.pager1.MainActivity$MyClientTask.onPostExecute(MainActivity.java:88)
at android.os.AsyncTask.finish(AsyncTask.java:755)
at android.os.AsyncTask.access$900(AsyncTask.java:192)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:772)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
I/Process: Sending signal. PID: 12175 SIG: 9
를 입력하세요
//at com.example.pager1.MainActivity$MyClientTask.onPostExecute(MainActivity.java:145)
at com.example.pager1.MainActivity$MyClientTask.onPostExecute(MainActivity.java:88) 입력하세요
E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
W/System.err: java.net.SocketException: socket failed: EPERM (Operation not permitted)
at java.net.Socket.createImpl(Socket.java:492)
at java.net.Socket.<init>(Socket.java:446)
W/System.err: at java.net.Socket.<init>(Socket.java:218)
at com.example.pager1.MainActivity$MyClientTask.doInBackground(MainActivity.java:107)
at com.example.pager1.MainActivity$MyClientTask.doInBackground(MainActivity.java:88)
이렇게 뜹니다 문제가 뭔지 알 수 있을까요? 읽어주셔서 감사합니다(__)
-
(•́ ✖ •̀)
알 수 없는 사용자
3 답변
-
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.pager1, PID: 12175 java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.ActionBar$Tab android.app.ActionBar$Tab.setText(java.lang.CharSequence)' on a null object reference at com.example.pager1.MainActivity$MyClientTask.onPostExecute(MainActivity.java:145)
Logcat 출력에서 이 스택 추적을 잘 살펴보시면, setText 메서드가 MainActivity 내의 MyClientTask 안의 메서드 onPostExecute 내부에서 null object reference에 호출되었다고 나옵니다.
MyClientTask 내부의 recieveText 변수에 아무것도 할당되어있지 않기 때문에 이런 오류가 발생할 수 밖에 없습니다.
이를 해결하는 방법 중에 하나로, MyClientTask가 초기화될 때, findViewById() 메서드로 recieveText에 TextView를 연결할 수도 있습니다.
수정
MyClientTask 클래스가 static이므로 클래스 외부의 객체를 참조하는 것은 불가능합니다. MyClientTask를 정적 클래스로 선언하지 않으면 됩니다.
-
(•́ ✖ •̀)
알 수 없는 사용자
-
-
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.pager1, PID: 12175 java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.ActionBar$Tab android.app.ActionBar$Tab.setText(java.lang.CharSequence)' on a null object reference at com.example.pager1.MainActivity$MyClientTask.onPostExecute(MainActivity.java:145) at com.example.pager1.MainActivity$MyClientTask.onPostExecute(MainActivity.java:88) at android.os.AsyncTask.finish(AsyncTask.java:755) at android.os.AsyncTask.access$900(AsyncTask.java:192) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:772) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
서버에서 받은 응답을 출력하는 과정에서 에러가 발생합니다.
recieveText.setText(response);
정확하게는 이 부분입니다.
메인액티비티에서 recieveText라는 텍스트뷰를 참조 하시는 것을 빼먹으신 것 같습니다. 그리고 AsyncTask 안에 receiveText는 삭제하세요.
- 네 맞습니다.. 처음에 다 제대로 하고 보니까 receiveText 에서 빨간색이 떴습니다. 그래서 옆에 전구 모양을 통해서 1. private ActionBar.Tab receiveText; 를 추가했었고 또 안되니 메인 액티비티에서 2. TextView recieveText; 를 static TextView recieveText; 로 바꾸었었고, 마지막으로 또 안되니 3. MyClientTask 를 non static으로 바꾸니 Fragment1.java에서 오류가 생겼습니다.. 안드로이드 스튜디오를 잘 모르는 상태에서 하니까 많이 힘드네요.. 텍스트뷰를 참조하라는게 어떤 말인지를 모르겠습니다. ㅜㅜ 죄송합니다 알 수 없는 사용자 2020.5.15 15:52
- pager = findViewById(R.id.pager); 여기 이 코드처럼 textview를 엑티비티에 참조하라는 얘기입니다. 주동혁 2020.5.15 15:54
- receiveText = findViewById(R.id.textViewReciev); 이렇게 하라는 말씀이신가요? 바로 밑에 이렇게 추가를 해도 아무런 변동이 없습니다. Fragment1.java에 receiveText = (TextView) view.findViewById(R.id.textViewReciev); 이렇게 있는데 이거랑은 무관한건가요? 오류를 보면 error: non-static variable receiveText cannot be referenced from a static context receiveText.setText(response); 이렇게 생깁니다. 알 수 없는 사용자 2020.5.15 15:59
- 메인액티비티와 프래그먼트의 레이아웃이 어떻게 구성되어 있는지 모르기에 그 이상 자세하게 얘기드리기 어렵습니다. 주동혁 2020.5.15 16:06
-
생성자를 통해 결과를 출력할 view 의 변수를 넣어주시기 바랍니다.
public static class MyClientTask extends AsyncTask<Void, Void, Void> { //MyClientTask 라는 class를 만들어줌 String dstAddress; int dstPort; String response = ""; String myMessage = ""; private TextView recieveText; MyClientTask(String addr, int port, String message, TextView recieveText) { //생성자를 통해서 MyClientTask() 에 입력되는 ip주소, 포트, 메세지 dstAddress = addr; dstPort = port; myMessage = message; this.recieveText = recieveText; } @Override protected Void doInBackground(Void... arg0) { ... return null; } @Override protected void onPostExecute(Void result) { recieveText.setText(response); super.onPostExecute(result); } }
이렇게 호출하시면 됩니다.
new MainActivity.MyClientTask(editTextAddress.getText().toString(), Integer.parseInt(editTextPort.getText().toString()), messageText.getText().toString(), recieveText).execute();
좀더 안전하게 하는 방법은 TextView receiveText 를 WeakReference 로 선언해주세요
// 선언 //private TextView receiveText; private WeakReference<TextView> receiveTextReference; // 생성자 //this.recieveText = recieveText; receiveTextReference = new WeakReference<TextView>(recieveText); // 온 포스트 //recieveText.setText(response); TextView receiveText = receiveTextReference.get(); if (receiveText != null) { recieveText.setText(response); }
댓글 입력