06 May 2019
|
Android
프로젝트 build.gradle
buildscript {
ext.kotlin_version = '1.3.31'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "io.realm:realm-gradle-plugin:5.2.0"
}
}
모듈 build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'realm-android'
...
dependencies {
...
implementation 'io.realm:android-adapters:2.1.1'
}
SnowApplication.kt
import android.app.Application
import android.content.Context
import io.realm.Realm
import io.realm.RealmConfiguration
class SnowApplication : Application() {
companion object {
private var instance: SnowApplication? = null
fun context(): Context {
return instance!!.applicationContext
}
}
init {
instance = this
}
override fun onCreate() {
super.onCreate()
Realm.init(this)
Realm.setDefaultConfiguration(getRealmConfig())
}
private fun getRealmConfig(): RealmConfiguration {
return RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
.build()
}
}
데이터 레코드 정의
open
키워드를 이용해서 상속을 가능하게 해야 하며, RealmObject()
를 상속받아야 합니다.
import android.os.Parcel
import android.os.Parcelable
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
open class RewardDto(
var habitId: Long = 0,
var year: Int = 0, var month: Int = 0, var day: Int = 0,
var percent: Int = 0, var stampType: Int = 0) : RealmObject()
open class HabitDto(
@PrimaryKey var id: Long = 0,
var name: String = "", var seq: Long = 0) : RealmObject()
데이터 생성, 조회, 수정, 삭제
import com.snowdeer.htracker.model.data.HabitDto
import io.realm.Realm
import io.realm.Sort
import io.realm.kotlin.createObject
import io.realm.kotlin.where
interface OnDatabaseEventListener {
fun onDatabaseUpdated()
}
class HabitModelManager {
companion object {
val instance = HabitModelManager()
}
private constructor()
private val realm = Realm.getDefaultInstance()
private var onDatabaseEventListener: OnDatabaseEventListener? = null
fun setOnDatabaseEventListener(l: OnDatabaseEventListener) {
onDatabaseEventListener = l
}
fun notifyDatabaseUpdated() {
onDatabaseEventListener?.onDatabaseUpdated()
}
private fun nextId(): Long {
val maxId = realm.where<HabitDto>().max("id")
if (maxId != null) {
return maxId.toLong() + 1
}
return 0
}
private fun nextSeq(): Long {
val maxSeq = realm.where<HabitDto>().max("seq")
return maxSeq?.toLong()?.plus(1) ?: 0
}
fun getList(): ArrayList<HabitDto> {
val realmResult = realm.where<HabitDto>()
.findAll()
.sort("seq", Sort.DESCENDING)
val list = ArrayList<HabitDto>()
for (item in realmResult) {
list.add(item)
}
return list
}
fun create(name: String) {
realm.beginTransaction()
val item = realm.createObject<HabitDto>(nextId())
item.name = name
item.seq = nextSeq()
realm.commitTransaction()
notifyDatabaseUpdated()
}
fun update(id: Long, name: String, seq: Long) {
realm.beginTransaction()
val item = realm.where<HabitDto>().equalTo("id", id).findFirst()!!
item.name = name
item.seq = seq
realm.commitTransaction()
notifyDatabaseUpdated()
}
fun deleteWithReward(id: Long) {
realm.beginTransaction()
val item = realm.where<HabitDto>().equalTo("id", id).findFirst()!!
item.deleteFromRealm()
realm.commitTransaction()
notifyDatabaseUpdated()
}
}
04 May 2019
|
Android
File에 텍스트 읽고 쓰는 예제
</pre class=”prettyprint”>
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
public class FileUtil {
public synchronized static void writeTextToFile(String filepath, String text) {
File file = new File(filepath);
FileWriter fw = null;
BufferedWriter bw = null;
try {
fw = new FileWriter(file);
bw = new BufferedWriter(fw);
bw.write(text);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
fw.close();
} catch (Exception e) {
e.printStackTrace();
}
} }
public synchronized static String getTextFromFile(String filepath) {
File file = new File(filepath);
StringBuilder sb = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append('\n');
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString(); } }
</pre>
03 May 2019
|
Android
styles.xml
<resources>
<style name=”AppTheme” parent=”Theme.AppCompat.Light.DarkActionBar”>
<item name=”colorPrimary”>#80CBC4</item>
<item name=”colorPrimaryDark”>#80CBC4</item>
<item name=”colorAccent”>#3F51B5</item>
</style>
<style name=”SnowDeerTheme” parent=”AppTheme”>
<item name=”windowNoTitle”>true</item>
<item name=”windowActionBar”>false</item>
</style>
</resources>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.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"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="@color/colorPrimary"
app:expandedTitleMarginEnd="0dp"
app:expandedTitleMarginStart="0dp"
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:orientation="vertical"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.7">
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_gravity="center_horizontal"
app:srcCompat="@drawable/ic_launcher"/>
<TextView
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/app_name"/>
</LinearLayout>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:popupTheme="@style/SnowDeerTheme"
android:title="@string/app_name"
app:layout_collapseMode="parallax"
app:layout_scrollFlags="scroll|exitUntilCollapsed"/>
</android.support.design.widget.CollapsingToolbarLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:tabGravity="fill"
app:tabMaxWidth="200dp"
app:tabMode="scrollable"/>
</RelativeLayout>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
01 May 2019
|
Android
회원 가입
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import com.google.firebase.auth.FirebaseAuth
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
create_userid_button.setOnClickListener {
val email = email_input.text.toString()
val password = password_input.text.toString()
registerUser(email, password)
}
}
private fun registerUser(email: String, password: String) {
FirebaseAuth.getInstance().createUserWithEmailAndPassword(email, password)
.addOnSuccessListener {
val userId = FirebaseAuth.getInstance().currentUser
Toast.makeText(applicationContext, "UserId(${userId?.email}) 생성 성공", Toast.LENGTH_SHORT).show()
}
.addOnFailureListener {
it.printStackTrace()
Toast.makeText(applicationContext, "UserId 생성 실패(${it.message})", Toast.LENGTH_SHORT).show()
}
}
}
로그인
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import com.google.firebase.auth.FirebaseAuth
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
login_button.setOnClickListener {
val email = email_input.text.toString()
val password = password_input.text.toString()
login(email, password)
}
}
private fun login(email: String, password: String) {
FirebaseAuth.getInstance().signInWithEmailAndPassword(email, password)
.addOnSuccessListener {
val userId = FirebaseAuth.getInstance().currentUser
Toast.makeText(applicationContext, "로그인 성공", Toast.LENGTH_SHORT).show()
}
.addOnFailureListener {
it.printStackTrace()
Toast.makeText(applicationContext, "로그인 실패(${it.message})", Toast.LENGTH_SHORT).show()
}
}
}
인증 메일 전송
인증 메일 양식은 Firebase Console에서 수정할 수 있습니다.
하지만 악용될 가능성이 있기 때문에 제목만 수정이 가능하며, 내요을 수정하지는 못합니다.
private fun verifyEmail() {
val currentUser = FirebaseAuth.getInstance().currentUser
currentUser?.let {
it.sendEmailVerification()
.addOnSuccessListener {
Toast.makeText(applicationContext, "인증 메일을 전송했습니다.", Toast.LENGTH_SHORT).show()
}
.addOnFailureListener {
it.printStackTrace()
Toast.makeText(applicationContext, "인증 메일 전송 실패(${it.message})", Toast.LENGTH_SHORT).show()
}
}
}
Email 변경 및 패스워드 변경
Email 및 패스워드 변경은 다음 명령어를 이용해서 할 수 있습니다.
- currentUser.updateEmail(newEmail: String)
- currentUser.updatePassword(newPassword: String)
25 Apr 2019
|
Android
build.gradle (프로젝트)
dependencies {
classpath 'com.android.tools.build:gradle:3.4.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.2.0'
}
build.gradle (모듈)
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.google.firebase:firebase-auth:16.0.5'
implementation 'com.google.firebase:firebase-database:16.0.4'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.google.android.gms:play-services:12.0.1'
implementation 'com.google.android.gms:play-services-auth:16.0.1'
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/logout_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="logout"/>
</RelativeLayout>
activity_sign_in.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.google.android.gms.common.SignInButton
android:id="@+id/sign_in_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
</RelativeLayout>
MainActivity.kt
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import com.google.android.gms.auth.api.Auth
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.api.GoogleApiClient
import com.google.firebase.auth.FirebaseAuth
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity(), GoogleApiClient.OnConnectionFailedListener {
override fun onConnectionFailed(p0: ConnectionResult) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
lateinit var googleApiClient: GoogleApiClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
googleApiClient = GoogleApiClient.Builder(applicationContext)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API)
.build()
val currentUser = FirebaseAuth.getInstance().currentUser
if (currentUser == null) {
val intent = Intent(applicationContext, LoginActivity::class.java)
startActivity(intent)
} else {
// TODO ...
}
logout_button.setOnClickListener {
FirebaseAuth.getInstance().signOut()
Auth.GoogleSignInApi.signOut(googleApiClient)
val intent = Intent(applicationContext, LoginActivity::class.java)
startActivity(intent)
}
}
override fun onResume() {
super.onResume()
val currentUser = FirebaseAuth.getInstance().currentUser
supportActionBar?.title = currentUser.toString()
}
}
LoginActivity.kt
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import com.google.android.gms.auth.api.Auth
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.api.GoogleApiClient
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.GoogleAuthProvider
import kotlinx.android.synthetic.main.activity_login.*
class LoginActivity : AppCompatActivity(), GoogleApiClient.OnConnectionFailedListener {
private val REQUEST_CODE_SIGN_IN = 1001
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build()
val googleSignInClient = GoogleSignIn.getClient(this, gso)
login_button.setOnClickListener {
val intent = googleSignInClient.signInIntent
startActivityForResult(intent, REQUEST_CODE_SIGN_IN)
}
}
override fun onConnectionFailed(result: ConnectionResult) {
Toast.makeText(applicationContext, "연결 실패", Toast.LENGTH_SHORT).show()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_CODE_SIGN_IN) {
val result = Auth.GoogleSignInApi.getSignInResultFromIntent(data)
if (result.isSuccess) {
val account = result.signInAccount
val credential = GoogleAuthProvider.getCredential(account?.idToken, null)
FirebaseAuth.getInstance().signInWithCredential(credential)
.addOnSuccessListener {
Toast.makeText(applicationContext, "인증 성공", Toast.LENGTH_SHORT).show()
startActivity(Intent(applicationContext, MainActivity::class.java))
finish()
}
.addOnFailureListener {
Toast.makeText(applicationContext, "인증 실패(${it.message})", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(applicationContext, "로그인 실패", Toast.LENGTH_SHORT).show()
}
}
}
}