MultiClients with Multithreading on AndroidStudio

I am working on a project which has three WiFi modules “ESP8266-01” (they represent three servers) and I want to read from all of them at same time.
And i want to achieve that by running three clients each on on a separate Thread .
I created a special class for this purpose (called IMU1) and I run it on PC and it works fine but when I try to move this program to android it gives me this error when i press the button :

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: client.app.recrive, PID: 4416
    java.lang.IllegalStateException: Could not execute method for android:onClick
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:414)
        at android.view.View.performClick(View.java:4438)
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119)
        at android.view.View$PerformClick.run(View.java:18422)
        at android.os.Handler.handleCallback(Handler.java:733)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5017)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
        at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:409)
        at android.view.View.performClick(View.java:4438) 
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119) 
        at android.view.View$PerformClick.run(View.java:18422) 
        at android.os.Handler.handleCallback(Handler.java:733) 
        at android.os.Handler.dispatchMessage(Handler.java:95) 
        at android.os.Looper.loop(Looper.java:136) 
        at android.app.ActivityThread.main(ActivityThread.java:5017) 
        at java.lang.reflect.Method.invokeNative(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:515) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
        at dalvik.system.NativeStart.main(Native Method) 
     Caused by: android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1145)
        at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:163)
        at libcore.io.IoBridge.recvfrom(IoBridge.java:506)
        at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
        at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:46)
        at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:240)
        at java.io.InputStreamReader.read(InputStreamReader.java:233)
        at java.io.BufferedReader.fillBuf(BufferedReader.java:145)
        at java.io.BufferedReader.readLine(BufferedReader.java:397)
        at client.app.recrive.IMU1.read(IMU1.java:45)
        at client.app.recrive.MainActivity.receiveData(MainActivity.java:27)
        at java.lang.reflect.Method.invokeNative(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:515) 
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:409) 
        at android.view.View.performClick(View.java:4438) 
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119) 
        at android.view.View$PerformClick.run(View.java:18422) 
        at android.os.Handler.handleCallback(Handler.java:733) 
        at android.os.Handler.dispatchMessage(Handler.java:95) 
        at android.os.Looper.loop(Looper.java:136) 
        at android.app.ActivityThread.main(ActivityThread.java:5017) 
        at java.lang.reflect.Method.invokeNative(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:515) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
        at dalvik.system.NativeStart.main(Native Method)   

MainActivity:

package client.app.recrive;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.net.*;
import java.io.*;
import client.app.recrive.IMU1;

public class MainActivity extends AppCompatActivity {
    private Button btn;
    private TextView tv;
    private EditText txt;
    public void receiveData(View v) throws IOException , InterruptedException{

       IMU1 imu = new IMU1("192.168.1.7", 8080, 1);
        imu.start();
        //wait until the connection is complete
        Thread.sleep(100);
        this.tv.setText(imu.read());
        imu.join();
        Log.d("wifi","finished");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.btn = findViewById(R.id.button);
        this.txt = findViewById(R.id.text);
        this.tv = findViewById(R.id.textView);
        this.tv.setText("");
    }
}

IMU1 class:

package client.app.recrive;

import java.net.*;
import java.io.*;
import android.util.Log;

class IMU1 extends Thread {
    private String ip = "";
    private int port = 0;
    private int id = 0;
    private float q1 = 0;
    private float q2 = 0;
    private float q3 = 0;
    private float q4 = 0;
    private Socket socket;
    private BufferedReader reader;
    private InputStream input;
    private String text;
    
    public IMU1(String ip, int port, int id) {
        this.ip = ip;
        this.port = port;
        this.id = id;
    }
     

    public synchronized void initialize() {
        try {
            Socket s = new Socket(this.ip, this.port);
            this.socket = s;
            BufferedReader r = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
            this.reader = r;
            } catch (IOException e) { e.printStackTrace();}
        
    }
    
    public String read() throws IOException  {
        if ((this.reader.readLine()) == null) { ///////////////////////// The Error!
        return "Nothing!";
        } else {
        return this.reader.readLine().toString();
        }

    }

    
    public void terminate() throws IOException {
        this.socket.close();
        this.reader.close();
        //stop Thread
        
    }

    @Override
    public void run() {
        super.run();
        this.initialize();
    }

}

Layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/msg"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerHorizontal="false"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:background="@color/gray"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="200dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="30dp"
        android:ems="10"
        android:hint="Message"
        android:inputType="textPersonName"
        android:textColor="@color/purple_700" />

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center|center_horizontal"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="30dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="30dp"
        android:insetLeft="10dp"
        android:insetRight="10dp"
        android:onClick="receiveData"
        android:text="Recieve"
        app:backgroundTint="@color/purple_700" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="350dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="TextView" />

</LinearLayout>

Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="client.app.recrive">
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Client">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

One of the three servers that I am using to test the program:

package server;

import java.net.*;
import java.io.*;
import java.util.Date;

public class server2 {

    static Socket csk;
    static byte[] data = { 111 };
    public static void main(String[] args) {
        try {
            ServerSocket server = new ServerSocket(8080);
            System.out.println("Listening for connection on port 8080 ....");
            while (true) {
                try (Socket socket = server.accept()) {
                
                    System.out.println("accepted");
                    
                    String text = "Hello! from server2n";
                    while(true) {
                    socket.getOutputStream().write(text.getBytes("UTF-8"));
                    //Thread.sleep(100);
                    }
                }
            }

        } catch (Exception e2) {
            System.out.println("Error" + e2);
        }

    }

}

It indicates that the error is on the if ((this.reader.readLine()) == null) statement so I inverted the condition but it didn’t work.

Answer

Before you ask a question like this, plaese learn about Threading and Java Streams first, but here is the reworked code:

Here is the receiveData method (DON’T just add exceptions to onClick methods):

public void receiveData(View v) {
    IMU1 imu = new IMU1("192.168.1.7", 8080, 1) {
        @Override
        public void postRun(String text) {
            tv.setText(text);
            Log.d("wifi","finished");
        }
    };
    imu.start();
}

And here is the reworked IMU1 class (please learn how threads work):

public abstract class IMU1 extends Thread {
    private final String ip;
    private final int port;
    private final int id;

    private Socket socket;
    private BufferedReader reader;

    public IMU1(String ip, int port, int id) {
        this.ip = ip;
        this.port = port;
        this.id = id;
    }

    private void initialize() throws IOException {
        socket = new Socket(ip, port);
        reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    }

    private String read() throws IOException {
        String line = reader.readLine();
        return line != null ? line : "Nothing!";
    }

    private void terminate() throws IOException {
        socket.close();
        reader.close();
    }

    @Override
    public void run() {
        String readText;
        try {
            initialize();

            readText = read();
        } catch (Throwable tr) {
            tr.printStackTrace();

            readText = "An error occurred";
        } finally {
            try {
                terminate();
            } catch (Throwable ignored) {
            }
        }

        String text = readText;

        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                postRun(text);
            }
        });
    }

    public abstract void postRun(String text);
}

Leave a Reply

Your email address will not be published. Required fields are marked *