안드로이드 node js 통신 - andeuloideu node js tongsin

package org.androidtown.socketio;

import android.os.Bundle;

import android.support.v7.app.AppCompatActivity;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

import android.widget.Toast;

import org.json.JSONObject;

import java.net.URL;

import io.socket.client.IO;

import io.socket.client.Socket;

import io.socket.emitter.Emitter;

public class MainActivity extends AppCompatActivity {

EditText et_msg, et_host, et_port;

TextView tv_msg;

Button btn_connect, btn_send;

Socket socket;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

init();

}

private void init() {

et_msg = findViewById(R.id.editText_msg);

et_host = findViewById(R.id.editText_host);

et_port = findViewById(R.id.editText_port);

tv_msg = findViewById(R.id.TextView_msgFromServer);

btn_connect = findViewById(R.id.btn_connect);

btn_send = findViewById(R.id.btn_send);

btn_connect.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

if(socket != null)

return;

try {

String host = et_host.getText().toString();

int port = Integer.parseInt(et_port.getText().toString());

URL url = new URL("http", host, port, "/");

socket = IO.socket(url.toURI());

socket.connect();

socket.on("SEND"new Emitter.Listener() {

@Override

public void call(final Object... args) {

runOnUiThread(new Runnable() {

@Override

public void run() {

try {

JSONObject data = (JSONObject) args[0];

tv_msg.setText(data.getString("message"));

catch(Exception e) {

Toast.makeText(getApplicationContext(), e.getMessage(),

Toast.LENGTH_LONG).show();

e.printStackTrace();

}

}

});

}

});

catch(Exception e) {

Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG)

.show();

e.printStackTrace();

}

}

});

btn_send.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

if(socket != null) {

JSONObject data = new JSONObject();

try {

data.put("message", et_msg.getText().toString());

socket.emit("SEND", data);

catch(Exception e) {

Toast.makeText(getApplicationContext(), e.getMessage(), Toast

.LENGTH_LONG).show();

e.printStackTrace();

}

}

}

});

}

@Override

protected void onDestroy() {

super.onDestroy();

socket.emit("disconnect"null);

socket.disconnect();

}

}

- 간단한 버튼들로 Retrofit을 이용해 node.js 서버와 각각 ( post / get / put / delete )의 통신 방법으로 데이터를 주고받는 기능을 구현해보자 

  • 프로젝트 생성
안드로이드 node js 통신 - andeuloideu node js tongsin

Create New Project

안드로이드 node js 통신 - andeuloideu node js tongsin

Empty Activity / Next

안드로이드 node js 통신 - andeuloideu node js tongsin

Name : Example_Retrofit / Finish

  • 버튼 만들기

- activity_main.xml

: Layout은 본인 편한대로! 저는 ConstraintLayout 공부중이라 이걸로... ( 쓰다보면 편할거같음 => 좋음 )

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <Button
        android:id="@+id/btn_get"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="GET"
        app:layout_constraintBottom_toTopOf="@+id/btn_post"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_chainStyle="packed" />

    <Button
        android:id="@+id/btn_post"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="POST"
        app:layout_constraintBottom_toTopOf="@id/btn_update"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn_get" />

    <Button
        android:id="@+id/btn_update"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="UPDATE"
        app:layout_constraintBottom_toTopOf="@id/btn_delete"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn_post" />

    <Button
        android:id="@+id/btn_delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="DELETE"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn_update" />

</androidx.constraintlayout.widget.ConstraintLayout>
안드로이드 node js 통신 - andeuloideu node js tongsin
  • gradle에 retrofit 추가

- build.gradle ( Module: Example_Retrofit.app ) 

: dependencies 블럭 안에 추가하고 우측 상단에 Sync Now 클릭!

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
안드로이드 node js 통신 - andeuloideu node js tongsin
안드로이드 node js 통신 - andeuloideu node js tongsin
  • AndroidManifest 에 권한 추가

- AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />

: <manifest ... > 태그 다음에 넣기

android:usesCleartextTraffic="true"

: <application 태그 안에 넣기 

안드로이드 node js 통신 - andeuloideu node js tongsin
  • 통신하면서 동작할 인터페이스 생성
안드로이드 node js 통신 - andeuloideu node js tongsin
안드로이드 node js 통신 - andeuloideu node js tongsin

- ApiService.java

package com.example.example_retrofit;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.DELETE;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Path;
import retrofit2.http.Query;

public interface ApiService {
    @GET("/retrofit/get")
    Call<ResponseBody> getFunc(@Query("data") String data);

    @FormUrlEncoded
    @POST("/retrofit/post")
    Call<ResponseBody> postFunc(@Field("data") String data);

    @FormUrlEncoded
    @PUT("/retrofit/put/{id}")
    Call<ResponseBody> putFunc(@Path("id") String id, @Field("data") String data);

    @DELETE("/retrofit/delete/{id}")
    Call<ResponseBody> deleteFunc(@Path("id") String id);
}

: GET - Query 형태로 보냄 

: POST - Field 형태로 보내기 때문에 @FormUrlEncoded 어노테이션 붙여줘야함

