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 )의 통신 방법으로 데이터를 주고받는 기능을 구현해보자
- 프로젝트 생성
Create New Project
Empty Activity / Next
Name : Example_Retrofit / Finish
- 버튼 만들기
- activity_main.xml
: Layout은 본인 편한대로! 저는 ConstraintLayout 공부중이라 이걸로... ( 쓰다보면 편할거같음 => 좋음 )
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="//schemas.android.com/apk/res/android" xmlns:app="//schemas.android.com/apk/res-auto" xmlns:tools="//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>- 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'- AndroidManifest 에 권한 추가
- AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />: <manifest ... > 태그 다음에 넣기
android:usesCleartextTraffic="true": <application 태그 안에 넣기
- 통신하면서 동작할 인터페이스 생성
- 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 = "//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 서버를 만들어보자.