0

I'm new on the site and I'm here to ask a question about Sockets and Thread. I have this code, and it gives me the error below:

    public class Conferma extends AppCompatActivity {

    private final String TAG = "Conferma";
    public Socket socket;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.conferma);

        final EditText etTavolo = (EditText) findViewById(R.id.etTavolo);
        final RadioButton rbSi = (RadioButton) findViewById(R.id.rbSi);
        RadioButton rbNo = (RadioButton) findViewById(R.id.rbNo);
        Button bInvia = (Button) findViewById(R.id.bInvia);

        Thread t = new Thread(new ClientThread());
        t.start();

        bInvia.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String ordine = getIntent().getExtras().getString("ordine");
                if(etTavolo.getText().toString().equals("")){
                    AlertDialog.Builder builder = new AlertDialog.Builder(Conferma.this);
                    builder.setMessage("Inserire il numero del tavolo!").setNegativeButton("Riprova!", null).create().show();
                }
                ordine = ordine + "Tavolo: " + etTavolo.getText().toString() + "/";
                if(rbSi.isChecked()) {
                    ordine = ordine + "Coperto: Sì/";
                }
                else{
                    ordine = ordine + "Coperto: No/";
                }
                Log.d(TAG, ordine);

                //invio informazione
                inviaStringa(view, ordine);
            }
        });
    }

    private void inviaStringa(View view, String ordine) {

        try{
            OutputStream s = socket.getOutputStream();
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(s);
            BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
            PrintWriter out = new PrintWriter(bufferedWriter, true);
            out.println(ordine);
        } catch (Exception e) {
            Log.e(TAG, "Errore: " + e);
        }
    }

    private class ClientThread implements Runnable {

        private static final int SERVER_PORT = 6000;
        private static final String SERVER_IP = "109.115.84.90";
        private static final String TAG = "ClientThread";

        @Override
        public void run() {
            try {
                InetAddress serverAddress = InetAddress.getByName(SERVER_IP);
                Log.d(TAG, "creato");
                socket = new Socket(serverAddress, SERVER_PORT);
            } catch (UnknownHostException e) {
                Log.e(TAG, "Errore: " + e);
            } catch (IOException e) {
                Log.e(TAG, "Errore: " + e);
            }
        }
    }
}

Error:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.OutputStream java.net.Socket.getOutputStream()' on a null object reference

Now, from the error i supposed that the problem is in the Socket, which means that is not initialized. But if i call the ClientThread method inside the creation of the simple Thread, why don't he get initialized? Thanks for the help, and sorry if I can't be more clear than this! :((

Denko Swagga
  • 13
  • 1
  • 7
  • Looks like the socket will created later than you called getOutputStream() – Jens Jun 12 '17 at 12:48
  • Socket is not instantiated, maybe you're misunderstanding the socket you create on the runnable class and the other? EDIT: Nevermind, i saw what you've done – Thecave3 Jun 12 '17 at 12:54
  • It doesn't give me the line, just that thing that i paste on the quote (the NullPointerException thing). Jens, I took this example from an android book, so I don't exclude the possibility that is wrong :/ How do you suggest to fix it? – Denko Swagga Jun 12 '17 at 12:54
  • instead of use threads, use [AsyncTask](https://developer.android.com/reference/android/os/AsyncTask.html) – Thecave3 Jun 12 '17 at 12:55
  • I took that option too, but they told me to use Thread and it's for an exam, so I prefer to solve the problem with Threads and Sockets :D Thanks for the suggestion! :3 – Denko Swagga Jun 12 '17 at 13:00
  • When you create the socket you invoke a constructor that *may* throw an exception. If it does throw an exception the `socket` variable will remain null. You catch and log the exception, but then continue the normal program flow, which eventually gets to the point where `socket` is dereferenced for an NPE. Look at your logcat output to see what the exception is. – President James K. Polk Jun 12 '17 at 13:09

1 Answers1

0

The best (and most correct) way to achieve this is use an AsyncTask (as I wrote in comments).

If you want to use that class, then there're many solutions, here I just suggest the one I think is cleaner, create in another file the class ClientThread and add the to that the method inviaStringa:

ClientThread:

private class ClientThread implements Runnable {    
   private static final int SERVER_PORT = 6000;
         private static final String SERVER_IP = "109.115.84.90";
            private static final String TAG = "ClientThread";
        private Socket socket;

    public ClientThread(){
                try {
                    InetAddress serverAddress = InetAddress.getByName(SERVER_IP);
                    Log.d(TAG, "creato");
                    socket = new Socket(serverAddress, SERVER_PORT);
                } catch (UnknownHostException e) {
                    Log.e(TAG, "Errore: " + e);
                } catch (IOException e) {
                    Log.e(TAG, "Errore: " + e);
                }
            }

    }

            @Override
            public void run() {
    }
            private void inviaStringa(View view, String ordine) {

            try{
                OutputStream s = socket.getOutputStream();
                OutputStreamWriter outputStreamWriter = new OutputStreamWriter(s);
                BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
                PrintWriter out = new PrintWriter(bufferedWriter, true);
                out.println(ordine);
            } catch (Exception e) {
                Log.e(TAG, "Errore: " + e);
            }
        }

        }

then inside Conferma you don't need more to declare the socket, but just do this

Thread t = new Thread(new ClientThread());
        t.start();

...//when you've to send the String

t.inviaStringa(view, ordine);
Thecave3
  • 762
  • 12
  • 27
  • It gives me an error when I try to call the inviaStringa method on the Thread, it says that I have to put it **final** , and even if I do that, it's unable to find the method on ClientThread class. – Denko Swagga Jun 12 '17 at 13:24
  • This is because you're using it inside the Listener, try to put final the Thread t. – Thecave3 Jun 12 '17 at 13:32
  • if i put the Thread t final, it gives me that the method **inviaStringa** cannot be resolved, even if I declare it inside the Listener or outside. I think is like this because the object is a Thread type, and the Thread class doesn't have a method call **inviaStringa** inside. – Denko Swagga Jun 12 '17 at 13:35
  • Ok, this is a problem caused by the fact that you're using an anonymous OnClickListener. If you declare your custom onClickListener it should work properly. Another approach, in this case, could be the use of a class method as a mask (in this case you must do some changes). This [question](https://stackoverflow.com/questions/10969803/variable-should-be-final-inside-listener) could explain better what's the problem now. – Thecave3 Jun 12 '17 at 13:41
  • I try to create my own Listener, but with that I lose the Extras from the previous activity (the String **ordine**). How can I don't lose that? – Denko Swagga Jun 12 '17 at 14:00
  • Pass it as a value in the constructor, – Thecave3 Jun 12 '17 at 14:04
  • I tried your solution, and now it crashes after pressing the button. It gives me the error on these 2 rows: socket = new Socket(serverAddress, SERVER_PORT); Thread t = new Thread(new ClientThread()); – Denko Swagga Jun 12 '17 at 14:20
  • Print the stack trace and also please don't copy and paste but think in what are you writing – Thecave3 Jun 12 '17 at 14:22
  • As I said at the beginning of this post this kind of things is no more used and that's exactly why you must not use this but AsyncTask. If you do not trust me, then please trust this [link](http://www.androiddesignpatterns.com/2012/06/app-force-close-honeycomb-ics.html) where it explains why. I can not help you further. – Thecave3 Jun 12 '17 at 15:59
  • Ok thank you for the help, I'll try to change the code and eventually open another topic for help! Thank you again! :) – Denko Swagga Jun 12 '17 at 16:08