728x90

그동안은 Retrofit을 사용할 일이 전혀 없었는데, 사용할 일이 있어서 관련 자료를 찾아서 테스트하고 적어둔다.

예제를 이해하는데 참 어려웠다. 그래서 유투브 동영상도 보고 이해하고 따라해보고 동작되는 걸 확인한 후에야 로직이 이해가 되었다.

구글에서 추천하는 Volley 라이브러리보다 속도가 빠르다고 검색결과가 나온다.

 

Retrofit 은 안전한 타입 방식의 HTTP 클라이언트로서 Android 와 Java 애플리케이션을 위한 라이브러리이다.

Json converter : JSON 타입의 응답결과를 객체로 매핑(변환)해주는 Converter

https://square.github.io/retrofit/ 를 참조한다. 그런데 설명만으로는 이해하기 어렵더라.

 

이해를 돕기 위해서 그림으로 설명한다.

Interface 생성

이 부분에는 GET/POST/PUT/DELETE 등 필요한 모든 함수를 선언하는 부분이다.

Call <> 사이에는 서버의 Json 형태에 따라 클래스 파일을 만들어서 넣어주면 된다.

/**
 * GET 방식, URL/getphoto.php/{code} 호출.
 * Data Type의 여러 개의 JSON을 통신을 통해 받음.
 * 주소값이 "http://www.abc.com/getphoto.php?code=1" 이 됨.
 * @param code 요청에 필요한 code
 * @return 다수의 Data 객체를 JSON 형태로 반환.
 */
@GET("/getphoto.php")
Call<Data> getData(@Query("code") String code);

 

 

앱 build.gradle 설정

    compileOptions { // 이거 안해주면 에러가 나오더라.
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

dependencies {
    implementation 'com.google.android.material:material:1.0.0'
    implementation 'com.squareup.retrofit2:retrofit:2.7.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.7.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.4.0'
}

 

AndroidManifest.xml

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

android:usesCleartextTraffic="true"

 

activity_login.xml

구글에서 Meterial Design 예제를 검색하면 나온다. 그걸 참조해서 하면 된다.

 

Resource 관련 파일을 첨부한다.

res.zip
다운로드

 

 

LoginActivity.java

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

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

public class LoginActivity extends AppCompatActivity implements View.OnClickListener {
    Context context;
    EditText etId;
    EditText etPw;
    String userID;
    String userPW;
    String uID; // 스마트 기기의 대체 고유값

    LoginAPI mloginService;

    PermissionListener permissionlistener = new PermissionListener() {
        @Override
        public void onPermissionGranted() {
            initView();
        }

        @Override
        public void onPermissionDenied(ArrayList<String> deniedPermissions) {
            Toast.makeText(LoginActivity.this, "권한 허용을 하지 않으면 서비스를 이용할 수 없습니다.", Toast.LENGTH_SHORT).show();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        context = LoginActivity.this;
        checkPermissions();
    }

    private void checkPermissions() {
        if (Build.VERSION.SDK_INT >= 23) { // 마시멜로(안드로이드 6.0) 이상 권한 체크
            TedPermission.with(context)
                    .setPermissionListener(permissionlistener)
                    .setRationaleMessage("앱을 이용하기 위해서는 접근 권한이 필요합니다")
                    .setDeniedMessage("앱에서 요구하는 권한설정이 필요합니다...\n [설정] > [권한] 에서 사용으로 활성화해주세요.")
                    .setPermissions(new String[]{
                            android.Manifest.permission.READ_PHONE_STATE,
                            android.Manifest.permission.READ_CALL_LOG, // 안드로이드 9.0 에서는 이것도 추가하라고 되어 있음.
                            android.Manifest.permission.CALL_PHONE,  // 전화걸기 및 관리
                            android.Manifest.permission.ACCESS_FINE_LOCATION
                    })
                    .check();

        } else {
            initView();
        }
    }

    private void initView() {
        etId = findViewById(R.id.et_id);
        etPw = findViewById(R.id.et_pw);
        Button btn_login = findViewById(R.id.btn_login);

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Value.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .client(createOkHttpClient())
                .build();


        mloginService = retrofit.create(LoginAPI.class);
    }

    @Override
    public void onClick(View v) {
        userID = etId.getText().toString().trim();
        userPW = etPw.getText().toString().trim();
        uID = Settings.Secure.getString(getApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);
        mloginService.Login(userID, userPW, uID)
                .enqueue(new Callback<LoginResult>() {
            @Override
            public void onResponse(Call<LoginResult> call, Response<LoginResult> response) {
                // 네트워크 통신 성공
                LoginResult result = response.body();
                if(result.getResult().contains("success")){
                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY);
                    startActivity(intent);
                    finish();
                } else {
                    showAlert(result.getResult(),result.getMessage());
                }
            }

            @Override
            public void onFailure(Call<LoginResult> call, Throwable t) {
                // 네트워크 통신 실패
            }
        });
    }



    private OkHttpClient createOkHttpClient() {
        // 네트워크 통신 로그(서버로 보내는 파라미터 및 받는 파라미터) 보기
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        builder.addInterceptor(interceptor);
        return builder.build();
    }

    public void showAlert(String title, String message) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle(title);
        builder.setMessage(message)
                .setCancelable(false)
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        dialog.dismiss();
                    }
                });
        AlertDialog alert = builder.create();
        alert.show();
    }
}

