1
\$\begingroup\$

I am a beginner in Android and this is my first big project in it. I am trying to communicate with an STM Discovery board using an ESP01 module.

Below is the client connection class

    package com.example.remote_dslr;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;

import android.app.Activity;
import android.util.Log;

public class TCPClient {
    private static String TAG = "TCPClient"; //For debugging, always a good idea to have defined
    boolean receiveThreadRunning = false;
    //just to track the time
    long startTime = 0L;
    private Socket connectionSocket = null;
    private InputStream inputStream = null;
    private OutputStream outputStream = null;
    private MessageReceivedListener messageReceivedListener = null;

    //Runnables for sending and receiving data
    private SendRunnable sendRunnable;
    private ReceiveRunnable receiveRunnable;
    //Threads to execute the Runnables above
    private Thread sendThread = null;
    private Thread receiveThread = null;

    private String severIp = "192.168.4.1";
    private int serverPort = 80;

    public TCPClient(String ip, int port) {
        severIp = ip;
        serverPort = port;
    }

    /**
     *  Create a new instance of TCPClient and attach listener
     * @param msgRecListner Instance of MessageReceivedListener
     */
    public TCPClient(MessageReceivedListener msgRecListner) {
        connectionSocket = null;
        inputStream = null;
        outputStream = null;
        messageReceivedListener = msgRecListner;
    }

    public String getIP(){
        return severIp;
    }

    public Integer getPort(){
        return serverPort;
    }
    /**
     * Returns true if TCPClient is connected, else false
     * @return Boolean
     */
    public boolean isConnected() {
        return connectionSocket != null && connectionSocket.isConnected() && !connectionSocket.isClosed();
    }

    /**
     * Open connection to server
     */
    public void Connect(String ip, int port) {
        severIp = ip;
        serverPort = port;
        Log.e(TAG, "Connect to " + severIp + ":" + serverPort);
        new Thread(new ConnectRunnable()).start();
    }

    /**
     * Close connection to server
     */
    public void Disconnect() {
        if (receiveThread != null)
            receiveThread.interrupt();

        if (sendThread != null)
            sendThread.interrupt();

        try {
            connectionSocket.close();
        } catch (IOException e) {
            Log.e(TAG,"Disconnect() Error" + e.getMessage());
        }
    }

    /**
     * Send data to server
     * @param data byte array to send
     */
    public void SendToESP(String data) {
        if (isConnected()) {
            sendRunnable.Send(data.getBytes());
        }
    }
    /**
     * Send data to server
     * @param data byte array to send
     */
    public void SendToESP(byte[] data) {
        if (isConnected()) {
            sendRunnable.Send(data);
        }
    }

    public class ReceiveRunnable implements Runnable {

        @Override
        public void run() {
            Log.e(TAG, "Receiving started");
            receiveThreadRunning = true;
            while (!Thread.currentThread().isInterrupted() && isConnected()) {
                receiveThreadRunning = true;
                try {
                    //Log.e(TAG, "Receiving try");
                    String message="";
                    BufferedReader bufferReader = new BufferedReader(new InputStreamReader(inputStream));
                    //stream is ready to be read
                    if(bufferReader.ready()) {
                        message = bufferReader.readLine();
                        Log.e(TAG, ">>>>" + message + "<<<<");
                        if (messageReceivedListener != null) {
                            if(message.equals("GVI!")) {
                                long confirmTime = System.currentTimeMillis() - startTime;
                                messageReceivedListener.OnConnectSuccess(confirmTime);
                            } else if(!message.equals("")) {
                                messageReceivedListener.OnMessageReceived(message);
                            }
                        }
                    }
                } catch (Exception e) {
                    Log.e("ReceiveRunnable--Err", e.getMessage());
                    if (messageReceivedListener !=null)
                        messageReceivedListener.OnReceivedError();
                    //Gets stuck in a loop if we don't call this on error?
                    Disconnect();
                }
                //don't eat all cpu, the RemoteController will send messages at min. interval of 40ms (25Hz)
                try {
                    Thread.sleep(40);
                }catch (final InterruptedException e){
                    e.printStackTrace();
                }
            }
            //what to do it this thread is done?
            Log.e(TAG, "Receiving stopped");
            receiveThreadRunning = false;
        }
    }

    public class SendRunnable implements Runnable {
        byte[] data;
        private boolean hasMessage = false;

        /**
         * Send data as bytes to the server
         * @param bytes
         */
        public void Send(byte[] bytes) {
            this.data = bytes;
            this.hasMessage = true;
        }

