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
。
我有来自 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
。