<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발공부</title>
    <link>https://mscha.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 24 Jul 2026 11:58:34 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>mscha</managingEditor>
    <item>
      <title>[Firebase] Realtime DataBase를 사용하기 위한 환경 설정</title>
      <link>https://mscha.tistory.com/244</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;firebase의 Realtime DataBase를 사용하기 위해 환경 설정을 하는데 어려움을 겪었어서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 설정한 방법을 게시합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;firebase 콘솔에서 앱추가를 하여 google-services.json 파일을 받은 상태라고 가정하고 진행하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 안드로이드 스튜디오의 폴더 형식을 Project로 변경합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;193&quot; data-origin-height=&quot;231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSBBuX/btrMjCLns9R/OP4Mt5r3TC2czZGIMSTGi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSBBuX/btrMjCLns9R/OP4Mt5r3TC2czZGIMSTGi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSBBuX/btrMjCLns9R/OP4Mt5r3TC2czZGIMSTGi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSBBuX%2FbtrMjCLns9R%2FOP4Mt5r3TC2czZGIMSTGi1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;193&quot; height=&quot;231&quot; data-origin-width=&quot;193&quot; data-origin-height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 받은 google-serviecs.json 파일을 app 폴더 안에 넣습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;206&quot; data-origin-height=&quot;244&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkw78G/btrMhWEwHei/vw7e1ZH4GxtpabSDV0kkzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkw78G/btrMhWEwHei/vw7e1ZH4GxtpabSDV0kkzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkw78G/btrMhWEwHei/vw7e1ZH4GxtpabSDV0kkzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbkw78G%2FbtrMhWEwHei%2Fvw7e1ZH4GxtpabSDV0kkzk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;206&quot; height=&quot;244&quot; data-origin-width=&quot;206&quot; data-origin-height=&quot;244&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 프로젝트 수준 gradle 파일의 plugins에 아래 형식을 추가합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1663309781168&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plugins {
    id &quot;com.google.gms.google-services&quot; version &quot;4.3.10&quot; apply false
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 모듈 수준 gradel 파일의 plugins와 dependencies에 아래 형식을 추가합니다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;plugins {
    id 'com.google.gms.google-services'
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;dependencies {
    implementation platform('com.google.firebase:firebase-bom:30.3.2')
    implementation 'com.google.firebase:firebase-analytics'
    implementation 'com.google.firebase:firebase-database'

    implementation 'commons-io:commons-io:2.4'
}
apply plugin: 'com.google.gms.google-services'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5.&amp;nbsp; Sync를 누릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. SDK Manager로 들어갑니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;206&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsUkdc/btrMTDZdNnv/sftNIAJihFuvEWjyPPQMgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsUkdc/btrMTDZdNnv/sftNIAJihFuvEWjyPPQMgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsUkdc/btrMTDZdNnv/sftNIAJihFuvEWjyPPQMgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsUkdc%2FbtrMTDZdNnv%2FsftNIAJihFuvEWjyPPQMgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;206&quot; height=&quot;126&quot; data-origin-width=&quot;206&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. SDK Tools의 Google Play services를 체크 후 OK를 눌러 적용해줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;307&quot; data-origin-height=&quot;445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CNx4U/btrMTKqpOTD/WTerx1G2N8T2d4ZFvC9YE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CNx4U/btrMTKqpOTD/WTerx1G2N8T2d4ZFvC9YE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CNx4U/btrMTKqpOTD/WTerx1G2N8T2d4ZFvC9YE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCNx4U%2FbtrMTKqpOTD%2FWTerx1G2N8T2d4ZFvC9YE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;307&quot; height=&quot;445&quot; data-origin-width=&quot;307&quot; data-origin-height=&quot;445&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Android</category>
      <author>mscha</author>
      <guid isPermaLink="true">https://mscha.tistory.com/244</guid>
      <comments>https://mscha.tistory.com/244#entry244comment</comments>
      <pubDate>Fri, 16 Sep 2022 15:36:13 +0900</pubDate>
    </item>
    <item>
      <title>Serverless Region(지역) 변경하기</title>
      <link>https://mscha.tistory.com/243</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;서버리스로 배포한 프로젝트의 경로로가서 serverless.yml을 엽니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨위의 이부분을 지우고&lt;/p&gt;
&lt;pre id=&quot;code_1660784977071&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;org: fullspringwater
app: aws-movie-server&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드를 추가합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1660785022190&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console: true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;provider 부분에 region 부분을 추가합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1660785045982&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;provider:
  name: aws
  runtime: python3.8
  region: ap-northeast-2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 deploy 해주시면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1660801076519&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sls deploy&lt;/code&gt;&lt;/pre&gt;</description>
      <category>AWS/Lambda</category>
      <author>mscha</author>
      <guid isPermaLink="true">https://mscha.tistory.com/243</guid>
      <comments>https://mscha.tistory.com/243#entry243comment</comments>
      <pubDate>Thu, 18 Aug 2022 14:38:01 +0900</pubDate>
    </item>
    <item>
      <title>[Android] GPS 위도, 경도 정보 받기, 권한 설정</title>
      <link>https://mscha.tistory.com/242</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;androidManifest.xml&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 권한을 추가합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;uses-permission android:name=&quot;android.permission.ACCESS_FINE_LOCATION&quot;/&amp;gt;
&amp;lt;uses-permission android:name=&quot;android.permission.ACCESS_COARSE_LOCATION&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;MainActivity.java&lt;/h4&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.fullspringwater.location;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    LocationManager locationManager;
    LocationListener locationListener;

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

        locationManager = (LocationManager) this.getSystemService(LOCATION_SERVICE);
        locationListener = new LocationListener() {
            // 움직일 때 마다 location에 좌표정보를 담는다.
            @Override
            public void onLocationChanged(@NonNull Location location) {
                Log.i(&quot;myLocation&quot;, &quot;위도 : &quot; + location.getLatitude());
                Log.i(&quot;myLocation&quot;, &quot;경도 : &quot; + location.getLongitude());
            }
        };


        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &amp;amp;&amp;amp; ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
                                Manifest.permission.ACCESS_COARSE_LOCATION},
                    100);
            return;
        }
        // LocationManager.GPS_PROVIDER
        // locationRequest : 어느 시간 주기로 이동을 감지할 것인지 (ms)
        // pendingIntent : 어느 거리만큼 이동했을 때 감지할 것인지 (m)
        // 조건을 사용하지 않으려면 -1로 지정한다.
        // 둘중 하나만 충족해도 update한다.
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                3000,
                3,
                locationListener);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if(requestCode == 100){
            // 권한 설정 여부
            if (ActivityCompat.checkSelfPermission(MainActivity.this,
                    Manifest.permission.ACCESS_FINE_LOCATION) !=
                    PackageManager.PERMISSION_GRANTED &amp;amp;&amp;amp;
                    ActivityCompat.checkSelfPermission(MainActivity.this,
                            Manifest.permission.ACCESS_COARSE_LOCATION) !=
                                    PackageManager.PERMISSION_GRANTED) {
                // 권한 거부상태면 다이얼로그를 띄운다.
                AlertDialog.Builder localBuilder = new AlertDialog.Builder(this);
                localBuilder.setTitle(&quot;권한 설정&quot;)
                        .setMessage(&quot;권한을 설정하지 않으면 앱 사용이 불가능합니다.&quot;)
                        .setPositiveButton(&quot;권한 설정하러 가기&quot;, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                try {
                                    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                                            .setData(Uri.parse(&quot;package:&quot; + getPackageName()));
                                    startActivity(intent);
                                } catch (ActivityNotFoundException e){
                                    e.printStackTrace();
                                    Intent intent = new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
                                    startActivity(intent);
                                }
                            }
                        })
                        .setNegativeButton(&quot;종료하기&quot;, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
//                                Toast.makeText(getApplication(), &quot;제한됩니다.&quot;, Toast.LENGTH_SHORT).show();
                                finish();
                            }
                        }).create().show();


                return;
            }

            // LocationManager.GPS_PROVIDER
            // locationRequest : 어느 시간 주기로 이동을 감지할 것인지 (ms)
            // pendingIntent : 어느 거리만큼 이동했을 때 감지할 것인지 (m)
            // 조건을 사용하지 않으려면 -1로 지정한다.
            // 둘중 하나만 충족해도 update한다.
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                    3000,
                    3,
                    locationListener);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;실행화면&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dboWQW/btrItvwK4Wc/wNOE1CHdpPn2DPt1drNGdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dboWQW/btrItvwK4Wc/wNOE1CHdpPn2DPt1drNGdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dboWQW/btrItvwK4Wc/wNOE1CHdpPn2DPt1drNGdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdboWQW%2FbtrItvwK4Wc%2FwNOE1CHdpPn2DPt1drNGdk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;406&quot; height=&quot;714&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;714&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거부 눌렀을 때&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;704&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doQD7S/btrIoAMA68O/Bvm2uKjKo0nOwU34ne07uK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doQD7S/btrIoAMA68O/Bvm2uKjKo0nOwU34ne07uK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doQD7S/btrIoAMA68O/Bvm2uKjKo0nOwU34ne07uK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoQD7S%2FbtrIoAMA68O%2FBvm2uKjKo0nOwU34ne07uK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;407&quot; height=&quot;704&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;704&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;권한 설정하기 눌렀을 때&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;405&quot; data-origin-height=&quot;710&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6wA43/btrIwHwemZ6/Kf09UXDNBN11gMhYmFUoVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6wA43/btrIwHwemZ6/Kf09UXDNBN11gMhYmFUoVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6wA43/btrIwHwemZ6/Kf09UXDNBN11gMhYmFUoVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6wA43%2FbtrIwHwemZ6%2FKf09UXDNBN11gMhYmFUoVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;405&quot; height=&quot;710&quot; data-origin-width=&quot;405&quot; data-origin-height=&quot;710&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 권한 허용이 가능합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;405&quot; data-origin-height=&quot;725&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWsbju/btrItvKfYFw/JYIHxu9WhT6I0gfOSkFCk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWsbju/btrItvKfYFw/JYIHxu9WhT6I0gfOSkFCk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWsbju/btrItvKfYFw/JYIHxu9WhT6I0gfOSkFCk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWsbju%2FbtrItvKfYFw%2FJYIHxu9WhT6I0gfOSkFCk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;405&quot; height=&quot;725&quot; data-origin-width=&quot;405&quot; data-origin-height=&quot;725&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;권한 허용 후 로그캣&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8sUUV/btrIq6Eghbt/8PUfYXPjeTsKTG4Id1oRwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8sUUV/btrIq6Eghbt/8PUfYXPjeTsKTG4Id1oRwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8sUUV/btrIq6Eghbt/8PUfYXPjeTsKTG4Id1oRwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8sUUV%2FbtrIq6Eghbt%2F8PUfYXPjeTsKTG4Id1oRwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;832&quot; height=&quot;44&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;44&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Android</category>
      <author>mscha</author>
      <guid isPermaLink="true">https://mscha.tistory.com/242</guid>
      <comments>https://mscha.tistory.com/242#entry242comment</comments>
      <pubDate>Fri, 29 Jul 2022 11:16:12 +0900</pubDate>
    </item>
    <item>
      <title>[Android] Retrofit2 라이브러리  form-data 형식 파일, 텍스트 전송하기(Multipart form 이용)</title>
      <link>https://mscha.tistory.com/241</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;아래와 같이 Heder로는 Authorization.&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Body로는 form-data 형식의 key - value로 되어있는&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;File과 Text를 옮기는 방법을 알아보겠습니다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;170&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kA34x/btrIdx9my4M/5Cld9TunO8LEKL2rTHb3PK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kA34x/btrIdx9my4M/5Cld9TunO8LEKL2rTHb3PK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kA34x/btrIdx9my4M/5Cld9TunO8LEKL2rTHb3PK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkA34x%2FbtrIdx9my4M%2F5Cld9TunO8LEKL2rTHb3PK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;701&quot; height=&quot;170&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;170&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TguQu/btrH2ostaLU/Aqe6hFta1bwbY0KLbEGaV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TguQu/btrH2ostaLU/Aqe6hFta1bwbY0KLbEGaV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TguQu/btrH2ostaLU/Aqe6hFta1bwbY0KLbEGaV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTguQu%2FbtrH2ostaLU%2FAqe6hFta1bwbY0KLbEGaV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;752&quot; height=&quot;222&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;137&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuq9o5/btrIdXNuS2w/8jGGkLiCDKhuoQmd10es71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuq9o5/btrIdXNuS2w/8jGGkLiCDKhuoQmd10es71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuq9o5/btrIdXNuS2w/8jGGkLiCDKhuoQmd10es71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcuq9o5%2FbtrIdXNuS2w%2F8jGGkLiCDKhuoQmd10es71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;416&quot; height=&quot;137&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;137&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;475&quot; data-origin-height=&quot;143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F3DOc/btrIhiDqi5O/M8BaKjKWjKXHQASQgySwZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F3DOc/btrIhiDqi5O/M8BaKjKWjKXHQASQgySwZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F3DOc/btrIhiDqi5O/M8BaKjKWjKXHQASQgySwZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF3DOc%2FbtrIhiDqi5O%2FM8BaKjKWjKXHQASQgySwZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;475&quot; height=&quot;143&quot; data-origin-width=&quot;475&quot; data-origin-height=&quot;143&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제로는 이미지와 텍스트를 올리는 것으로 하겠습니다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;API 인터페이스&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;PostingApi&lt;/h4&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;// 파일을 알아서 쪼개서 보내줌 @Multipart