public interface LoginAPI { // 서버에 호출할 메소드를 선언하는 인터페이스
    // POST 방식으로 데이터를 주고 받을 때 넘기는 변수는 Field 라고 해야 한다.
    @FormUrlEncoded
    @POST(Value.URL_LOGIN)
    Call<LoginResult> Login(
            @Field("userId") String userId,
            @Field("userPw") String userPw,
            @Field("uuid") String uuid
            );
}

public class LoginResult { // 결과를 받을 모델
    private String result;
    private String message;

    public String getResult() {
        return result;
    }

    public String getMessage() {
        return message;
    }
}

public class Value extends AppCompatActivity {
    public static final String BASE_URL = "http://www.abc.com/mobile/";
    public static final String URL_LOGIN = "login.php";
}

 

예제는 결과를 받아서 RecyclerView 에 보여준다거나 후속 action 에 대한 건 기술하지 않았다.

이 예제는 그냥 복사해서 붙여넣기를 어떻게 하는지에 대한 설명이라고 보면 된다.

PHP 파일에 대한 사항은 기술하지 않는다. 이미 본 블로그 다른 예제를 보면 충분히 이해할 수 있으리라.

 

참고하면 도움되는 글

https://thdev.tech/androiddev/2016/11/13/Android-Retrofit-Intro/

 

https://link2me.tistory.com/1850 ArrayList 처리 예제

 

 

Update : 2020.8.3일

ㅇ Retrofit2 라이브러리를 여러번 호출하는 걸 만들어야 한다면 함수화를 하는 게 좋다.

 

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitAPI {
    private static Retrofit retrofit = null;

    public static Retrofit getClient() {
        retrofit = new Retrofit.Builder()
                .baseUrl(Value.IPADDRESS)
                .addConverterFactory(GsonConverterFactory.create())
                .client(createOkHttpClient())
                .build();

        return retrofit;
    }

    private static OkHttpClient createOkHttpClient() {
        // 네트워크 통신 로그(서버로 보내는 파라미터 및 받는 파라미터) 보기
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        builder.addInterceptor(interceptor);
        return builder.build();
    }
}

 

사용 예제

public interface RemoteService {// 서버에 호출할 메소드를 선언하는 인터페이스
    // POST 방식으로 데이터를 주고 받을 때 넘기는 변수는 Field 라고 해야 한다.
    @FormUrlEncoded
    @POST(RetrofitUrl.URL_Verson)
    Call<VersionResult> lastVersion(
            @Field("os") String os
    );

    @FormUrlEncoded
    @POST(RetrofitUrl.URL_GroupList)
    Call<GroupResult> getGroupList(
            @Field("keyword") String keyword
    );
}

class RetrofitUrl {
    companion object {
        const val URL_Verson = "lastVersion.php"
        const val URL_GroupList = "groupList.php"
    }
}

private void UpgradeChk() {
    mloginService = RetrofitAPI.getClient().create(RemoteService.class);
    mloginService.lastVersion("0").enqueue(new Callback<VersionResult>() {
        @Override
        public void onResponse(Call<VersionResult> call, Response<VersionResult> response) {
            VersionResult result = response.body();

            version = Value.VERSION; // 앱 버전
            version = version.replaceAll("[^0-9]", ""); // 버전에서 숫자만 추출
            Log.d("WEB", "Response: " + response);

            String Response = result.getVersion().replaceAll("[^0-9]", ""); // 버전에서 숫자만 추출
            System.out.println("Server Version : " + Response);

            if (Integer.parseInt(version) < Integer.parseInt(Response)) { // 서버 버전이 더 높으면
                UpgradeProcess();
                if(Build.VERSION.SDK_INT >= 26)  {
                    NonSecretApp_Setting(); // 출처를 알 수 없는 앱 설정 화면 띄우기
                } else {
                    startActivity(new Intent(android.provider.Settings.ACTION_SECURITY_SETTINGS));
                }
            } else {
                AutoLoginProgress();
            }
        }

        @Override
        public void onFailure(Call<VersionResult> call, Throwable t) {

        }
    });
}

 

더 세부적인 것은 Github 에 올려진 소스코드를 참조하면 도움될 것이다.

https://github.com/jsk005/JavaProjects/tree/master/retrofitsample

 

GitHub - jsk005/JavaProjects: 자바 기능 테스트

자바 기능 테스트. Contribute to jsk005/JavaProjects development by creating an account on GitHub.

github.com

 

728x90
블로그 이미지

Link2Me

,