Roosh Kim
Roosh Kim

Reputation: 11

How to send message from node.js server to Android app?

Im trying to make a simple application. That is When I write a word at edittext in android app such as "Hi", Then android app send message "Hi" to node.js server and node.js server send message "Hi has sent successflly" to android app. This is just a example, actually my object is android send a data(message) to server, and receive another data(message) from server.

The problem is this. When I write a word at android app and press button, the message transmitted successfully(I can confirm by console at node.js). But I cant send message to android from node.js .. When I press send button, My android app shut down..

What android says is "java.lang.NullPointerException: Attempt to invoke virtual method 'void android.app.Activity.runOnUiThread(java.lang.Runnable)' on a null object reference" ..

Yesterday, this error didn't happened and another error occured. "cannot cast string to JSONObject."

I will show you my code.

Server Side(Node.js)

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var port = 12000;

app.get('/', function(req, res) {
    res.sendFile('index.html');
})

io.on('connection', function(socket) {
    console.log('Android device has been connected');
    socket.on('message', function(data) {
        console.log('message from Android : ' + data);

        Object.keys(io.sockets.sockets);
        Object.keys(io.sockets.sockets).forEach(function (id) {
            console.log("ID : ", id );
            io.to(id).emit('message', data);
            console.log(data + ' has sent successfully');
        })

        /*if (data != null) {
            io.emit('message', {message : data + ' has received successfully'});
        }*/
    })

    socket.on('disconnect', function() {
        console.log('Android device has been disconnected');
    })
})

http.listen(port, function() {
    console.log('Server Start at port number ' + port);
})

Client Side (Android)

private Emitter.Listener handleIncomingMessages = new Emitter.Listener(){
        @Override
        public void call(final Object... args){
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    JSONObject data = (JSONObject) args[0];
                    String message;
                    try {
                        message = data.getString("text").toString();
                        Log.i("result", message);
                        addMessage(message);

                    } catch (JSONException e) {
                        Log.e("result", "Error : JSONException");
                        return;
                    } catch (ClassCastException e) {
                        Log.e("result", "Error : ClassCastException");
                        e.printStackTrace();
                        return;
                    }
                }
            });
        }
    };

private void sendMessage(){
    String message = mInputMessageView.getText().toString().trim();
    mInputMessageView.setText("");
    addMessage(message);
    JSONObject sendText = new JSONObject();
    try{
        sendText.put("text", message);
        socket.emit("message", message);
    }catch(JSONException e){

    }
}

private void addMessage(String message) {

    mMessages.add(new Message.Builder(Message.TYPE_MESSAGE)
            .message(message).build());
    // mAdapter = new MessageAdapter(mMessages);
    mAdapter = new MessageAdapter( mMessages);
    mAdapter.notifyItemInserted(0);
    scrollToBottom();
}

private void scrollToBottom() {
    mMessagesView.scrollToPosition(mAdapter.getItemCount() - 1);
}

I already searched similar problems that other people asked, but It didn't give me solution. Please help me. Thank you for reading long question.

p.s Because Im not English speaker, Im not good at English .. There will be many problems at grammar and writing skills. Thanks for understanding...

Upvotes: 1

Views: 2342

Answers (1)

TheKarlo95
TheKarlo95

Reputation: 1153

Reason this happens is because method getActivity() returns null. This might happen if you run this on a fragment after it is detached from an activity or activity is no longer visible. I would do a normal null check before like:

Activity activity = getActivity();
if(activity != null) {
    activity.runOnUiThread(new Runnable() {...}
}

I'm not familiar with socket.emit() method but it might throw network exception since it's running on UI thread and you are not allowed to do that. I recommend using RxJava/RxAndroid if you want to do this on another thread.

If you want to do network operation just use it like this:

Observable
    .fromRunnable(new Runnable {
       void run() {
          // here do your work
       }
     })
    .subscribeOn(Schedulers.newThread())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Subscriber<Void>() {
        @Override
        public void onCompleted() {
            // not really needed here
        }

        @Override
        public void onError(Throwable e) {
            // handle errors on UI thread
        }

        @Override
        public void onNext(Void void) {
           // do something on UI thread after run is done
        }
    });

Basically what it does it calls method call from Callable you just made on separate thread and when it's over it invokes onNext method if no exception was thrown or onError method if exception was thrown from Subscriber class.

Note that Response class isn't part of the RxJava/RxAndroid API and you can make it if you want. You can make it a simple POJO class or anything else you need it to be. If you don't need to have response you can use Runnable instead of Callable and it will work just fine.

In order for this to work you need to add this dependencies to your modules Gradle file:

dependencies {
    compile 'io.reactivex:rxandroid:1.2.1'
    compile 'io.reactivex:rxjava:1.1.6'
}

Upvotes: 1

Related Questions