: PUT - 마찬가지로 Field 형태가 있어서 어노테이션 추가, 경로를 통해 id를 보냄

: DELETE - 경로를 통해 id를 보냄

=> 통신방법에 따라 보내는 형태가 다름 주의!

  • MainActivity 작성

- MainActivity.java

 : onCreate() 메소드 안에 소스코드가 길면 개인적으로 가독성이 좋지 않은것 같아서 메소드를 따로 만들어서 작성하는 편이다. 그리고 버튼이 비슷한 동작을 할 때에는 아래 코드처럼 클릭리스너를 implements해서 작성한다. 상황에 따라 본인이 알맞게 쓰시길... 코드스타일 굳히기가 너무 어렵다 ㅠ

package com.example.example_retrofit;

import androidx.appcompat.app.AppCompatActivity;

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

import java.io.IOException;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private final String TAG = "MainActivityLog";
    private final String URL = "http://192.168.0.174:3000";

    private Retrofit retrofit;
    private ApiService service;

    private Button btn_get, btn_post, btn_delete, btn_update;

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

        firstInit();

        btn_get.setOnClickListener(this);
        btn_post.setOnClickListener(this);
        btn_delete.setOnClickListener(this);
        btn_update.setOnClickListener(this);
    }

    /**
     * Init
     */
    public void firstInit() {
        btn_get = (Button) findViewById(R.id.btn_get);
        btn_post = (Button) findViewById(R.id.btn_post);
        btn_delete = (Button) findViewById(R.id.btn_delete);
        btn_update = (Button) findViewById(R.id.btn_update);

        retrofit = new Retrofit.Builder()
                .baseUrl(URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        service = retrofit.create(ApiService.class);
    }

    /**
     * View.OnLongClickListener override method
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_get:
                Call<ResponseBody> call_get = service.getFunc("get data");
                call_get.enqueue(new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                        if (response.isSuccessful()) {
                            try {
                                String result = response.body().string();
                                Log.v(TAG, "result = " + result);
                                Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        } else {
                            Log.v(TAG, "error = " + String.valueOf(response.code()));
                            Toast.makeText(getApplicationContext(), "error = " + String.valueOf(response.code()), Toast.LENGTH_SHORT).show();
                        }
                    }

                    @Override
                    public void onFailure(Call<ResponseBody> call, Throwable t) {
                        Log.v(TAG, "Fail");
                        Toast.makeText(getApplicationContext(), "Response Fail", Toast.LENGTH_SHORT).show();
                    }
                });
                break;

            case R.id.btn_post:
                Call<ResponseBody> call_post = service.postFunc("post data");
                call_post.enqueue(new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                        if (response.isSuccessful()) {
                            try {
                                String result = response.body().string();
                                Log.v(TAG, "result = " + result);
                                Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        } else {
                            Log.v(TAG, "error = " + String.valueOf(response.code()));
                            Toast.makeText(getApplicationContext(), "error = " + String.valueOf(response.code()), Toast.LENGTH_SHORT).show();
                        }
                    }

                    @Override
                    public void onFailure(Call<ResponseBody> call, Throwable t) {
                        Log.v(TAG, "Fail");
                        Toast.makeText(getApplicationContext(), "Response Fail", Toast.LENGTH_SHORT).show();
                    }
                });
                break;

            case R.id.btn_update:
                Call<ResponseBody> call_put = service.putFunc("board", "put data");
                call_put.enqueue(new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                        if (response.isSuccessful()) {
                            try {
                                String result = response.body().string();
                                Log.v(TAG, "result = " + result);
                                Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        } else {
                            Log.v(TAG, "error = " + String.valueOf(response.code()));
                            Toast.makeText(getApplicationContext(), "error = " + String.valueOf(response.code()), Toast.LENGTH_SHORT).show();
                        }
                    }

                    @Override
                    public void onFailure(Call<ResponseBody> call, Throwable t) {
                        Log.v(TAG, "Fail");
                        Toast.makeText(getApplicationContext(), "Response Fail", Toast.LENGTH_SHORT).show();
                    }
                });
                break;

            case R.id.btn_delete:
                Call<ResponseBody> call_delete = service.deleteFunc("board");
                call_delete.enqueue(new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                        if (response.isSuccessful()) {
                            try {
                                String result = response.body().string();
                                Log.v(TAG, "result = " + result);
                                Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        } else {
                            Log.v(TAG, "error = " + String.valueOf(response.code()));
                            Toast.makeText(getApplicationContext(), "error = " + String.valueOf(response.code()), Toast.LENGTH_SHORT).show();
                        }
                    }

                    @Override
                    public void onFailure(Call<ResponseBody> call, Throwable t) {
                        Log.v(TAG, "Fail");
                        Toast.makeText(getApplicationContext(), "Response Fail", Toast.LENGTH_SHORT).show();
                    }
                });
                break;
            default:
                break;
        }
    }

}

여기까지 앱에서 동작하는 부분은 완료! 다음 포스팅에서 각각의 버튼에 따라 동작하는 node.js 서버를 만들어보자.