Android 客户端:无法在未调用 Looper.prepare() 的线程内创建处理程序

Android client: Can't create handler inside thread that has not called Looper.prepare()

我有来自 python 服务器和 java 客户端的以下代码工作正常。但是,我想使用相同的概念从 android 的 ssl 客户端发送文本消息。以下是我为 Python 和 Java 编写的代码,运行良好。

Python 服务器代码:

import time
import glob
import os
import ssl, socket
from sh import ls


class serverText():

    host = ""
    def __init__(self, host, port):
        self.host = host
        self.port = port


    def wavFinder(self):
        try:
            newest = max(glob.iglob('*.[Ww][Aa][Vv]'), key=os.path.getctime)
            yield
        finally:
            print "no wav file here"


    def find_all(self, a_str, sub):
        start = 0
        while True:
            start = a_str.find(sub, start)
            if start == -1: return
            yield start
            start += len(sub)

    def get_IP_Edison(self,value=basestring):
        IP = os.popen(value).read()
        try :
            place = int(list(serverText.find_all(self, IP,":"))[1]+1)
        except:
            place = int(list(serverText.find_all(self, IP, ":"))[0] + 1)
        self.host = IP[place:-1]
        # return IP[tag1 + 1:tag2]

    def deal_with_client(self,connstream):
        timestr = time.strftime("%Y-%m-%d_%H-%M-%S")
        data = connstream.recv(1024)
        print data
        # null data means the client is finished with us
        while data:
            if not data:
                print 'no more data being sent'
                break
            data = connstream.recv(1024)
            print data
            # finished with client

    def start_Server(self):

        # calling the client context to loaded with
        context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)

        # CONFIGS--------
        # Key and cert created with OPENSSL
        key, cert = "/home/root/Coding/certificates/server/privKey.key", \
                    "/home/root/Coding/certificates/server/server.pem"

        # Load the certifications
        context.load_cert_chain(certfile=cert, keyfile=key)

        # calling the port and host / needs to be of the edison
        HOST = self.host
        PORT = self.port
        # create a normal socket
        bindsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # Bind the socket or create it
        bindsocket.bind((HOST, PORT))
        # make the socket listen on five connections
        bindsocket.listen(1)
        print 'Listening..on IP:' + str(HOST) + " and port:" + str(PORT)

        # accept the connection
        newsocket, fromaddr = bindsocket.accept()
        print 'accepted connection from' + str(fromaddr)
        # wrap it in socket but make sure keys match
        connstream = context.wrap_socket(newsocket, server_side=True,
                                         do_handshake_on_connect=True)
        try:
            # call the receive function to receive file (more details above )
            serverText.deal_with_client(self,connstream=connstream)
        finally:
            connstream.shutdown(socket.SHUT_RDWR)
            connstream.close()
            print 'socket was closed'


if __name__ == '__main__':
    startServer = serverText(host="",port=5000)
    value_school = '''ifconfig | grep "inet " | grep -v 127.0.0.1 | grep -v 192.* | awk '{print }' '''
    #value_home = '''ifconfig | grep "inet " | grep -v 127.* | awk '{print }' '''
    startServer.get_IP_Edison(value=value_school)
    print 'host is : '+ startServer.host
    print ls()
    startServer.wavFinder()
    startServer.start_Server()

这是我的 Java 代码:

import java.io.*;
import java.net.*;
import java.security.*;

import javax.net.ssl.SSLSocketFactory;

import com.sun.net.ssl.SSLContext;
import com.sun.net.ssl.TrustManagerFactory;
import com.sun.net.ssl.TrustManager;

public class test {

    private static final String HOST = "192.168.0.103";

    private static final int PORT = 5000;
    final static String pathToStores = "/Users/admirmonteiro/Documents/Coding/Python/Thesis_Code/_Codes_/_Code_/Fall_15/fileTransmissionFiles/certs";
    final static String trustStoreFile = "cert.jks" ; // filename