        @Override
        public void run() {
            Log.e(TAG, "Sending started");
            while (!Thread.currentThread().isInterrupted() && isConnected()) {
                if (this.hasMessage) {
                    //startTime = System.currentTimeMillis();
                    try {
                        //Send the data
                        outputStream.write(data, 0, data.length);
                        //Flush the stream to be sure all bytes has been written out
                        outputStream.flush();
                        if (messageReceivedListener != null)
                            messageReceivedListener.OnSendSuccess();
                        this.hasMessage = false;
                        this.data =  null;
                    } catch (IOException e) {
                        Log.e("ConnectRunnable---", e.getMessage());
                        if (messageReceivedListener !=null)
                            messageReceivedListener.OnSendError();
                    }
                }
            }
            Log.e(TAG, "Sending stopped");
        }
    }

    //this is the thread that creates the connection to ESP
    public class ConnectRunnable implements Runnable {

        public void run() {
            try {
                Log.e(TAG, "C: Connecting...");
                startTime = System.currentTimeMillis();
                //Create a new instance of Socket
                connectionSocket = new Socket();
                //Start connecting to the server with 5000ms timeout
                //This will block the thread until a connection is established
                connectionSocket.connect(new InetSocketAddress(InetAddress.getByName(severIp), serverPort), 5000);
                //create in and out streams
                inputStream = new BufferedInputStream(connectionSocket.getInputStream());
                outputStream = new BufferedOutputStream(connectionSocket.getOutputStream());
                //prepare the threads
                sendRunnable = new SendRunnable();
                sendThread = new Thread(sendRunnable);
                receiveThread = new Thread(new ReceiveRunnable());
                //start the threads
                receiveThread.start();
                sendThread.start();
                long connTime = System.currentTimeMillis() - startTime;
                Log.e(TAG, "Connected! Current duration: " + connTime + "ms");
                if (messageReceivedListener != null){
                    messageReceivedListener.OnConnect(connTime);
                }
            } catch (Exception e) {
                Log.e("ConnectRunnable---", e.getMessage());
                if (messageReceivedListener !=null)
                    messageReceivedListener.OnConnectionError();
            }
            Log.e(TAG, "Connection thread stopped");
        }
    }
}

The listener is below

    package com.example.remote_dslr;

/**
 * Interface to handle various events that might occur that needs to be passed in to the parent
 *
 */
public interface MessageReceivedListener {

    /**
    * Called when new message received
    * @param msg Command/message as String
    */
    public void OnMessageReceived(String msg);
    /**
     * Called when an error occur when receiving
     */
    public void OnReceivedError();
    /**
    * Called when we send with success
    */
    public void OnSendSuccess();
    /**
     * Called when an error occur when sending
     */
    public void OnSendError();
    /**
    * Called when socket has connected to the correct server
    */
    public void OnConnectSuccess(long time);
    /**
     * Called when socket has connected to a server
     */
    public void OnConnect(long time);
    /**
     * Called when an error occur at connection
     */
    public void OnConnectionError();
}

And the usage

    package com.example.remote_dslr;

import com.example.remote_dslr.MessageReceivedListener;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
    public int SER_PORT = 80;
    public String SER_IP = "192.168.4.1";
    public String cmdStr = "";

    SettingsCtrl mySettings;
    private DrawerLayout drawer;
    private Fragment fragment = null;
    private Class fragmentClass = null;
    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mySettings = new SettingsCtrl(getApplicationContext());
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();

        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);

        //ApplicationProvider appProvider = (ApplicationProvider) getApplicationContext();

        Fragment fragment = null;
        Class fragmentClass = null;
        fragmentClass = ConnectFragment.class;
        try {
            fragment = (Fragment) fragmentClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();
    }

    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            Intent intent = new Intent(MainActivity.this, SettingsActivity.class);
            startActivity(intent);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        switch (item.getItemId()) {
            case R.id.nav_manual:
                fragmentClass = ManualFragment.class;
                break;
            case R.id.nav_bulb:
                break;
            case R.id.nav_timelapse:
                break;
            case R.id.nav_triggered:
                break;
            case R.id.nav_darkroom:
                break;
            case R.id.nav_lightning:
                break;
            case R.id.nav_fastobjects:
                break;
            case R.id.nav_droplets:
                break;
        }
        try {
            fragment = (Fragment) fragmentClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

}

I am asking help here for correcting/improving the code.

Thank you for your support.

\$\endgroup\$
  • \$\begingroup\$ Your MainActivity seems completely separate from the other classes. Did you forget to add something? Also, it's fairly difficult to answer to a question that is just a big code paste and question "any improvements?" Try to concentrate on a particular aspect and remove all unrelated auxiliary code from your example. \$\endgroup\$ – TorbenPutkonen Feb 28 at 12:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.