@Multipart
@POST(&quot;/posting&quot;)
Call&amp;lt;PostingRes&amp;gt; addPosting(@Header(&quot;Authorization&quot;) String AccessToken,
                            @Part MultipartBody.Part photo,
                            @Part(&quot;content&quot;)RequestBody content);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;PostingRes&lt;/h4&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class PostingRes {
    private String result;


    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }
   
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;호출 부분&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;AddActivity&lt;/h4&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;Retrofit retrofit = NetworkClient.getRetrofitClient(AddActivity.this);
PostingApi api = retrofit.create(PostingApi.class);

// 멀티파트로 파일을 보내는 경우, 파일 파라미터 만드는 방법
RequestBody fileBody = RequestBody.create(photoFile, MediaType.parse(&quot;image/*&quot;));
// 키값, 파일명, 실제 파일
MultipartBody.Part photo = MultipartBody.Part.createFormData(&quot;photo&quot;,
        photoFile.getName(), fileBody);

// 멀티파트로 form-data형식 text 보내는 경우
RequestBody contentBody = RequestBody.create(&quot;보낼 텍스트&quot;, MediaType.parse(&quot;text/plain&quot;));

// 헤더에 들어갈 억세스토큰 가져온다.
SharedPreferences sp = getApplication()
        .getSharedPreferences(Config.PREFERENCES_NAME, MODE_PRIVATE);
String accessToken = sp.getString(&quot;accessToken&quot;, &quot;&quot;);


Call&amp;lt;PostingRes&amp;gt; call = api.addPosting(&quot;Bearer &quot; + accessToken, photo, contentBody);


call.enqueue(new Callback&amp;lt;PostingRes&amp;gt;() {
    @Override
    public void onResponse(Call&amp;lt;PostingRes&amp;gt; call, Response&amp;lt;PostingRes&amp;gt; response) {
       
        if(response.isSuccessful()){
            Toast.makeText(AddActivity.this, &quot;포스팅 완료&quot;, Toast.LENGTH_SHORT).show();
            finish();
        }else {
            Toast.makeText(AddActivity.this, &quot;에러발생 : &quot; + response.code(),
                    Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onFailure(Call&amp;lt;PostingRes&amp;gt; call, Throwable t) {
     
        // 네트워크 자체 문제로 실패
        Toast.makeText(AddActivity.this, &quot;네트워크에 문제가 있습니다.&quot;, Toast.LENGTH_SHORT).show();
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;이때 photoFile은 아래 게시글의 과정을 통해 얻어온 File형식의 변수입니다.&lt;/h4&gt;
&lt;figure id=&quot;og_1658798348008&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Android] 카메라 / 앨범 처리&quot; data-og-description=&quot;build.gradle 아래 코드를 추가합니다. dependencies { implementation 'commons-io:commons-io:2.4' } res/xml 경로 fileprovider.xml 파일을 생성합니다. fileprovider.xml &amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-..&quot; data-og-host=&quot;mscha.tistory.com&quot; data-og-source-url=&quot;https://mscha.tistory.com/237?category=1084575&quot; data-og-url=&quot;https://mscha.tistory.com/237&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/MZYbM/hyPdcplIX6/J8HF72VKZPOgvMP0f2pdWk/img.png?width=218&amp;amp;height=185&amp;amp;face=0_0_218_185,https://scrap.kakaocdn.net/dn/XmmJ4/hyPdgZAOLg/scYbQqawKQo3fUsokNqUlk/img.png?width=218&amp;amp;height=185&amp;amp;face=0_0_218_185,https://scrap.kakaocdn.net/dn/c8nQw3/hyPc4Zarha/to3yvRAblzwvGztkfAwX9K/img.png?width=300&amp;amp;height=633&amp;amp;face=0_0_300_633&quot;&gt;&lt;a href=&quot;https://mscha.tistory.com/237?category=1084575&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mscha.tistory.com/237?category=1084575&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/MZYbM/hyPdcplIX6/J8HF72VKZPOgvMP0f2pdWk/img.png?width=218&amp;amp;height=185&amp;amp;face=0_0_218_185,https://scrap.kakaocdn.net/dn/XmmJ4/hyPdgZAOLg/scYbQqawKQo3fUsokNqUlk/img.png?width=218&amp;amp;height=185&amp;amp;face=0_0_218_185,https://scrap.kakaocdn.net/dn/c8nQw3/hyPc4Zarha/to3yvRAblzwvGztkfAwX9K/img.png?width=300&amp;amp;height=633&amp;amp;face=0_0_300_633');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Android] 카메라 / 앨범 처리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;build.gradle 아래 코드를 추가합니다. dependencies { implementation 'commons-io:commons-io:2.4' } res/xml 경로 fileprovider.xml 파일을 생성합니다. fileprovider.xml &amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mscha.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Android</category>
      <author>mscha</author>
      <guid isPermaLink="true">https://mscha.tistory.com/241</guid>
      <comments>https://mscha.tistory.com/241#entry241comment</comments>
      <pubDate>Tue, 26 Jul 2022 10:23:09 +0900</pubDate>
    </item>
    <item>
      <title>[Android] Progress Dialog 프로그레스 다이얼로그 생성/제거</title>
      <link>https://mscha.tistory.com/240</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;변수 선언&lt;/h4&gt;
&lt;pre id=&quot;code_1658710008894&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 네트워크 처리 보여주는 프로그레스 다이얼로그
    ProgressDialog dialog;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;함수 정의&lt;/h4&gt;
&lt;pre id=&quot;code_1658710025101&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void showProgress(String message){
        dialog = new ProgressDialog(this);
        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        dialog.setMessage(message);
        dialog.show();
    }

    void dismissProgress(){
        dialog.dismiss();
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;사용하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성&lt;/p&gt;
&lt;pre id=&quot;code_1658710062647&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;showProgress(&quot;보여줄 텍스트&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제거&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;dismissProgress();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Android</category>
      <author>mscha</author>
      <guid isPermaLink="true">https://mscha.tistory.com/240</guid>
      <comments>https://mscha.tistory.com/240#entry240comment</comments>
      <pubDate>Mon, 25 Jul 2022 09:49:06 +0900</pubDate>
    </item>
    <item>
      <title>[Android] Retrofit2 라이브러리를 이용한 POST로 API 호출하여 처리하는 방법</title>
      <link>https://mscha.tistory.com/239</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;retrofit2 라이브러리 사용하기 전&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 설정 방법은 아래 링크에 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mscha.tistory.com/238&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://mscha.tistory.com/238&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1658392259937&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Android] Retrofit2 라이브러리 사용을 위한 설정 방법&quot; data-og-description=&quot;build.gradle 아래 코드를 추가합니다. dependencies { implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation(&amp;quot;com.squareup.o..&quot; data-og-host=&quot;mscha.tistory.com&quot; data-og-source-url=&quot;https://mscha.tistory.com/238&quot; data-og-url=&quot;https://mscha.tistory.com/238&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bczHjc/hyParGJFje/PkfJOkYMsh8l6JfaYwvmN1/img.png?width=332&amp;amp;height=178&amp;amp;face=0_0_332_178,https://scrap.kakaocdn.net/dn/GO2Dh/hyPax709zz/k5tNRNzL3C5I6vf5FkDKWK/img.png?width=332&amp;amp;height=178&amp;amp;face=0_0_332_178,https://scrap.kakaocdn.net/dn/cqpq7B/hyPaq17L91/fXVu0vKmR92JGKjB86tSo0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://mscha.tistory.com/238&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mscha.tistory.com/238&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bczHjc/hyParGJFje/PkfJOkYMsh8l6JfaYwvmN1/img.png?width=332&amp;amp;height=178&amp;amp;face=0_0_332_178,https://scrap.kakaocdn.net/dn/GO2Dh/hyPax709zz/k5tNRNzL3C5I6vf5FkDKWK/img.png?width=332&amp;amp;height=178&amp;amp;face=0_0_332_178,https://scrap.kakaocdn.net/dn/cqpq7B/hyPaq17L91/fXVu0vKmR92JGKjB86tSo0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Android] Retrofit2 라이브러리 사용을 위한 설정 방법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;build.gradle 아래 코드를 추가합니다. dependencies { implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation(&quot;com.squareup.o..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mscha.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 POST 메소드로 api의 body에 아래와 같은식으로 데이터를 주면&lt;/p&gt;
&lt;pre id=&quot;code_1658392363590&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;email&quot;: &quot;test9@naver.com&quot;,
    &quot;password&quot;: &quot;1234&quot;,
    &quot;nickname&quot;: &quot;김동주&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 식으로 결과가 나오는 api를 가지고 테스트 해보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1658392389445&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;result&quot;: &quot;success&quot;,
    &quot;access_token&quot;: &quot;eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTY1ODM4NzA0NiwianRpIjoiNGVmNGNiMGQtNTVjMC00MjVlLWI4YzYtNzg1N2RjYWFiNWQxIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6MTAsIm5iZiI6MTY1ODM4NzA0Nn0.YVCP9wcN1rnNh_4OUTNnT4-aPbG15_bwe7drwHkO4xQ&quot;,
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;기본적으로 아래와 같은 식의 구성을 만들어 줍니다.&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;313&quot; data-origin-height=&quot;226&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byzMij/btrHUBctoPd/IlKmYRsC8M9Is3jRLBfzQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byzMij/btrHUBctoPd/IlKmYRsC8M9Is3jRLBfzQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byzMij/btrHUBctoPd/IlKmYRsC8M9Is3jRLBfzQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyzMij%2FbtrHUBctoPd%2FIlKmYRsC8M9Is3jRLBfzQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;313&quot; height=&quot;226&quot; data-origin-width=&quot;313&quot; data-origin-height=&quot;226&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.회원가입 화면 만들기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;activity_register.xml&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;androidx.constraintlayout.widget.ConstraintLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.RegisterActivity&quot;&amp;gt;

    &amp;lt;LinearLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:layout_margin=&quot;10dp&quot;
        android:orientation=&quot;vertical&quot;
        app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
        app:layout_constraintEnd_toEndOf=&quot;parent&quot;
        app:layout_constraintStart_toStartOf=&quot;parent&quot;
        app:layout_constraintTop_toTopOf=&quot;parent&quot;&amp;gt;

        &amp;lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_marginTop=&quot;30dp&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;회원가입&quot;
            android:textSize=&quot;28sp&quot; /&amp;gt;

        &amp;lt;EditText
            android:id=&quot;@+id/editEmail&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_marginTop=&quot;30dp&quot;
            android:ems=&quot;10&quot;
            android:hint=&quot;이메일&quot;
            android:inputType=&quot;textPersonName&quot;
            android:textSize=&quot;28sp&quot; /&amp;gt;

        &amp;lt;EditText
            android:id=&quot;@+id/editPassword&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:ems=&quot;10&quot;
            android:hint=&quot;비밀번호&quot;
            android:inputType=&quot;textPersonName&quot;
            android:textSize=&quot;28sp&quot; /&amp;gt;

        &amp;lt;EditText
            android:id=&quot;@+id/editNickname&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:ems=&quot;10&quot;
            android:hint=&quot;닉네임&quot;
            android:inputType=&quot;textPersonName&quot;
            android:textSize=&quot;28sp&quot; /&amp;gt;

        &amp;lt;Button
            android:id=&quot;@+id/btnRegister&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_marginTop=&quot;50dp&quot;
            android:text=&quot;회원가입&quot;
            android:textSize=&quot;28sp&quot; /&amp;gt;
    &amp;lt;/LinearLayout&amp;gt;
&amp;lt;/androidx.constraintlayout.widget.ConstraintLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. model/User&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회원가입과 관련있는 데이터는 User이기 때문에 User 클래스를 만들어줍니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;package com.fullspringwater.memo.model;

import java.io.Serializable;

public class User implements Serializable {
    private String email;
    private String password;
    private String nickname;

    public User(String email, String password, String nickname) {
        this.email = email;
        this.password = password;
        this.nickname = nickname;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. model/RegisterRes&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;package com.fullspringwater.memo.model;

import java.io.Serializable;

public class RegisterRes implements Serializable {
    private String result;
    private String accessToken;

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. config/Config&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.fullspringwater.memo.config;

public class Config {

    public static final String BASE_URL = &quot;URL주소&quot;;
    public static final String TEST_URL = &quot;TEST_URL 주소&quot;;
    public static final String PREFERENCES_NAME = &quot;memo_app&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. api/UserApi&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@POST(&quot;/users/register&quot;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;: BASE_URL의 뒤에 오는 경로와 메소드를 지정해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Call&amp;lt;RegisterRes&amp;gt; register(@Body User user)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;: Body에 user 객체를 넘겨주고 반환은 RegisterRes 클래스의 형태로 줍니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;package com.fullspringwater.memo.api;

import com.fullspringwater.memo.model.RegisterRes;
import com.fullspringwater.memo.model.User;

import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.POST;

public interface UserApi {

    @POST(&quot;/users/register&quot;)
    Call&amp;lt;RegisterRes&amp;gt; register(@Body User user);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.&amp;nbsp; api/NetworkClient&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;네트워크 통신할 retrofit 객체를 반환하는 역할을 합니다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;package com.fullspringwater.memo.api;

import android.content.Context;

import com.fullspringwater.memo.config.Config;

import java.util.concurrent.TimeUnit;

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

public class NetworkClient {

    public static Retrofit retrofit;

    public static Retrofit getRetrofitClient(Context context){
        if(retrofit == null){
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);

            OkHttpClient httpClient = new OkHttpClient.Builder()
                    .connectTimeout(1, TimeUnit.MINUTES)
                    .readTimeout(1, TimeUnit.MINUTES)
                    .writeTimeout(1, TimeUnit.MINUTES)
                    .addInterceptor(loggingInterceptor)
                    .build();

            retrofit = new Retrofit.Builder().baseUrl(Config.BASE_URL)
                    .client(httpClient)
                    // 데이터를 주고 받을 때 클래스로 처리하겠다.
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. MainActivity&lt;/h3&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;package com.fullspringwater.memo;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.fullspringwater.memo.config.Config;

public class MainActivity extends AppCompatActivity {


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

        // 1. 쉐어드 프리퍼런스에서 억세스토큰을 가져온다.
        SharedPreferences sp = getApplication()
                .getSharedPreferences(Config.PREFERENCES_NAME, MODE_PRIVATE);
        String accessToken = sp.getString(&quot;accessToken&quot;, &quot;&quot;);

        // 2. 만약 억세스토큰이 없으면, 회원가입 액티비티를 실행하고,
        //    그렇지 않으면, 메모가져오는 API 호출해서, 리사이클러뷰로 화면에
        //    내 메모 보여준다.
        if(accessToken.isEmpty()){
            Intent intent = new Intent(MainActivity.this, RegisterActivity.class);
            startActivity(intent);
        }else{
            // todo : 내 메모 가져오는 api 호출
        }



    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. RegisterActivity&lt;/h3&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;package com.fullspringwater.memo;

import androidx.appcompat.app.AppCompatActivity;

import android.app.ProgressDialog;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.fullspringwater.memo.api.NetworkClient;
import com.fullspringwater.memo.api.UserApi;
import com.fullspringwater.memo.config.Config;
import com.fullspringwater.memo.model.RegisterRes;
import com.fullspringwater.memo.model.User;

import java.util.regex.Pattern;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;

public class RegisterActivity extends AppCompatActivity {
    EditText editEmail;
    EditText editPassword;
    EditText editNickName;
    Button btnRegister;

    // 네트워크 처리 보여주는 프로그레스 다이얼로그
    ProgressDialog dialog;

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

        editEmail = findViewById(R.id.editEmail);
        editPassword = findViewById(R.id.editPassword);
        editNickName = findViewById(R.id.editNickname);
        btnRegister = findViewById(R.id.btnRegister);
        btnRegister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 이메일 가져온다. 이메일 형식체크
                String email = editEmail.getText().toString().trim();
                Pattern pattern = android.util.Patterns.EMAIL_ADDRESS;
                if(pattern.matcher(email).matches() == false){
                    Toast.makeText(RegisterActivity.this
                            , &quot;이메일 형식이 올바르지 않습니다.&quot;
                            , Toast.LENGTH_SHORT).show();
                    return;
                }

                // 비밀번호 가져온다.
                String password = editPassword.getText().toString().trim();

                // 비밀번호 길이 체크
                if(password.length() &amp;lt; 4 || password.length() &amp;gt; 12){
                    Toast.makeText(RegisterActivity.this
                            , &quot;비밀번호 길이는 4자 이상, 12자 이하로 만들어주세요.&quot;
                            , Toast.LENGTH_SHORT).show();
                    return;
                }

                // 닉네임을 가져와서, 빈 문자열인지만 체크
                String nickname = editNickName.getText().toString().trim();
                if(nickname.isEmpty()){
                    Toast.makeText(RegisterActivity.this, &quot;닉네임 입력하세요.&quot;,
                            Toast.LENGTH_SHORT).show();
                    return;
                }

                // 이 데이터를 API로 호출
                // 네트워크 통해서 데이터를 보내고 있다는,
                // 프로그레스 다이얼로그를 먼저 띄운다.
                showProgress(getString(R.string.dialog_register));

                Retrofit retrofit = NetworkClient.getRetrofitClient(RegisterActivity.this);

                UserApi api = retrofit.create(UserApi.class);

                User user = new User(email, password, nickname);

                Call&amp;lt;RegisterRes&amp;gt; call = api.register(user);
                // 실제 api 호출
                call.enqueue(new Callback&amp;lt;RegisterRes&amp;gt;() {
                    @Override
                    public void onResponse(Call&amp;lt;RegisterRes&amp;gt; call, Response&amp;lt;RegisterRes&amp;gt; response) {
                        dismissProgress();

                        // 200 OK
                        if(response.isSuccessful()){
                            RegisterRes registerRes = response.body();

                            // 억세스토큰은, 이제 앱에서 api 호출할 때마다 헤더에 넣어서 보내야 한다.
                            // 따라서 억세스토큰은, 쉐어드 프리퍼런스에 저장해 놓는다.
                            SharedPreferences sp = getApplication().getSharedPreferences(Config.PREFERENCES_NAME, MODE_PRIVATE);
                            SharedPreferences.Editor editor = sp.edit();
                            editor.putString(&quot;accessToken&quot;, registerRes.getAccessToken());
                            editor.apply();

                            finish();

                        } else if(response.code() == 400){

                        } else{
                            Toast.makeText(RegisterActivity.this, &quot;에러발생 : &quot; + response.code(),
                                    Toast.LENGTH_SHORT).show();
                        }
                    }

                    @Override
                    public void onFailure(Call&amp;lt;RegisterRes&amp;gt; call, Throwable t) {
                        // 네트워크 자체 문제로 실패
                        dismissProgress();
                    }
                });




            }
        });
    }
    void showProgress(String message){
        dialog = new ProgressDialog(this);
        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        dialog.setMessage(message);
        dialog.show();
    }

    void dismissProgress(){
        dialog.dismiss();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행화면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;395&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mA0IW/btrHSAZ9Dy8/KagLLugsKJxFXFFQfKeBXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mA0IW/btrHSAZ9Dy8/KagLLugsKJxFXFFQfKeBXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mA0IW/btrHSAZ9Dy8/KagLLugsKJxFXFFQfKeBXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmA0IW%2FbtrHSAZ9Dy8%2FKagLLugsKJxFXFFQfKeBXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;395&quot; height=&quot;385&quot; data-origin-width=&quot;395&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz3JAL/btrHUL0oVnN/LgEF6c2cOiqhUpKtJg3eUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz3JAL/btrHUL0oVnN/LgEF6c2cOiqhUpKtJg3eUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz3JAL/btrHUL0oVnN/LgEF6c2cOiqhUpKtJg3eUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz3JAL%2FbtrHUL0oVnN%2FLgEF6c2cOiqhUpKtJg3eUk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;399&quot; height=&quot;387&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;387&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;403&quot; data-origin-height=&quot;399&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXxE9d/btrHUhFhDik/iJZVaJQbrXDvgPt11dGjk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXxE9d/btrHUhFhDik/iJZVaJQbrXDvgPt11dGjk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXxE9d/btrHUhFhDik/iJZVaJQbrXDvgPt11dGjk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXxE9d%2FbtrHUhFhDik%2FiJZVaJQbrXDvgPt11dGjk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;403&quot; height=&quot;399&quot; data-origin-width=&quot;403&quot; data-origin-height=&quot;399&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 api의 데이터베이스에 추가된 모습&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;35&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2ssXd/btrHPcrYdnp/KPqlFUUBfb7n8rfrGVph31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2ssXd/btrHPcrYdnp/KPqlFUUBfb7n8rfrGVph31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2ssXd/btrHPcrYdnp/KPqlFUUBfb7n8rfrGVph31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2ssXd%2FbtrHPcrYdnp%2FKPqlFUUBfb7n8rfrGVph31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;35&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;35&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Android</category>
      <author>mscha</author>
      <guid isPermaLink="true">https://mscha.tistory.com/239</guid>
      <comments>https://mscha.tistory.com/239#entry239comment</comments>
      <pubDate>Thu, 21 Jul 2022 17:50:29 +0900</pubDate>
    </item>
    <item>
      <title>[Android] Retrofit2 라이브러리 사용을 위한 설정 방법</title>
      <link>https://mscha.tistory.com/238</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;build.gradle&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드를 추가합니다.&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;dependencies {
    
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation(&quot;com.squareup.okhttp3:logging-interceptor:4.9.0&quot;)

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;res/xml&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;network_security_config.xml&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;332&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XGNp3/btrHQIRpv3F/N2MNQcLpwW6vLUKPLySAN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XGNp3/btrHQIRpv3F/N2MNQcLpwW6vLUKPLySAN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XGNp3/btrHQIRpv3F/N2MNQcLpwW6vLUKPLySAN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXGNp3%2FbtrHQIRpv3F%2FN2MNQcLpwW6vLUKPLySAN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;332&quot; height=&quot;178&quot; data-origin-width=&quot;332&quot; data-origin-height=&quot;178&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&amp;gt;

&amp;lt;network-security-config&amp;gt;
    &amp;lt;domain-config cleartextTrafficPermitted=&quot;false&quot;&amp;gt;
        &amp;lt;domain includeSubdomains=&quot;true&quot;&amp;gt;*.허용할 도메인&amp;lt;/domain&amp;gt;
    &amp;lt;/domain-config&amp;gt;
&amp;lt;/network-security-config&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;AndroidMenifest.xml&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드를 추가합니다.&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;android:targetSandboxVersion=&quot;1&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;uses-permission android:name=&quot;android.permission.INTERNET&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;android:networkSecurityConfig=&quot;@xml/network_security_config&quot;
android:usesCleartextTraffic=&quot;true&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;예시&lt;/h4&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    package=&quot;com.fullspringwater.memo&quot;
    android:targetSandboxVersion=&quot;1&quot;&amp;gt;

    &amp;lt;uses-permission android:name=&quot;android.permission.INTERNET&quot;/&amp;gt;



    &amp;lt;application
        android:networkSecurityConfig=&quot;@xml/network_security_config&quot;
        android:usesCleartextTraffic=&quot;true&quot;
        android:allowBackup=&quot;true&quot;
        android:dataExtractionRules=&quot;@xml/data_extraction_rules&quot;
        android:fullBackupContent=&quot;@xml/backup_rules&quot;
        android:icon=&quot;@mipmap/ic_launcher&quot;
        android:label=&quot;@string/app_name&quot;
        android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;
        android:supportsRtl=&quot;true&quot;
        android:theme=&quot;@style/Theme.Memo&quot;
        tools:targetApi=&quot;31&quot;&amp;gt;
        &amp;lt;activity
            android:name=&quot;.RegisterActivity&quot;
            android:exported=&quot;false&quot; /&amp;gt;
        &amp;lt;activity
            android:name=&quot;.MainActivity&quot;
            android:exported=&quot;true&quot;&amp;gt;
            &amp;lt;intent-filter&amp;gt;
                &amp;lt;action android:name=&quot;android.intent.action.MAIN&quot; /&amp;gt;

                &amp;lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&amp;gt;
            &amp;lt;/intent-filter&amp;gt;
        &amp;lt;/activity&amp;gt;
    &amp;lt;/application&amp;gt;

&amp;lt;/manifest&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Android</category>
      <author>mscha</author>
      <guid isPermaLink="true">https://mscha.tistory.com/238</guid>
      <comments>https://mscha.tistory.com/238#entry238comment</comments>
      <pubDate>Thu, 21 Jul 2022 17:30:05 +0900</pubDate>
    </item>
    <item>
      <title>[Android] 카메라 / 앨범 처리</title>
      <link>https://mscha.tistory.com/237</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;build.gradle&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드를 추가합니다.&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;dependencies {

    implementation 'commons-io:commons-io:2.4'
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;res/xml 경로&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fileprovider.xml 파일을 생성합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;218&quot; data-origin-height=&quot;185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I7y8f/btrHOcyX21x/ttLE1sT1e6kKykNXzCgzLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I7y8f/btrHOcyX21x/ttLE1sT1e6kKykNXzCgzLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I7y8f/btrHOcyX21x/ttLE1sT1e6kKykNXzCgzLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI7y8f%2FbtrHOcyX21x%2FttLE1sT1e6kKykNXzCgzLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;218&quot; height=&quot;185&quot; data-origin-width=&quot;218&quot; data-origin-height=&quot;185&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;fileprovider.xml&lt;/h4&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;paths&amp;gt;
    &amp;lt;root-path
        name=&quot;root&quot;
        path=&quot;.&quot; /&amp;gt;

    &amp;lt;cache-path
        name=&quot;cache&quot;
        path=&quot;.&quot; /&amp;gt; &amp;lt;!--Context.getCacheDir() 내부 저장소--&amp;gt;
    &amp;lt;files-path
        name=&quot;files&quot;
        path=&quot;.&quot; /&amp;gt; &amp;lt;!--Context.getFilesDir() 내부 저장소--&amp;gt;

    &amp;lt;external-path
        name=&quot;external&quot;
        path=&quot;.&quot;/&amp;gt;  &amp;lt;!--  Environment.getExternalStorageDirectory() 외부 저장소--&amp;gt;
    &amp;lt;external-cache-path
        name=&quot;external-cache&quot;
        path=&quot;.&quot;/&amp;gt; &amp;lt;!--  Context.getExternalCacheDir() 외부 저장소--&amp;gt;
    &amp;lt;external-files-path
        name=&quot;images&quot;
        path=&quot;Pictures&quot; /&amp;gt; &amp;lt;!--  Context.getExternalFilesDir() 외부 저장소--&amp;gt;
&amp;lt;/paths&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;AndroidMenifest.xml&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드들을 추가해줍니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;uses-permission android:name=&quot;android.permission.READ_EXTERNAL_STORAGE&quot;/&amp;gt;
&amp;lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot;/&amp;gt;
&amp;lt;uses-permission android:name=&quot;android.permission.CAMERA&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;&amp;lt;application
    android:requestLegacyExternalStorage=&quot;true&quot;
    &amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;&amp;lt;provider
    android:authorities=&quot;패키지명.fileprovider&quot;
    android:name=&quot;androidx.core.content.FileProvider&quot;
    android:exported=&quot;false&quot;
    android:grantUriPermissions=&quot;true&quot;&amp;gt;
    &amp;lt;meta-data
        android:name=&quot;android.support.FILE_PROVIDER_PATHS&quot;
        android:resource=&quot;@xml/fileprovider&quot;/&amp;gt;
&amp;lt;/provider&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;예시&lt;/h4&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    package=&quot;com.fullspringwater.camera&quot;&amp;gt;

    &amp;lt;uses-permission android:name=&quot;android.permission.READ_EXTERNAL_STORAGE&quot;/&amp;gt;
    &amp;lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot;/&amp;gt;
    &amp;lt;uses-permission android:name=&quot;android.permission.CAMERA&quot;/&amp;gt;


    &amp;lt;application
        android:requestLegacyExternalStorage=&quot;true&quot;
        android:allowBackup=&quot;true&quot;
        android:dataExtractionRules=&quot;@xml/data_extraction_rules&quot;
        android:fullBackupContent=&quot;@xml/backup_rules&quot;
        android:icon=&quot;@mipmap/ic_launcher&quot;
        android:label=&quot;@string/app_name&quot;
        android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;
        android:supportsRtl=&quot;true&quot;
        android:theme=&quot;@style/Theme.Camera&quot;
        tools:targetApi=&quot;31&quot;&amp;gt;

        &amp;lt;provider
            android:authorities=&quot;com.fullspringwater.camera.fileprovider&quot;
            android:name=&quot;androidx.core.content.FileProvider&quot;
            android:exported=&quot;false&quot;
            android:grantUriPermissions=&quot;true&quot;&amp;gt;
            &amp;lt;meta-data
                android:name=&quot;android.support.FILE_PROVIDER_PATHS&quot;
                android:resource=&quot;@xml/fileprovider&quot;/&amp;gt;
        &amp;lt;/provider&amp;gt;

        &amp;lt;activity
            android:name=&quot;.MainActivity&quot;
            android:exported=&quot;true&quot;&amp;gt;
            &amp;lt;intent-filter&amp;gt;
                &amp;lt;action android:name=&quot;android.intent.action.MAIN&quot; /&amp;gt;

                &amp;lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&amp;gt;
            &amp;lt;/intent-filter&amp;gt;
        &amp;lt;/activity&amp;gt;
    &amp;lt;/application&amp;gt;

&amp;lt;/manifest&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼을 누르면 카메라로 사진을 찍을 것인지,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앨범에서 사진을 가져올 것인지를 선택하는 기능을 구현 해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;activity_main.xml&lt;/h4&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;androidx.constraintlayout.widget.ConstraintLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.MainActivity&quot;&amp;gt;


    &amp;lt;LinearLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:orientation=&quot;vertical&quot;
        app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
        app:layout_constraintEnd_toEndOf=&quot;parent&quot;
        app:layout_constraintStart_toStartOf=&quot;parent&quot;
        app:layout_constraintTop_toTopOf=&quot;parent&quot;&amp;gt;

        &amp;lt;Button
            android:id=&quot;@+id/button&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_marginLeft=&quot;10dp&quot;
            android:layout_marginTop=&quot;30dp&quot;
            android:layout_marginRight=&quot;10dp&quot;
            android:layout_marginBottom=&quot;30dp&quot;
            android:text=&quot;사진&quot;
            android:textSize=&quot;30sp&quot; /&amp;gt;

        &amp;lt;ImageView
            android:id=&quot;@+id/imageView&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            app:srcCompat=&quot;@drawable/ic_launcher_foreground&quot; /&amp;gt;
    &amp;lt;/LinearLayout&amp;gt;
&amp;lt;/androidx.constraintlayout.widget.ConstraintLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;MainActivity.java&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 되어있는 코드 부분은 본인의 패키지명으로 바꿔주셔야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1658383140291&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;com.fullspringwater.camera.fileprovider&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1658383178948&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;패키지명.fileprovider&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;package com.fullspringwater.camera;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity {

    Button button;
    ImageView imageView;
    private File photoFile;

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

        button = findViewById(R.id.button);
        imageView = findViewById(R.id.imageView);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 버튼을 누르면 카메라와 앨범 어떤 것을 선택할 것인지
                // 알러트 다이얼로그를 띄운다.
                showDialog();
                // 카메라를 선택하면, 사진찍는 것으로,
                // 앨범을 선택하면, 앨범에서 사진 선택할 수 있도록 하고

                // 그 결과는 이미지 뷰에 보여주도록 개발.

            }
        });

    }

    // 알러트 다이얼로그 띄우는 함수
    void showDialog(){
        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
        builder.setTitle(R.string.alert_title);
        builder.setItems(R.array.alert_photo, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                if(i == 0){
                    // 사진 찍는 코드 실행
                    camera();
                }else{
                    // 앨범에서 사진 가져오는 코드 실행
                    album();
                }
            }
        });
        AlertDialog alertDialog = builder.create();
        alertDialog.show();
    }
    
    private void camera(){
        int permissionCheck = ContextCompat.checkSelfPermission(
                MainActivity.this, Manifest.permission.CAMERA);

        if(permissionCheck != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.CAMERA} ,
                    1000);
            Toast.makeText(MainActivity.this, &quot;카메라 권한 필요합니다.&quot;,
                    Toast.LENGTH_SHORT).show();
            return;
        } else {
            Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            if(i.resolveActivity(MainActivity.this.getPackageManager())  != null  ){

                // 사진의 파일명을 만들기
                String fileName = new SimpleDateFormat(&quot;yyyyMMdd_HHmmss&quot;).format(new Date());
                photoFile = getPhotoFile(fileName);

                Uri fileProvider = FileProvider.getUriForFile(MainActivity.this,
                        &quot;com.fullspringwater.camera.fileprovider&quot;, photoFile);
                i.putExtra(MediaStore.EXTRA_OUTPUT, fileProvider);
                startActivityForResult(i, 100);

            } else{
                Toast.makeText(MainActivity.this, &quot;이폰에는 카메라 앱이 없습니다.&quot;,
                        Toast.LENGTH_SHORT).show();
            }
        }


    }
    private File getPhotoFile(String fileName) {
        File storageDirectory = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        try{
            return File.createTempFile(fileName, &quot;.jpg&quot;, storageDirectory);
        }catch (IOException e){
            e.printStackTrace();
            return null;
        }
    }

    private void album(){
        if(checkPermission()){
            displayFileChoose();
        }else{
            requestPermission();
        }
    }
    private void requestPermission() {
        if(ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)){
            Toast.makeText(MainActivity.this, &quot;권한 수락이 필요합니다.&quot;,
                    Toast.LENGTH_SHORT).show();
        }else{
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 500);
        }
    }

    private boolean checkPermission(){
        int result = ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if(result == PackageManager.PERMISSION_DENIED){
            return false;
        }else{
            return true;
        }
    }

    private void displayFileChoose() {
        Intent i = new Intent();
        i.setType(&quot;image/*&quot;);
        i.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(Intent.createChooser(i, &quot;SELECT IMAGE&quot;), 300);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 1000: {
                if (grantResults.length &amp;gt; 0 &amp;amp;&amp;amp; grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(MainActivity.this, &quot;권한 허가 되었음&quot;,
                            Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this, &quot;아직 승인하지 않았음&quot;,
                            Toast.LENGTH_SHORT).show();
                }
                break;
            }
            case 500: {
                if (grantResults.length &amp;gt; 0 &amp;amp;&amp;amp; grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(MainActivity.this, &quot;권한 허가 되었음&quot;,
                            Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this, &quot;아직 승인하지 않았음&quot;,
                            Toast.LENGTH_SHORT).show();
                }

            }

        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if(requestCode == 100 &amp;amp;&amp;amp; resultCode == RESULT_OK){

            Bitmap photo = BitmapFactory.decodeFile(photoFile.getAbsolutePath());

            ExifInterface exif = null;
            try {
                exif = new ExifInterface(photoFile.getAbsolutePath());
            } catch (IOException e) {
                e.printStackTrace();
            }
            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_UNDEFINED);
            photo = rotateBitmap(photo, orientation);

            // 압축시킨다. 해상도 낮춰서
            OutputStream os;
            try {
                os = new FileOutputStream(photoFile);
                photo.compress(Bitmap.CompressFormat.JPEG, 50, os);
                os.flush();
                os.close();
            } catch (Exception e) {
                Log.e(getClass().getSimpleName(), &quot;Error writing bitmap&quot;, e);
            }

            photo = BitmapFactory.decodeFile(photoFile.getAbsolutePath());

            imageView.setImageBitmap(photo);
            imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

            // 네트워크로 데이터 보낸다.


        }else if(requestCode == 300 &amp;amp;&amp;amp; resultCode == RESULT_OK &amp;amp;&amp;amp; data != null &amp;amp;&amp;amp;
                data.getData() != null){

            Uri albumUri = data.getData( );
            String fileName = getFileName( albumUri );
            try {

                ParcelFileDescriptor parcelFileDescriptor = getContentResolver( ).openFileDescriptor( albumUri, &quot;r&quot; );
                if ( parcelFileDescriptor == null ) return;
                FileInputStream inputStream = new FileInputStream( parcelFileDescriptor.getFileDescriptor( ) );
                photoFile = new File( this.getCacheDir( ), fileName );
                FileOutputStream outputStream = new FileOutputStream( photoFile );
                IOUtils.copy( inputStream, outputStream );

//                //임시파일 생성
//                File file = createImgCacheFile( );
//                String cacheFilePath = file.getAbsolutePath( );


                // 압축시킨다. 해상도 낮춰서
                Bitmap photo = BitmapFactory.decodeFile(photoFile.getAbsolutePath());
                OutputStream os;
                try {
                    os = new FileOutputStream(photoFile);
                    photo.compress(Bitmap.CompressFormat.JPEG, 60, os);
                    os.flush();
                    os.close();
                } catch (Exception e) {
                    Log.e(getClass().getSimpleName(), &quot;Error writing bitmap&quot;, e);
                }

                imageView.setImageBitmap(photo);
                imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

//                imageView.setImageBitmap( getBitmapAlbum( imageView, albumUri ) );

            } catch ( Exception e ) {
                e.printStackTrace( );
            }
            // 네트워크로 보낸다.
        }
        super.onActivityResult(requestCode, resultCode, data);
    }


    public static Bitmap rotateBitmap(Bitmap bitmap, int orientation) {

        Matrix matrix = new Matrix();
        switch (orientation) {
            case ExifInterface.ORIENTATION_NORMAL:
                return bitmap;
            case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
                matrix.setScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                matrix.setRotate(180);
                break;
            case ExifInterface.ORIENTATION_FLIP_VERTICAL:
                matrix.setRotate(180);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_TRANSPOSE:
                matrix.setRotate(90);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_90:
                matrix.setRotate(90);
                break;
            case ExifInterface.ORIENTATION_TRANSVERSE:
                matrix.setRotate(-90);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                matrix.setRotate(-90);
                break;
            default:
                return bitmap;
        }
        try {
            Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            bitmap.recycle();
            return bmRotated;
        }
        catch (OutOfMemoryError e) {
            e.printStackTrace();
            return null;
        }
    }

    //앨범에서 선택한 사진이름 가져오기
    public String getFileName( Uri uri ) {
        Cursor cursor = getContentResolver( ).query( uri, null, null, null, null );
        try {
            if ( cursor == null ) return null;
            cursor.moveToFirst( );
            @SuppressLint(&quot;Range&quot;) String fileName = cursor.getString( cursor.getColumnIndex( OpenableColumns.DISPLAY_NAME ) );
            cursor.close( );
            return fileName;

        } catch ( Exception e ) {
            e.printStackTrace( );
            cursor.close( );
            return null;
        }
    }

    //이미지뷰에 뿌려질 앨범 비트맵 반환
    public Bitmap getBitmapAlbum( View targetView, Uri uri ) {
        try {
            ParcelFileDescriptor parcelFileDescriptor = getContentResolver( ).openFileDescriptor( uri, &quot;r&quot; );
            if ( parcelFileDescriptor == null ) return null;
            FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor( );
            if ( fileDescriptor == null ) return null;

            int targetW = targetView.getWidth( );
            int targetH = targetView.getHeight( );

            BitmapFactory.Options options = new BitmapFactory.Options( );
            options.inJustDecodeBounds = true;

            BitmapFactory.decodeFileDescriptor( fileDescriptor, null, options );

            int photoW = options.outWidth;
            int photoH = options.outHeight;

            int scaleFactor = Math.min( photoW / targetW, photoH / targetH );
            if ( scaleFactor &amp;gt;= 8 ) {
                options.inSampleSize = 8;
            } else if ( scaleFactor &amp;gt;= 4 ) {
                options.inSampleSize = 4;
            } else {
                options.inSampleSize = 2;
            }
            options.inJustDecodeBounds = false;

            Bitmap reSizeBit = BitmapFactory.decodeFileDescriptor( fileDescriptor, null, options );

            ExifInterface exifInterface = null;
            try {
                if ( Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.N ) {
                    exifInterface = new ExifInterface( fileDescriptor );
                }
            } catch ( IOException e ) {
                e.printStackTrace( );
            }

            int exifOrientation;
            int exifDegree = 0;

            //사진 회전값 구하기
            if ( exifInterface != null ) {
                exifOrientation = exifInterface.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL );

                if ( exifOrientation == ExifInterface.ORIENTATION_ROTATE_90 ) {
                    exifDegree = 90;
                } else if ( exifOrientation == ExifInterface.ORIENTATION_ROTATE_180 ) {
                    exifDegree = 180;
                } else if ( exifOrientation == ExifInterface.ORIENTATION_ROTATE_270 ) {
                    exifDegree = 270;
                }
            }

            parcelFileDescriptor.close( );
            Matrix matrix = new Matrix( );
            matrix.postRotate( exifDegree );

            Bitmap reSizeExifBitmap = Bitmap.createBitmap( reSizeBit, 0, 0, reSizeBit.getWidth( ), reSizeBit.getHeight( ), matrix, true );
            return reSizeExifBitmap;

        } catch ( Exception e ) {
            e.printStackTrace( );
            return null;
        }


    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIOeUr/btrHQpK4Iwt/2baAwUvqgVXBOpa07uCNR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIOeUr/btrHQpK4Iwt/2baAwUvqgVXBOpa07uCNR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIOeUr/btrHQpK4Iwt/2baAwUvqgVXBOpa07uCNR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIOeUr%2FbtrHQpK4Iwt%2F2baAwUvqgVXBOpa07uCNR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;633&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_01.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOwRK5/btrHSASQLXF/quf7lpO2KXGsORsug0eaB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOwRK5/btrHSASQLXF/quf7lpO2KXGsORsug0eaB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOwRK5/btrHSASQLXF/quf7lpO2KXGsORsug0eaB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOwRK5%2FbtrHSASQLXF%2Fquf7lpO2KXGsORsug0eaB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;633&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_01.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_02.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FNoWi/btrHTEApJdq/xkQU9pgDdHzv1K0wnbNiCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FNoWi/btrHTEApJdq/xkQU9pgDdHzv1K0wnbNiCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FNoWi/btrHTEApJdq/xkQU9pgDdHzv1K0wnbNiCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFNoWi%2FbtrHTEApJdq%2FxkQU9pgDdHzv1K0wnbNiCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;633&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_02.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_03.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvejak/btrHQpqH3Iw/8vcRGIhPJX1FkgApp0w0Ok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvejak/btrHQpqH3Iw/8vcRGIhPJX1FkgApp0w0Ok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvejak/btrHQpqH3Iw/8vcRGIhPJX1FkgApp0w0Ok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbvejak%2FbtrHQpqH3Iw%2F8vcRGIhPJX1FkgApp0w0Ok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;633&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_03.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_04.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxUVhH/btrHTqCpkI7/OC0uqTupDg3hJJrQn54b6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxUVhH/btrHTqCpkI7/OC0uqTupDg3hJJrQn54b6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxUVhH/btrHTqCpkI7/OC0uqTupDg3hJJrQn54b6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxUVhH%2FbtrHTqCpkI7%2FOC0uqTupDg3hJJrQn54b6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;633&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_04.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_05.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dx50sA/btrHOSG982K/4P7ISuoKAGqSLYjFrM3UUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dx50sA/btrHOSG982K/4P7ISuoKAGqSLYjFrM3UUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dx50sA/btrHOSG982K/4P7ISuoKAGqSLYjFrM3UUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdx50sA%2FbtrHOSG982K%2F4P7ISuoKAGqSLYjFrM3UUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;633&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_05.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_06.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXnv4j/btrHROqgdfN/HsokAG0FvG7mp20hArfuv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXnv4j/btrHROqgdfN/HsokAG0FvG7mp20hArfuv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXnv4j/btrHROqgdfN/HsokAG0FvG7mp20hArfuv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXnv4j%2FbtrHROqgdfN%2FHsokAG0FvG7mp20hArfuv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;633&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_06.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_07.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k2FUc/btrHPgnxqD3/7tkYyODY8HMv2KYiq5kiAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k2FUc/btrHPgnxqD3/7tkYyODY8HMv2KYiq5kiAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k2FUc/btrHPgnxqD3/7tkYyODY8HMv2KYiq5kiAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk2FUc%2FbtrHPgnxqD3%2F7tkYyODY8HMv2KYiq5kiAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;633&quot; data-filename=&quot;edited_KakaoTalk_20220721_145342280_07.jpg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Android</category>
      <author>mscha</author>
      <guid isPermaLink="true">https://mscha.tistory.com/237</guid>
      <comments>https://mscha.tistory.com/237#entry237comment</comments>
      <pubDate>Thu, 21 Jul 2022 14:56:13 +0900</pubDate>
    </item>
    <item>
      <title>[Android] 리사이클러뷰 스크롤 위치 찾기, 페이징 처리</title>
      <link>https://mscha.tistory.com/236</link>
      <description>&lt;pre id=&quot;code_1658307583041&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));

// 리사이클러뷰가 맨 밑까지 갔는지 알 수 있는 방법.
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
	@Override
	public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
		super.onScrollStateChanged(recyclerView, newState);
	}

	@Override
	public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
		super.onScrolled(recyclerView, dx, dy);
				
		// 리사이클러뷰 가장 마지막 index
		int lastPosition = ((LinearLayoutManager) recyclerView.getLayoutManager())
			.findLastCompletelyVisibleItemPosition();
		// 받아온 리사이클러 뷰 카운트
		int totalCount = recyclerView.getAdapter().getItemCount();

		// 스크롤을 맨 끝까지 한 것!
		if(lastPosition == totalCount -1){
			// 이곳에 스크롤이 맨 끝에 왔을 경우
			// 행동할 코드 입력
		}
	}
});&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Android</category>
      <author>mscha</author>
      <guid isPermaLink="true">https://mscha.tistory.com/236</guid>
      <comments>https://mscha.tistory.com/236#entry236comment</comments>
      <pubDate>Wed, 20 Jul 2022 18:01:55 +0900</pubDate>
    </item>
    <item>
      <title>[Android] 이미지 처리를 위한 Glide 라이브러리 사용법</title>
      <link>https://mscha.tistory.com/235</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크를 통해 이미지를 받아서 이미지뷰에 이미지를 설정할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 Glide를 이용하면 편리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;build.gradle에 아래 코드를 추가해줍니다.&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;dependencies {
    
    implementation 'com.github.bumptech.glide:glide:4.13.2'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AndroidMenifest.xml&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터넷접속 권한을 추가해줍니다.&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;&amp;lt;uses-permission android:name=&quot;android.permission.INTERNET&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 예제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 이미지 url의 끝이 jpg와 같은 이미지 확장자가 아닌 경우&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;//글라이드 라이브러리를 이용해서, 이미지뷰에 표시한다.
GlideUrl url = new GlideUrl(getUrl,
        new LazyHeaders.Builder().addHeader(&quot;User-Agent&quot;, &quot;Android&quot;).build());
Glide.with(MainActivity.this).load(url).into(imageView);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. url의 끝이 이미지 확장자인 경우&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658307190696&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//글라이드 라이브러리를 이용해서, 이미지뷰에 표시한다.
Glide.with(MainActivity.this).load(url).into(imageView);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.overide : 이미지의 크기를 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.placeholder : 이미지를 받아오기 전에 디폴트 이미지를 설정할 수 있다.&lt;/p&gt;</description>
      <category>Android</category>
      <author>mscha</author>
      <guid isPermaLink="true">https://mscha.tistory.com/235</guid>
      <comments>https://mscha.tistory.com/235#entry235comment</comments>
      <pubDate>Wed, 20 Jul 2022 17:55:30 +0900</pubDate>
    </item>
  </channel>
</rss>