안드로이드 5기 2017년 강의 정리 4 (오준석의 생존코딩)
https://www.youtube.com/watch?v=qCyHkVRZnXo&list=PLxTmPHxRH3VWSF7kMcsIaTglWUJZpWeQ9&index=56
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki
MyFirstAndroidApp5ki-master.zip
29일차 Notification
30일차 CoordinatorLayout
30일차 암시적 인텐트로 이미지 가져오기
31일차 메모장 아이템 클릭시 화면전환 효과 하던 중
32일차 Service
32일차 메서드 리팩토링, NavigationDrawer
33일차 런타임 퍼미션 체크
33일차 FileZilla, SublimeText 설치
34일차 PHP 진화된 Insert처리
35일차 Realm
29일차 Notification
# Broadcasts overview
https://developer.android.com/guide/components/broadcasts#java
# Notification
https://developer.android.com/guide/topics/ui/notifiers/notifications
# BroadcastReceiverActivity.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/activities/BroadcastReceiverActivity.java
# MyLocalReceiver.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/receiver/MyLocalReceiver.java
# activity_broadcast_receiver.xml
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/activity_broadcast_receiver.xml
/**
* 매니페스트에 리시버를 등록 하지 않는다
* onStart(), onStop() 코드로 리시버 등록, 해제한다
*/
public class BroadcastReceiverActivity extends AppCompatActivity {
private BroadcastReceiver mReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast_receiver);
}
@Override
protected void onStart() {
super.onStart();
mReceiver = new MyLocalReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_LOW);
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
filter.addAction("com.example.myapplication.broadcast.ACTION_TEST");
// 리시버 등록
registerReceiver(mReceiver, filter);
}
@Override
protected void onStop() {
super.onStop();
// 리시버 해제
unregisterReceiver(mReceiver);
}
public void onClick(View view) {
// 나만의 액션을 쏘기
Intent intent = new Intent("com.example.myapplication.broadcast.ACTION_TEST");
// 순서없는
sendBroadcast(intent);
// 순서있는
// sendOrderedBroadcast()
}
}
public class MyLocalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BATTERY_LOW)) {
Toast.makeText(context, "로컬 브로드캐스트 리시버다!!!", Toast.LENGTH_LONG).show();
} else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
Toast.makeText(context, "전원이 뽑혔습니다", Toast.LENGTH_SHORT).show();
} else if (intent.getAction().equals("com.example.myapplication.broadcast.ACTION_TEST")) {
Toast.makeText(context, "나만의 액션 받기 성공!!", Toast.LENGTH_SHORT).show();
showNotification(context);
}
}
private void showNotification(Context context) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setContentTitle("나만의 알림");
builder.setContentText("나만의 텍스트");
builder.setSmallIcon(R.mipmap.ic_launcher);
Bitmap bitmap = BitmapFactory.decodeResource(
context.getResources(), R.mipmap.ic_launcher);
builder.setLargeIcon(bitmap);
// 알림을 클릭하면 수행될 인텐트
Intent resultIntent = new Intent(context, BroadcastReceiverActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context,
0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pendingIntent);
// 클릭하면 날리기
builder.setAutoCancel(true);
// 색상
builder.setColor(Color.YELLOW);
// 기본 알림음
Uri uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
builder.setSound(uri);
// 진동
builder.setVibrate(new long[]{100, 200, 300});
// 액션
builder.addAction(R.mipmap.ic_launcher, "확인", pendingIntent);
builder.addAction(R.mipmap.ic_launcher, "취소", pendingIntent);
// 알림 표시
NotificationManagerCompat manager = NotificationManagerCompat.from(context);
manager.notify(0, builder.build());
}
}
30일차 CoordinatorLayout
#Scrolling Techniques
https://material.io/archive/guidelines/patterns/scrolling-techniques.html
# Activity 추가 -> Scrolling Activity
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ScrollingActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/app_bar_height"
android:fitsSystemWindows="true"
android:theme="@style/Theme.MyFirstAppApplication.AppBarOverlay">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorAccent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:toolbarId="@+id/toolbar">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_collapseMode="parallax" // 축소될 때 이미지 뷰가 자연스럽게 사라짐 (pin 이면 그냥 사라짐)
app:layout_collapseParallaxMultiplier="0.3" // 이미지뷰의 0.3 위치만큼 위로 올라감
android:background="@drawable/ic_launcher_foreground" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/Theme.MyFirstAppApplication.PopupOverlay" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_scrolling" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
app:layout_anchor="@id/app_bar"
app:layout_anchorGravity="bottom|end"
app:srcCompat="@android:drawable/ic_dialog_email" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
30일차 암시적 인텐트로 이미지 가져오기
# 갤러리에서 이미지 가져오기
# activity_scrolling.xml
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/activity_scrolling.xml
# content_scrolling.xml
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/content_scrolling.xml
// 이미지 썸네일 얻기 Glide.with(this).loadFromMediaStore(uri).thumbnail(0.2f).into(mImageView); Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri); ThumbnailUtils.extractThumbnail(bitmap, 100, 100);
public class ScrollingActivity extends AppCompatActivity {
private ImageView mImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scrolling);
mImageView = (ImageView) findViewById(R.id.appbar_image);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
public void onImageClick(View view) {
// 그림 줘
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, 1000);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1000 && resultCode == RESULT_OK && data != null) {
// 그림이 정상적으로 선택되었을 때
// 사진 경로
Uri uri = data.getData();
// 라이브러리
Glide.with(this).loadFromMediaStore(uri).into(mImageView);
// 이미지뷰에 bitmap 설정
// 사진을 bitmap으로 얻기
// 그냥
// Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
// mImageView.setImageBitmap(bitmap);
}
}
}
31일차 메모장 아이템 클릭시 화면전환 효과 하던 중
# Start an activity using an animation
https://developer.android.com/training/transitions/start-activity#java
# MemoActivity.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/activities/MemoActivity.java
# Memo2Activity.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/activities/Memo2Activity.java
# Sample Code : ActivitySceneTransitionBasic
https://github.com/android/animation/tree/main/ActivitySceneTransitionBasic
public class MainActivity extends AppCompatActivity {
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.imageView);
findViewById(R.id.button).setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(
MainActivity.this,
new Pair<>(imageView, DetailActivity.VIEW_NAME_HEADER_IMAGE));
ActivityCompat.startActivity(MainActivity.this, intent, activityOptions.toBundle());
});
}
}
public class DetailActivity extends AppCompatActivity {
public static final String VIEW_NAME_HEADER_IMAGE = "detail:header:image";
private ImageView mHeaderImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.details);
mHeaderImageView = findViewById(R.id.imageview_header);
ViewCompat.setTransitionName(mHeaderImageView, VIEW_NAME_HEADER_IMAGE);
mHeaderImageView.setImageResource(R.drawable.blizzard);
}
}
# activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:text="버튼"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/cloudy" />
</LinearLayout>
# details.xml
<ImageView
android:id="@+id/imageview_header"
android:layout_width="100dp"
android:layout_height="100dp"
android:scaleType="centerCrop" />
32일차 Service
# Services overview (android developers)
https://developer.android.com/guide/components/services#java
# Bound services overview (android developers)
https://developer.android.com/guide/components/bound-services#java
# MyIntentService.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/services/MyIntentService.java
# MyService.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/services/MyService.java
# ServiceActivity.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/activities/ServiceActivity.java
public class MyIntentService extends IntentService {
public static final String TAG = MyIntentService.class.getSimpleName();
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent.getAction().equals("play")) {
Log.d(TAG, "play");
String path = intent.getStringExtra("path");
} else {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
Log.d(TAG, "onHandleIntent: " + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class MyService extends Service {
public static final String TAG = MyService.class.getSimpleName();
public MyService() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
Log.d(TAG, "onHandleIntent: " + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IBinder mBinder = new MyBinder();
public class MyBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
public long getTime() {
return new Random().nextLong();
}
}
public class ServiceActivity extends AppCompatActivity {
private MyService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service);
}
public void onStartIntentService(View view) {
// 1. 순차적으로 실행 된다
// 2. Worker 스레드로 실행된다
Intent intent = new Intent(this, MyIntentService.class);
intent.setAction("play");
intent.putExtra("path", "file://dfadsf");
startService(intent);
}
public void onStartService(View view) {
// 1. Main스레드에서 돈다. 그래서 Thread를 별도 생성해서 실행해야 한다
// 2. 병렬 실행 가능
Intent intent = new Intent(this, MyService.class);
startService(intent);
}
public void onBindService(View view) {
Intent intent = new Intent(this, MyService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
public void getNumber(View view) {
if (mBound) {
Toast.makeText(this, "" + mService.getTime(), Toast.LENGTH_SHORT).show();
}
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 바인드 성공
MyService.MyBinder binder = (MyService.MyBinder) service;
mService = binder.getService();
Toast.makeText(ServiceActivity.this, "바인드 성공", Toast.LENGTH_SHORT).show();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 강제 종료시에 호출
mBound = false;
}
};
@Override
protected void onDestroy() {
super.onDestroy();
// 바인딩 끊기
if (mBound) {
unbindService(mConnection);
}
}
}
32일차 메서드 리팩토링, NavigationDrawer
# Update UI components with NavigationUI
https://developer.android.com/guide/navigation/navigation-ui
33일차 런타임 퍼미션 체크
# Request App Permissions
https://developer.android.com/training/permissions/requesting#java
# GalleryActivity.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/activities/GalleryActivity.java
public class GalleryActivity extends AppCompatActivity implements GalleryFragment.OnFragmentInteractionListener {
private Fragment mFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
mFragment = getSupportFragmentManager().findFragmentById(R.id.fragment);
}
@Override
public void onFragmentInteraction(Uri uri) {
}
// onRequestPermissionsResult 는 액티비티에서 작성해야함.
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
mFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
public class GalleryFragment extends Fragment {
private OnFragmentInteractionListener mListener;
private GridView mGridView;
public GalleryFragment() {
// Required empty public constructor
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
// 리스너 연결
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Bundle 받을꺼야
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 뷰 가져오기
return inflater.inflate(R.layout.fragment_gallery, container, false);
}
// 뷰 가져온 이후 할 것
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// 뷰
mGridView = (GridView) view.findViewById(R.id.grid_view);
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
// 설명을 보여줄 것인가
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
Manifest.permission.READ_EXTERNAL_STORAGE)) {
// 사용자 응답을 기다리는 설명을 비동기로 보여주기
// 권한 체크를 안 하면 이 기능을 사용할 수 없다고 어필하고
// 다이얼로그 표시
// 이 권한을 수락하지 않으면 이 기능을 사용할 수 없습니다
// 권한을 설정하시려면 설정 > 애플리케이션 > 앱이름 가서 설정하세요
// 다시 권한 요청
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
1000);
} else {
// No explanation needed, we can request the permission.
// 권한을 요청
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
1000);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
// 이미 권한이 있을 때
getPicture();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1000: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
// 승인 됨
Toast.makeText(getActivity(), "권한 승인됨", Toast.LENGTH_SHORT).show();
getPicture();
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
// 앱을 종료합니다
Toast.makeText(getActivity(), "권한 거부됨", Toast.LENGTH_SHORT).show();
getActivity().finish();
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
private void getPicture() {
// 사진 정보
// 미디어(사진, 동영상, 음악) media db
// provider로 media db 정보를 가져와야 됨
Cursor cursor = getActivity().getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null,
null,
null,
null
);
// 사진을 뿌릴 어댑터
MyCursorAdapter adapter = new MyCursorAdapter(getActivity(), cursor);
mGridView.setAdapter(adapter);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
private static class MyCursorAdapter extends CursorAdapter {
public MyCursorAdapter(Context context, Cursor c) {
super(context, c, false);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View convertView = LayoutInflater.from(context)
.inflate(R.layout.item_gallery, parent, false);
ViewHolder viewHolder = new ViewHolder();
viewHolder.imageView = (ImageView) convertView.findViewById(R.id.image_view);
convertView.setTag(viewHolder);
return convertView;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
Glide.with(context).load(path).into(viewHolder.imageView);
}
}
private static class ViewHolder {
ImageView imageView;
}
}
33일차 FileZilla, SublimeText 설치
34일차 PHP 진화된 Insert처리
# ResultModel.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/login/ResultModel.java
# RetrofitUtil.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/login/RetrofitUtil.java
# UserApi.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/login/UserApi.java
public class LoginActivity extends AppCompatActivity implements View.OnClickListener {
// UI references.
private AutoCompleteTextView mEmailView;
private EditText mPasswordView;
private View mProgressView;
private View mLoginFormView;
private UserApi mUserApi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// Set up the login form.
mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
mPasswordView = (EditText) findViewById(R.id.password);
Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
mLoginFormView = findViewById(R.id.login_form);
mProgressView = findViewById(R.id.login_progress);
mUserApi = new RetrofitUtil().getUserApi();
mEmailSignInButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Call<ResultModel> call = mUserApi.login(mEmailView.getText().toString(),
mPasswordView.getText().toString());
// 비동기 네트워크 처리
call.enqueue(new Callback<ResultModel>() {
@Override
public void onResponse(Call<ResultModel> call, Response<ResultModel> response) {
// 정상 결과
ResultModel result = response.body();
if (result.getResult().equals("ok")) {
// 성공
startActivity(new Intent(LoginActivity.this, MemoActivity.class));
} else {
Toast.makeText(LoginActivity.this, "실패", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<ResultModel> call, Throwable t) {
// 네트워크 문제
Toast.makeText(LoginActivity.this, "네트워크 연결 실패", Toast.LENGTH_SHORT).show();
}
});
}
}
public class RetrofitUtil {
private Retrofit mRetrofit;
private UserApi mUserApi;
public RetrofitUtil() {
mRetrofit = new Retrofit.Builder()
.baseUrl(UserApi.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
mUserApi = mRetrofit.create(UserApi.class);
}
public UserApi getUserApi() {
return mUserApi;
}
}
public interface UserApi {
String BASE_URL = "http://suwonsmartapp.iptime.org/test/junsuk2/";
// 로그인
@GET("login.php")
Call<ResultModel> login(@Query("email") String email,
@Query("password") String password);
// 회원가입
@GET("insert.php")
Call<ResultModel> signUp();
}
35일차 Realm
# realm.io
https://realm.io/kr/docs/java/latest/
# sqlite (android developer)
https://developer.android.com/training/data-storage/sqlite#java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/activities/RealmExamActivity.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/models/User.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/MyApplication.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/activity_reaml_exam.xml
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/AndroidManifest.xml
# AndroidManifest.xml
<application
android:name=".MyApplication"
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Realm.init(this);
RealmConfiguration config = new RealmConfiguration.Builder().build();
Realm.setDefaultConfiguration(config);
}
}
# 프로젝트 수준 build.gradle
buildscript {
dependencies {
classpath "io.realm:realm-gradle-plugin:3.5.0"
}
public class User extends RealmObject {
private String email;
private String password;
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;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("User{");
sb.append("email='").append(email).append('\'');
sb.append(", password='").append(password).append('\'');
sb.append('}');
return sb.toString();
}
}
# app 수준 build.gradle
plugins {
id 'realm-android'
}
public class RealmExamActivity extends AppCompatActivity implements RealmChangeListener<Realm> {
private EditText mEmail;
private EditText mPassword;
private EditText mNewPassword;
private TextView mResultText;
private Realm mRealm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_realm_exam);
mEmail = (EditText) findViewById(R.id.email_edit);
mPassword = (EditText) findViewById(R.id.password_edit);
mNewPassword = (EditText) findViewById(R.id.new_password_edit);
mResultText = (TextView) findViewById(R.id.result_text);
mRealm = Realm.getDefaultInstance();
mRealm.addChangeListener(this);
showResult();
}
@Override
protected void onDestroy() {
super.onDestroy();
mRealm.removeAllChangeListeners();
mRealm.close();
}
public void SignIn(View view) {
if (mRealm.where(User.class)
.equalTo("email", mEmail.getText().toString())
.equalTo("password", mPassword.getText().toString())
.count() > 0) {
Toast.makeText(this, "로그인 성공", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "로그인 실패", Toast.LENGTH_SHORT).show();
}
}
public void SignUp(View view) {
mRealm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
if (realm.where(User.class)
.equalTo("email", mEmail.getText().toString())
.count() == 0) {
User user = realm.createObject(User.class);
user.setEmail(mEmail.getText().toString());
user.setPassword(mPassword.getText().toString());
}
}
});
}
public void updatePassword(View view) {
mRealm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
User user = realm.where(User.class)
.equalTo("email", mEmail.getText().toString())
.findFirst();
user.setPassword(mNewPassword.getText().toString());
}
});
}
public void deleteAccount(View view) {
mRealm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.where(User.class)
.equalTo("email", mEmail.getText().toString())
.findAll()
.deleteAllFromRealm();
}
});
}
private void showResult() {
RealmResults<User> results = mRealm.where(User.class).findAll();
mResultText.setText(results.toString());
}
@Override
public void onChange(Realm element) {
// DB가 갱싱 될 때 마다 호출
showResult();
}
}
# activity_realm_exam.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/email_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="email"
android:inputType="textEmailAddress" />
<EditText
android:id="@+id/password_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="password"
android:inputType="textPassword" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="SignIn"
android:text="로그인" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="SignUp"
android:text="가입" />
<EditText
android:id="@+id/new_password_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="수정할 비밀번호" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="updatePassword"
android:text="비번 수정" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="deleteAccount"
android:text="탈퇴" />
<TextView
android:id="@+id/result_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp" />
</LinearLayout>