?>

Hard Copy World

HCW

Q&A

Home > Forum >

Q&A

Mqtt 예제에 대한 질문입니다.

페이지 정보

작성자 create 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 작성일16-06-24 16:00 조회1,429회 댓글1건

본문

안녕하세요 

먼저 올려주신 MQTT 자료는 감사하게 잘 봤습니다.

올려주신 자료와 타 자료를 통해 

현재 로컬호스트에서 서로 다른 두 기기에서  토픽을 주고 받는데는 성공했는데,

카톡과 같이 어플이 꺼져있어도 mqtt를 수신할 수 있도록

백그라운드단 이나 서비스단에 돌리고 싶습니다.

밑에는 테스트중인 소스 입니다. 

도움을 주시면 감사하겠습니다.

 

package com.example.namgung_won.mqtttestapp;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import com.example.namgung_won.mqtttestapp.ActionListener.Action;
import com.example.namgung_won.mqtttestapp.Connection.ConnectionStatus;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;

import butterknife.Bind;
import butterknife.ButterKnife;


public class MainActivity extends AppCompatActivity {

//    private ClientConnections clientConnections = null;

    private String server;
    private String port;
    private String clientid;

    private String topic;
    private int qos;

    Connection connection;
    @Bind(R.id.test)
    Button test;
    @Bind(R.id.distest)
    Button distest;
    @Bind(R.id.subtest)
    Button subtest;
    @Bind(R.id.pubtest)
    Button pubtest;

    @Bind(R.id.edit_address)
    EditText edit_address;

    //send message
    @Bind(R.id.editText1)
    EditText editText1;

    @Bind(R.id.listView1)
    ListView chatlist;
    public static CustomAdapter customAdapter;



    Toast m_Toast;
    //서버 연결시 아이디
    @Bind(R.id.edit_id)
    EditText edit_id;

    //메시지 보낼때 토픽
    @Bind(R.id.et_publish)
    EditText et_publish;

    //메세지 받을떄 토픽
    @Bind(R.id.edit_topic)
    EditText edit_topic;

    //manage Connection
    private ChangeListener changeListener = new ChangeListener();


    /**
     * {@link Bundle} which holds data from activities launched from this activity
     **/
    private Bundle result = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ButterKnife.bind(this);

        test.setOnClickListener(testListener);
        distest.setOnClickListener(testListener);
        subtest.setOnClickListener(testListener);
        pubtest.setOnClickListener(testListener);
        customAdapter = new CustomAdapter();

        chatlist.setAdapter(customAdapter);

//        customAdapter.add("이건 뭐지",1);
//        customAdapter.add("쿨쿨",1);
//        customAdapter.add("쿨쿨쿨쿨",0);
//        customAdapter.add("재미있게",1);
//        customAdapter.add("놀자라구나힐힐 감사합니다. 동해물과 백두산이 마르고 닳도록 놀자 놀자 우리 놀자",1);
//        customAdapter.add("재미있게",1);
//        customAdapter.add("재미있게",0);
    }

    View.OnClickListener testListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            switch (v.getId()) {
                case R.id.test:
                    Connection();
                    break;
                case R.id.distest:
                    Disconnect();
                    break;
                case R.id.subtest:
                    subscribe();
                    break;
                case R.id.pubtest:

                    if (et_publish.length() == 0) {

                        if (m_Toast != null)
                            m_Toast.cancel();
                        m_Toast = Toast.makeText(getApplicationContext(), "보내는데 사용할 토픽을 입력해주세요.", Toast.LENGTH_SHORT);
                        m_Toast.show();
                    } else {
                        publish();
                    }
                    break;
            }


        }
    };

    public static void MessageReceive(String msg) {

        customAdapter.add(msg, 0);
        customAdapter.notifyDataSetChanged();
        Log.d("won", "msg=" + msg);
    }

