Это мой код. (фактически скопирован из открытого исходного кода)

package com.example.realtest;

import android.content.Context;
import android.os.Bundle;
import android.os.StrictMode;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class MainActivity extends AppCompatActivity {

    public TextView Toptext;
    public Button StartButton;
    public Button StopButton;
    public Button ConnButton;
    private Socket socket;
    public TextView temphum;
    // fixme: TAG
    String TAG = "socketTest";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        temphum = (TextView)findViewById(R.id.temphum);
        ConnButton = findViewById(R.id.button1);
        StartButton = findViewById(R.id.button2);
        StopButton = findViewById(R.id.button3);
        final EditText ipNumber = findViewById(R.id.ipText);

        Log.i(TAG, "Application createad");

        int SDK_INT = android.os.Build.VERSION.SDK_INT;
        if (SDK_INT > 8) {
            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);
        }


        ConnButton.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(getApplicationContext(), "Connect 시도", Toast.LENGTH_SHORT).show();
                String addr = ipNumber.getText().toString().trim();
                ConnectThread thread = new ConnectThread(addr);

                //키보드 자동 내리기
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(ipNumber.getWindowToken(), 0);

                thread.start();
            }
        });

        // fixme: 버튼 ClickListener
        StartButton.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View view) {
                StartThread sthread = new StartThread();
                StartButton.setEnabled(false);
                StopButton.setEnabled(true);

                sthread.start();

            }
        });
        StopButton.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View view) {
                StopThread spthread = new StopThread();
                StartButton.setEnabled(true);
                StopButton.setEnabled(false);
                spthread.start();
            }
        });

    }

   // fixme: Start 버튼 클릭 시 데이터 송/수신.
    class StartThread extends Thread{

        int bytes;

        public StartThread(){

        }

        public void run(){

            // 데이터 수신
            try {
                Log.d(TAG, "데이터 수신 준비");

                //TODO:수신 데이터(프로토콜) 처리

                while (true) {
                    byte[] buffer = new byte[64];
                    InputStream input = socket.getInputStream();
                    bytes = input.read(buffer);
                    String sensor = new String(buffer);
                    Log.d(TAG, "data = " + sensor);
                }
            }catch(IOException e){
                e.printStackTrace();
                Log.e(TAG,"수신 에러");
            }
        }
    }

    // fixme: Stop 버튼 클릭 시 데이터 송신.
    class StopThread extends Thread{


        public StopThread(){
        }

        public void run(){
            // 데이터 송신
            try {

                String OutData = "AT+STOP\n";
                byte[] data = OutData.getBytes();
                OutputStream output = socket.getOutputStream();
                output.write(data);
                Log.d(TAG, "AT+STOP\\n COMMAND 송신");

            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }
    // fixme: Socket Connect.
    class ConnectThread extends Thread {
        String hostname;

        public ConnectThread(String addr) {
            hostname = addr;
        }

        public void run() {
            try { //클라이언트 소켓 생성

                int port = 9999;
                socket = new Socket(hostname, port);
                Log.d(TAG, "Socket 생성, 연결.");

                Toptext = findViewById(R.id.text1);

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        InetAddress addr = socket.getInetAddress();
                        String tmp = addr.getHostAddress();
                        Toptext.setText(tmp + " 연결 완료");
                        Toast.makeText(getApplicationContext(), "Connected", Toast.LENGTH_LONG).show();

                        ConnButton.setEnabled(false);
                        StartButton.setEnabled(true);
                    }
                });




            } catch (UnknownHostException uhe) { // 소켓 생성 시 전달되는 호스트(www.unknown-host.com)의 IP를 식별할 수 없음.

                Log.e(TAG, " 생성 Error : 호스트의 IP 주소를 식별할 수 없음.(잘못된 주소 값 또는 호스트 이름 사용)");
                runOnUiThread(new Runnable() {
                    public void run() {
                        Toast.makeText(getApplicationContext(), "Error : 호스트의 IP 주소를 식별할 수 없음.(잘못된 주소 값 또는 호스트 이름 사용)", Toast.LENGTH_SHORT).show();
                        Toptext.setText("Error : 호스트의 IP 주소를 식별할 수 없음.(잘못된 주소 값 또는 호스트 이름 사용)");
                    }
                });

            } catch (IOException ioe) { // 소켓 생성 과정에서 I/O 에러 발생.

                Log.e(TAG, " 생성 Error : 네트워크 응답 없음");
                runOnUiThread(new Runnable() {
                    public void run() {
                        Toast.makeText(getApplicationContext(), "Error : 네트워크 응답 없음", Toast.LENGTH_SHORT).show();
                        Toptext.setText("네트워크 연결 오류");
                    }
                });


            } catch (SecurityException se) { // security manager에서 허용되지 않은 기능 수행.

                Log.e(TAG, " 생성 Error : 보안(Security) 위반에 대해 보안 관리자(Security Manager)에 의해 발생. (프록시(proxy) 접속 거부, 허용되지 않은 함수 호출)");
                runOnUiThread(new Runnable() {
                    public void run() {
                        Toast.makeText(getApplicationContext(), "Error : 보안(Security) 위반에 대해 보안 관리자(Security Manager)에 의해 발생. (프록시(proxy) 접속 거부, 허용되지 않은 함수 호출)", Toast.LENGTH_SHORT).show();
                        Toptext.setText("Error : 보안(Security) 위반에 대해 보안 관리자(Security Manager)에 의해 발생. (프록시(proxy) 접속 거부, 허용되지 않은 함수 호출)");
                    }
                });


            } catch (IllegalArgumentException le) { // 소켓 생성 시 전달되는 포트 번호(65536)이 허용 범위(0~65535)를 벗어남.

                Log.e(TAG, " 생성 Error : 메서드에 잘못된 파라미터가 전달되는 경우 발생.(0~65535 범위 밖의 포트 번호 사용, null 프록시(proxy) 전달)");
                runOnUiThread(new Runnable() {
                    public void run() {
                        Toast.makeText(getApplicationContext(), " Error : 메서드에 잘못된 파라미터가 전달되는 경우 발생.(0~65535 범위 밖의 포트 번호 사용, null 프록시(proxy) 전달)", Toast.LENGTH_SHORT).show();
                        Toptext.setText("Error : 메서드에 잘못된 파라미터가 전달되는 경우 발생.(0~65535 범위 밖의 포트 번호 사용, null 프록시(proxy) 전달)");
                    }
                });

            }

        }
    }


    @Override
    protected void onStop() {  //앱 종료시
        super.onStop();
        try {
            socket.close(); //소켓을 닫는다.
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}

Этот код получает данные о температуре и влажности (например, «температура: 27 C, влажность 40%») от raspberrypi каждые 30 секунд.

Я хочу показать эти данные в текстовом представлении, поэтому я добавил текстовое представление (temphum) и использовал temphum.setText("data = " + sensor); для заполнения текстового представления данными датчика в этой части

                while (true) {
                    byte[] buffer = new byte[64];
                    InputStream input = socket.getInputStream();
                    bytes = input.read(buffer);
                    String sensor = new String(buffer);
                    Log.d(TAG, "data = " + sensor);
                    temphum.setText("data = " + sensor);
                }

Но когда я запускаю этот код, возникает ошибка.

Я думаю, что из-за того, что я использовал temphum.setText("data = " + sensor); в while(true), java вызывает недоумение.

Я думаю, мне следует рассмотреть оставшиеся данные датчика в текстовом представлении, потому что он получает новые данные каждые 30 секунд. (Удаление или обновление принимающей части или как-то еще ...)

На самом деле я новичок в программировании и не знаю, как заставить этот код работать хорошо.

Помоги мне, пожалуйста.

0
hakkyu 14 Окт 2021 в 23:29

2 ответа

Лучший ответ

Начнем с

if (SDK_INT > 8) {
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}

НИКОГДА НЕ ДЕЛАЙТЕ ЭТОГО. При этом разрешается любое поведение, которое на самом деле является незаконным и, вероятно, нарушит вашу программу. Без этих строк ваша программа сразу же вылетит из строя и сообщит вам, что вы сделали не так. Вы видите это с помощью этих строк.

Фактически, я бы пошел дальше - ни одному сайту или источнику, использующему этот код, нельзя доверять ни в чем. Используйте другое место, чтобы учиться. В лучшем случае они научат вас вредным привычкам.

Причина, по которой ваши данные не отображаются, заключается в том, что вы не можете изменять элементы пользовательского интерфейса ни в каком потоке, кроме основного потока. Не работает. Обычно вы получаете сбой, который сообщает вам об этом, но, отключив строгий режим, вы можете запустить его - на самом деле он просто не будет работать. Для этого отправьте сообщение обработчику в потоке пользовательского интерфейса и вызовите там setText. И удалите настройку строгого режима, чтобы в будущем ваша программа правильно предупреждала вас о подобных вещах.

0
Gabe Sechan 14 Окт 2021 в 20:50

Вы должны заметить, что изменение View (установленное значение или sth.) Находится в области:

runOnUiThread(new Runnable() {
                    public void run() {
                        //Toptext.setText("네트워크 연결 오류");
                        ....
                        temphum.setText("data = " + sensor);
                    }
                });

Вы можете следить и попробовать. Также, как сказал @Gabe Sechan, удалите этот код.

0
tancolo 15 Окт 2021 в 03:37