    public static void main(String[] args) throws Exception {

        String currentDirectory;
        currentDirectory = System.getProperty("user.dir");
        System.out.println("Current working directory : "+currentDirectory);

        String trustFileName = pathToStores + "/" + trustStoreFile;

        char[] passphrase = "admir2006".toCharArray();
        KeyStore keystore = KeyStore.getInstance("JKS");
        keystore.load(new FileInputStream(trustFileName), passphrase);

        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(keystore);

        SSLContext context = SSLContext.getInstance("TLS");
        TrustManager[] trustManagers = tmf.getTrustManagers();

        context.init(null, trustManagers, null);

        SSLSocketFactory sf = context.getSocketFactory();

        Socket s = sf.createSocket(HOST, PORT);

        OutputStream out = s.getOutputStream();
        out.write("\n New Thing sent .\n\n".getBytes());


        out.close();
        s.close();
    }
}

我更新了以下 android 代码,但仍然有错误:

    Button sendButton;
    EditText textSend;
    private String ip_address = "192.168.10.103";
    private int port = 5000;


    private SSLSocket socket = null;
    private BufferedWriter out = null;
    private BufferedReader in = null;
    private final String TAG = "TAG";
    private char keystorepass[] = "......".toCharArray();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sendButton = (Button) findViewById(R.id.send);
        textSend = (EditText) findViewById(R.id.textsend);

        sendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String send = textSend.getText().toString();
                if(send.isEmpty()){
                    AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(MainActivity.this);
                    dialogBuilder.setMessage("Enter Text!");
                    dialogBuilder.setTitle("No TEXT");
                    dialogBuilder.setPositiveButton("OK...", null);
                    dialogBuilder.show();
                }else{
                    try {
                        KeyStore ks = KeyStore.getInstance("BKS");
                        InputStream keyin = getApplicationContext().getResources().openRawResource(R.raw.androidnewkey);
                        ks.load(keyin, keystorepass);
                        Log.i(TAG,"2");
                        SSLSocketFactory socketFactory = new SSLSocketFactory(ks);
                        socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                        socket = (SSLSocket)
                                socketFactory.createSocket(new Socket(ip_address,port), ip_address, port, false);
                        socket.startHandshake();
                        out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                        chat(send);

                    }catch (KeyStoreException e){
                        Log.i(TAG,"KeyStor");
                    }catch (IOException r ){
                        Log.i(TAG,"IO");
                    }catch(NoSuchAlgorithmException r ){
                        Log.i(TAG,"No all");
                    }catch (CertificateException u){
                        Log.i(TAG,"CertEx");
                    }catch(KeyManagementException r){
                        Log.i(TAG,"eyEx");
                    }catch(UnrecoverableKeyException e){
                        Log.i(TAG,"UnrectEx");
                    }
                }
            }
        });
    }
    public void chat(String temp){
        String message = temp;
        String line = "";
        // send id of the device to match with the image
        try {
            out.write(message+"\n");
            out.flush();
        } catch (IOException e2) {
            Log.i(TAG,"Read failed");
            System.exit(1);
        }
        // receive a ready command from the server
//        try {
//            line = in.readLine();
//            mResponse.setText("SERVER SAID: "+line);
//            //Log.i(TAG,line);
//        } catch (IOException e1) {
//            Log.i(TAG,"Read failed");
//            System.exit(1);
//        }
    }

当我键入要发送的消息时,输出如下(生成套接字时出现问题:为什么?):

Process: com.example.admirmonteiro.client, PID: 13539
android.os.NetworkOnMainThreadException                                                                                                                          
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1273)
at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:110)
at libcore.io.IoBridge.connectErrno(IoBridge.java:137)
at libcore.io.IoBridge.connect(IoBridge.java:122)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:183)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:163)
at java.net.Socket.startupSocket(Socket.java:592)
at java.net.Socket.tryAllAddresses(Socket.java:128)
at java.net.Socket.<init>(Socket.java:178)
at java.net.Socket.<init>(Socket.java:150)
at com.example.admirmonteiro.client.MainActivity.onClick(MainActivity.java:70)
at android.view.View.performClick(View.java:5204)
at android.view.View$PerformClick.run(View.java:21153)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

您不能从 BG 线程祝酒,除非该线程已调用 Looper.prepare()AsyncTask 的想法是您在 doInBackground() 中执行长 运行 操作,然后在 onPostExecute() 中更新您的 UI。将您的 Toast.makeText() 移至 onPostExecute()

如果需要调试 onPostExecute(),请使用 Log 而不是 Toast