Android:适用于5.1,但不适用于7.0

时间:2017-04-30 04:14:41

标签: android server messaging

我目前正在尝试编写基于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");}
}

2 个答案:

答案 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卡上的文件中获取所需信息。