我目前正在尝试编写基于GPS的聊天应用程序。应用程序工作得很好运行Android 5.1的模拟器,但我使用运行Android 7.0的模拟器时出错,我无法弄清楚原因。我得到的错误如下:
android.os.NetworkOnMainThreadException 在 android.os.StrictMode $ AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1303) 在 java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111) 在java.net.SocketOutputStream.write(SocketOutputStream.java:157) 在 java.io.ObjectOutputStream中的$ BlockDataOutputStream.drain(ObjectOutputStream.java:1946) 在 java.io.ObjectOutputStream中的$ BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1833) 在 java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1229) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346) 在 com.liftedstarfish.lifte.gpschat0_2.Client.sendMessage(Client.java:90) 在 com.liftedstarfish.lifte.gpschat0_2.ClientActivity $ 1.onClick(ClientActivity.java:87) 在android.view.View.performClick(View.java:5610) 在android.view.View $ PerformClick.run(View.java:22265) 在android.os.Handler.handleCallback(Handler.java:751) 在android.os.Handler.dispatchMessage(Handler.java:95) 在android.os.Looper.loop(Looper.java:154) 在android.app.ActivityThread.main(ActivityThread.java:6077) at java.lang.reflect.Method.invoke(Native Method) 在 com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:865) 在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
同样,只有在使用Android 7.0时才会出现错误。 5.1作品。下面显示了出现错误的类的代码。错误的位置周围有大箭头。
客户类:
public class Client implements Parcelable{
// for I/O
private ObjectInputStream serverInput; // to read from the socket
private ObjectOutputStream serverOutput; // to write on the socket
private Socket socket;
// if I use a GUI or not
private ConnectActivity connectActivity;
private ClientActivity clientActivity;
// the server, the port and the username
private String server, username;
private int port;
// for GPS location
private static Double coordinates[] = new Double[]{0.0, 0.0};
public Client(String server, int port, String username)
{
this(server, port, username, null, null);
}
public Client(String server, int port, String username, ClientActivity clientActivity)
{
this(server, port, username, clientActivity, null);
}
/*
* Constructor call when used from a GUI
* in console mode the ClienGUI parameter is null
*/
public Client(String server, int port, String username, ClientActivity clientActivity, ConnectActivity connectActivity) {
this.server = server;
this.port = port;
this.username = username;
// save if we are in GUI mode or not
this.connectActivity = connectActivity;
this.clientActivity = clientActivity;
}
public void setCoordinates(double X, double Y)
{
setCoordinates(new Double[]{X, Y});
}
public void setCoordinates(Double[] coordinates)
{
this.coordinates = coordinates;
this.sendMessage(new ChatMessage(ChatMessage.LOCATION_UPDATE, "", coordinates));
}
/*
* To start the dialog
*/
public void start() {new ConnectToServer().start();}
/*
* To send a message to the console or the GUI
*/
private void display(String message)
{
if(connectActivity == null) System.out.println(message); // println in console mode
else connectActivity.append(message); // append to the ClientGUI JTextArea (or whatever)
}
public void setClientActivity(ClientActivity clientActivity)
{
this.clientActivity = clientActivity;
}
/*
* To send a message to the server
*/
public void sendMessage(ChatMessage message)
{
try
{
>>>>>>>>>>>>serverOutput.writeObject(message);<<<<<<<<<<<<<<<<<<<<<<<<
}
catch(IOException e)
{
display("Exception writing to server: " + e);
}
}
/*
* When something goes wrong
* Close the Input/Output streams and disconnect not much to do in the catch clause
*/
public void disconnect()
{
try
{
if(serverInput != null) serverInput.close();
}
catch(Exception e) {} // not much else I can do
try
{
if(serverOutput != null) serverOutput.close();
}
catch(Exception e) {} // not much else I can do
try
{
if(socket != null) socket.close();
}
catch(Exception e) {} // not much else I can do
// inform the GUI
if(clientActivity != null)
clientActivity.connectionFailed();
}
public static void main(String[] args)
{
int portNumber = 1500;
String serverAddress = "localHost";
String userName = "Anonymous";
switch(args.length)
{
case 3:
serverAddress = args[2];
case 2:
try {portNumber = Integer.parseInt(args[1]);}
catch(Exception e)
{
System.out.println("Invalid port number.");
System.out.println("Usage is: > java Client [username] [portNumber] [serverAddress]");
return;
}
case 1:
userName = args[0];
case 0:
break;
default:
System.out.println("Usage is: > java Client [username] [portNumber] {serverAddress]");
return;
}
// create the Client object
Client client = new Client(serverAddress, portNumber, userName);
Scanner scan = new Scanner(System.in);
while(true)
{
System.out.print("> ");
String message = scan.nextLine();
if(message.equalsIgnoreCase("LOGOUT"))
{
client.sendMessage(new ChatMessage(ChatMessage.LOGOUT, "", coordinates));
break;
}
//else if(message.equalsIgnoreCase("WHOISIN"))
//{
// client.sendMessage(new ChatMessage(ChatMessage.WHOISIN, ""));
//}
else if(message.equalsIgnoreCase("LOCATION_UPDATE"))
{
client.sendMessage(new ChatMessage(ChatMessage.LOCATION_UPDATE, message, coordinates));
}
else
client.sendMessage(new ChatMessage(ChatMessage.MESSAGE, message, coordinates));
}
client.disconnect();
}
public void writeToParcel(Parcel dest, int flags)
{
dest.writeString(server);
dest.writeString(username);
dest.writeInt(port);
}
public int describeContents() {return 0;}
public static final Parcelable.Creator<Client> CREATOR
= new Parcelable.Creator<Client>()
{
public Client createFromParcel(Parcel in) {return new Client(in);}
public Client[] newArray(int size) {return new Client[size];}
};
private Client(Parcel in)
{
server = in.readString();
username = in.readString();
port = in.readInt();
new ConnectToServer().start();
}
class ConnectToServer extends Thread
{
public void run()
{
try {socket = new Socket(server, port);}
catch(Exception ec) {display("Error connecting to server:" + ec);}
try
{
serverInput = new ObjectInputStream(socket.getInputStream());
serverOutput = new ObjectOutputStream(socket.getOutputStream());
}
catch (IOException eIO) {display("Exception creating new Input/output Streams: " + eIO);}
// creates the Thread to listen from the server
new ListenToServer().start();
try {serverOutput.writeObject(username);}
catch (IOException eIO)
{
display("Exception logging in: " + eIO);
disconnect();
}
}
}
class ListenToServer extends Thread {
public void run()
{
Looper.prepare();
while(true)
{
try
{
final String message = (String) serverInput.readObject();
if(clientActivity == null)
{
System.out.println(message);
System.out.print("> ");
}
else
{
clientActivity.runOnUiThread(new Runnable()
{
@Override
public void run()
{
clientActivity.append(message);
}
});
}
}
catch(IOException e)
{
clientActivity.connectionFailed();
display("Server has closed the connection: " + e);
break;
}
catch(ClassNotFoundException e2){}
}
}
}
}
ClientActivity类:
public class ClientActivity extends AppCompatActivity {
// for I/O
private Client client;
//Display Objects
private TextView lblMessages;
private TextView lblLocation;
//Mathematical value of PI (3.14159...)
private static final double PI = Math.PI;
//Used for finding client location
private double LAT, LON;
//coordinates is used for storing the coordinates in miles
private Double coordinates[] = new Double[]{0.0, 0.0};
private LocationManager locationManager;
private BroadcastReceiver broadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
client = bundle.getParcelable("CLIENT");
}
client.setClientActivity(ClientActivity.this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
//Checks for user permissions
if(!runtimePermissions())
{
Intent intent = new Intent(getApplicationContext(), GPS_Service.class);
startService(intent);
}
//Obtains Updated location when it is requested.
final TextView lblLocation = (TextView) findViewById(R.id.text_view_location);
this.lblLocation = lblLocation;
lblLocation.setText("LOCATION: X: " + coordinates[0] + " Y: " + coordinates[1]);
final TextView lblMessages = (TextView) findViewById(R.id.text_view_messages);
this.lblMessages = lblMessages;
final EditText txtMessage = (EditText) findViewById(R.id.edit_text_message);
final Button btnSend = (Button) findViewById(R.id.button_send);
btnSend.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
String message = txtMessage.getText().toString();
txtMessage.setText("");
>>>>>>>>>>>>>>>>client.sendMessage(new ChatMessage(ChatMessage.MESSAGE, message, coordinates));<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}
});
final Button btnLogOut = (Button) findViewById(R.id.button_log_out);
btnLogOut.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
client.sendMessage(new ChatMessage(ChatMessage.LOGOUT, "", coordinates));
client.disconnect();
}
});
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
@Override
protected void onResume()
{
super.onResume();
if(broadcastReceiver == null)
{
broadcastReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
coordinates = (Double[]) intent.getExtras().get("coordinates");
lblLocation.setText("LOCATION: X: " + coordinates[0] + " Y: " + coordinates[1]);
}
};
}
registerReceiver(broadcastReceiver, new IntentFilter("LocationUpdate"));
}
@Override
protected void onDestroy()
{
super.onDestroy();
if(broadcastReceiver != null)
{
unregisterReceiver(broadcastReceiver);
}
}
private boolean runtimePermissions()
{
if(Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
requestPermissions(new String[]
{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
}, 100);
return true;
}
return false;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == 100 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED &&
grantResults[1] == PackageManager.PERMISSION_GRANTED)
{
Intent intent = new Intent(getApplicationContext(), GPS_Service.class);
startService(intent);
}
else
{
runtimePermissions();
}
}
public void connectionFailed()
{
Intent intent = new Intent(this, ConnectActivity.class);
startActivity(intent);
}
// public void display(String msg) {lblMessages.append("Error" + msg);}
//Adds a message to the message display section
public void append(String str) {lblMessages.append(str + "\n");}
}
答案 0 :(得分:0)
将执行的代码放入AsyncTask。
EX:
public class ChatService extends AsyncTask<Void,Void,String> {
Context c;
public ChatService (Context x){
c=x;
}
private static Client client;
public ChatService setClient(Client client)
{
this.client = client;
return this; //will do ;)
}
private static ChatMessage mChat;
public ChatService setChatMessage(ChatMessage mChat)
{
this.mChat = mChat;
return this; //already did, what do you want from me?!
}
@Override
protected String doInBackground(Void... params) {
String message = "";
client.sendMessage(mChat);
return message;
}
PackageInfo pi;
@Override
protected void onPostExecute(String s) {
//Add text to Views
}
}
并执行此代码:
//out in the middle of no where
//appears a random wild code
//we must protect this code
protected void wildCode()
{
ChatService cs = new ChatService(this)
.setClient(client)
.setChatMessage(new ChatMessage(ChatMessage.MESSAGE, message, coordinates));
cs.execute();
}
如果你想添加AsyncTask而不弄乱(class,lol),请使用:
AsyncTask<Void, Void,String> task = new AsyncTask<Void,Void,String>() {
private static Client client;
public void setClient(Client client)
{
this.client = client;
}
private static ChatMessage mChat;
public void setChatMessage(ChatMessage mChat)
{
this.mChat = mChat;
}
@Override
protected String doInBackground(Void... params) {
String message = "";
client.sendMessage(mChat);
return message;
}
PackageInfo pi;
@Override
protected void onPostExecute(String s) {
//Add text to Views
}
};
task.setClient(client);
task.setChatMessage(new ChatMessage(ChatMessage.MESSAGE, message, location));
task.execute();
答案 1 :(得分:0)
正如Exception所说,你正在尝试做一些网络和数据消费任务(从GPS获取数据)。默认情况下,android设计用于避免MainThread(用户界面运行的地方)的那种工作。
要解决此问题,您可以使用AsyncTask,处理程序,线程甚至服务来请求并从GPS,网络甚至SD卡上的文件中获取所需信息。