//    private void createAndConnect()
//    {
//        Intent createConnection;
//
//        //start a new activity to gather information for a new connection
//        createConnection = new Intent();
//        createConnection.setClassName(
//                clientConnections.getApplicationContext(),
//                "org.eclipse.paho.android.service.sample.NewConnection");
//
//        clientConnections.startActivityForResult(createConnection,
//                ActivityConstants.connect);
//    }

    private void Connection() {

        Intent dataBundle = new Intent();

        String client_id = edit_id.getText().toString();
        if (client_id.equals("") || client_id == null || client_id.length() == 0) {
            if (m_Toast != null)
                m_Toast.cancel();
            m_Toast = Toast.makeText(getApplicationContext(), "클라이언트 아이디를 입력해주세요.", Toast.LENGTH_SHORT);
            m_Toast.show();
        } else {
            //connection setting
            String address = edit_address.getText().toString();
            if (address.length() < 5) {
                server = "169.254.42.33";

            } else {
                server = address;
            }
            port = "1883";
            clientid = client_id;

            //persiste server
            persistServerURI(server);

            //put data into a bundle to be passed back to ClientConnections
            dataBundle.putExtra(ActivityConstants.server, server);
            dataBundle.putExtra(ActivityConstants.port, port);
            dataBundle.putExtra(ActivityConstants.clientId, clientid);
            dataBundle.putExtra(ActivityConstants.action, ActivityConstants.connect);
            dataBundle.putExtra(ActivityConstants.cleanSession, false);//추후에 고민

            if (result == null) {
                // create a new bundle and put default advanced options into a bundle
                result = new Bundle();

                result.putString(ActivityConstants.message, ActivityConstants.empty);
                result.putString(ActivityConstants.topic, ActivityConstants.empty);
                result.putInt(ActivityConstants.qos, ActivityConstants.defaultQos);
                result.putBoolean(ActivityConstants.retained,
                        ActivityConstants.defaultRetained);

                result.putString(ActivityConstants.username,
                        ActivityConstants.empty);
                result.putString(ActivityConstants.password,
                        ActivityConstants.empty);

                result.putInt(ActivityConstants.timeout,
                        ActivityConstants.defaultTimeOut);
                result.putInt(ActivityConstants.keepalive,
                        ActivityConstants.defaultKeepAlive);
                result.putBoolean(ActivityConstants.ssl,
                        ActivityConstants.defaultSsl);
            }

            //add result bundle to the data being returned to ClientConnections
            dataBundle.putExtras(result);

            connectAction(dataBundle.getExtras());
//        setResult(RESULT_OK, dataBundle);

//        finish();
        }


    }

    private void reconnect() {

        Connections.getInstance(this).getConnection(connection.handle()).changeConnectionStatus(ConnectionStatus.CONNECTING);

        Connection c = Connections.getInstance(this).getConnection(connection.handle());
        try {
            c.getClient().connect(c.getConnectionOptions(), null, new ActionListener(this, Action.CONNECT, connection.handle(), null));
        } catch (MqttSecurityException e) {
            Log.e(this.getClass().getCanonicalName(), "Failed to reconnect the client with the handle " + connection.handle(), e);
            c.addAction("Client failed to connect");
        } catch (MqttException e) {
            Log.e(this.getClass().getCanonicalName(), "Failed to reconnect the client with the handle " + connection.handle(), e);
            c.addAction("Client failed to connect");
        }

    }

    /**
     * Add a server URI to the persisted file
     *
     * @param serverURI the uri to store
     */
    private void persistServerURI(String serverURI) {
        File fileDir = this.getFilesDir();
        File presited = new File(fileDir, "hosts.txt");
        BufferedWriter bfw = null;
        try {
            bfw = new BufferedWriter(new FileWriter(presited));
            bfw.write(serverURI);
            bfw.newLine();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (bfw != null) {
                    bfw.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    /**
     * Process data from the connect action
     *
     * @param data the {@link Bundle} returned by the {@link NewConnection} Acitivty
     */
    private void connectAction(Bundle data) {
        MqttConnectOptions conOpt = new MqttConnectOptions();
    /*
     * Mutal Auth connections could do something like this
     *
     *
     * SSLContext context = SSLContext.getDefault();
     * context.init({new CustomX509KeyManager()},null,null); //where CustomX509KeyManager proxies calls to keychain api
     * SSLSocketFactory factory = context.getSSLSocketFactory();
     *
     * MqttConnectOptions options = new MqttConnectOptions();
     * options.setSocketFactory(factory);
     *
     * client.connect(options);
     *
     */

        // The basic client information
        String server = (String) data.get(ActivityConstants.server);
        String clientId = (String) data.get(ActivityConstants.clientId);
        int port = Integer.parseInt((String) data.get(ActivityConstants.port));
        boolean cleanSession = (Boolean) data.get(ActivityConstants.cleanSession);

        boolean ssl = (Boolean) data.get(ActivityConstants.ssl);
        String ssl_key = (String) data.get(ActivityConstants.ssl_key);
        String uri = null;
        if (ssl) {
            Log.e("SSLConnection", "Doing an SSL Connect");
            uri = "ssl://";

        } else {
            uri = "tcp://";
        }

        uri = uri + server + ":" + port;

        MqttAndroidClient client;
        client = Connections.getInstance(this).createClient(this, uri, clientId);

        if (ssl) {
            try {
                if (ssl_key != null && !ssl_key.equalsIgnoreCase("")) {
                    FileInputStream key = new FileInputStream(ssl_key);
                    conOpt.setSocketFactory(client.getSSLSocketFactory(key,
                            "mqtttest"));
                }
            } catch (MqttSecurityException e) {
                Log.e(this.getClass().getCanonicalName(),
                        "MqttException Occured: ", e);
            } catch (FileNotFoundException e) {
                Log.e(this.getClass().getCanonicalName(),
                        "MqttException Occured: SSL Key file not found", e);
            }
        }

        // create a client handle
        String clientHandle = uri + clientId;

        // last will message
        String message = (String) data.get(ActivityConstants.message);
        String topic = (String) data.get(ActivityConstants.topic);
        Integer qos = (Integer) data.get(ActivityConstants.qos);
        Boolean retained = (Boolean) data.get(ActivityConstants.retained);

        // connection options

        String username = (String) data.get(ActivityConstants.username);

        String password = (String) data.get(ActivityConstants.password);

        int timeout = (Integer) data.get(ActivityConstants.timeout);
        int keepalive = (Integer) data.get(ActivityConstants.keepalive);

        connection = new Connection(clientHandle, clientId, server, port,
                this, client, ssl);
//        arrayAdapter.add(connection);

        connection.registerChangeListener(changeListener);
        // connect client

        String[] actionArgs = new String[1];
        actionArgs[0] = clientId;
        connection.changeConnectionStatus(ConnectionStatus.CONNECTING);

        conOpt.setCleanSession(cleanSession);
        conOpt.setConnectionTimeout(timeout);
        conOpt.setKeepAliveInterval(keepalive);
        if (!username.equals(ActivityConstants.empty)) {
            conOpt.setUserName(username);
        }
        if (!password.equals(ActivityConstants.empty)) {
            conOpt.setPassword(password.toCharArray());
        }

        final ActionListener callback = new ActionListener(this,
                ActionListener.Action.CONNECT, clientHandle, actionArgs);

        boolean doConnect = true;

        if ((!message.equals(ActivityConstants.empty))
                || (!topic.equals(ActivityConstants.empty))) {
            // need to make a message since last will is set
            try {
                conOpt.setWill(topic, message.getBytes(), qos.intValue(),
                        retained.booleanValue());
            } catch (Exception e) {
                Log.e(this.getClass().getCanonicalName(), "Exception Occured", e);
                doConnect = false;
                callback.onFailure(null, e);
            }
        }
        client.setCallback(new MqttCallbackHandler(this, clientHandle));


        //set traceCallback
        client.setTraceCallback(new MqttTraceCallback());

        connection.addConnectionOptions(conOpt);
        Connections.getInstance(this).addConnection(connection);
        if (doConnect) {
            try {
                client.connect(conOpt, null, callback);
            } catch (MqttException e) {
                Log.e(this.getClass().getCanonicalName(),
                        "MqttException Occured", e);
            }
        }

    }

    void Disconnect() {
        Connection c = Connections.getInstance(this).getConnection(connection.handle());

        //if the client is not connected, process the disconnect
        if (!c.isConnected()) {
            return;
        }

        try {
            c.getClient().disconnect(null, new ActionListener(this, Action.DISCONNECT, connection.handle(), null));
            c.changeConnectionStatus(ConnectionStatus.DISCONNECTING);
        } catch (MqttException e) {
            Log.e(this.getClass().getCanonicalName(), "Failed to disconnect the client with the handle " + connection.handle(), e);
            c.addAction("Client failed to disconnect");
        }
    }


    //subscribe
    private void subscribe() {

        String sub_topic = edit_topic.getText().toString();
        if (sub_topic.equals("") || sub_topic == null || sub_topic.length() == 0) {
            if (m_Toast != null)
                m_Toast.cancel();
            m_Toast = Toast.makeText(getApplicationContext(), "메시지를 받을 토픽을 적어주세요.", Toast.LENGTH_SHORT);
            m_Toast.show();
        } else {
            qos = 2;

            try {
                String[] topics = new String[1];
                topics[0] = sub_topic;
                Connections.getInstance(this).getConnection(connection.handle()).getClient()
                        .subscribe(sub_topic, qos, null, new ActionListener(this, Action.SUBSCRIBE, connection.handle(), topics));
            } catch (MqttSecurityException e) {
                Log.e(this.getClass().getCanonicalName(), "Failed to subscribe to" + sub_topic + " the client with the handle " + connection.handle(), e);
            } catch (MqttException e) {
                Log.e(this.getClass().getCanonicalName(), "Failed to subscribe to" + sub_topic + " the client with the handle " + connection.handle(), e);
            }
        }

    }

    private void publish() {


//            boolean retained = ((CheckBox) connectionDetails.findViewById(R.id.retained))
//                    .isChecked();

        String pub_topic = et_publish.getText().toString();
        boolean retained = false;
        String message = editText1.getText().toString();
        qos = 2;


        String[] args = new String[2];
        args[0] = message;
        args[1] = pub_topic + ";qos:" + qos + ";retained:" + retained;

        try {
            Connections.getInstance(this).getConnection(connection.handle()).getClient()
                    .publish(pub_topic, message.getBytes(), qos, retained, null, new ActionListener(this, Action.PUBLISH, connection.handle(), args));


            customAdapter.add(message, 1);
            customAdapter.notifyDataSetChanged();
        } catch (MqttSecurityException e) {
            Log.e(this.getClass().getCanonicalName(), "Failed to publish a messged from the client with the handle " + connection.handle(), e);
        } catch (MqttException e) {
            Log.e(this.getClass().getCanonicalName(), "Failed to publish a messged from the client with the handle " + connection.handle(), e);
        }

    }
    private class ChangeListener implements PropertyChangeListener {

        /**
         * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
         */
        @Override
        public void propertyChange(PropertyChangeEvent event) {

            if (!event.getPropertyName().equals(ActivityConstants.ConnectionStatusProperty)) {
                return;
            }
            runOnUiThread(new Runnable() {

                @Override
                public void run() {

                }

            });

        }

    }

}

 

댓글목록

최고관리자님의 댓글

최고관리자 쪽지보내기 메일보내기 홈페이지 자기소개 아이디로 검색 전체게시물 작성일

사실 이건 꽤 복잡한 문제입니다. 일단은 Activity-Service 구조로 앱이 동작하도록 이원화 해야합니다. 그리고 Activity가 시작할 때 Service 를 실행 또는 연결해서 상호 연동되도록 만들어줘야 합니다. 그리고 위 소스코드에서 MQTT 관련된 부분을 모두 Service로 옮겨서 처리하면 앱이 종료되어도 MQTT가 백그라운드 service에서 관리됩니다.
아래 예제는 BLE 통신을 백그라운드로 돌리는 예제코드입니다. 여기서 service 관련된 코드는 아래에 있으니 참고하세요.
https://github.com/godstale/Auto-Beacon/blob/master/src/com/wiredfactory/bluewave/service/BlueWaveService.java