#----Glide--- start
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}

#---Glide V4.X
-dontwarn com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool
-dontwarn com.bumptech.glide.load.resource.bitmap.Downsampler
-dontwarn com.bumptech.glide.load.resource.bitmap.HardwareConfigState
#----Glide--- end


'Development > Android' 카테고리의 다른 글

Google Translate  (0) 2018.05.30
Multipart used retrofit2  (0) 2018.05.16
If Broadcast Receiver is taking too long to receive in onReceive()  (0) 2018.05.04
Multidex setting  (0) 2018.04.06
apk 파일 디컴파일 하기  (0) 2018.04.06

BroadCastReceiver 호출 시


리시버 호출이 늦게 될 경우


intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);


를 추가해서 호출 속도를 높여준다.



출처 : https://stackoverflow.com/questions/20283440/broadcast-receiver-is-taking-too-long-to-receive-in-onreceive-after-airplane-m

'Development > Android' 카테고리의 다른 글

Multipart used retrofit2  (0) 2018.05.16
Android Glide Proguard rules  (0) 2018.05.16
Multidex setting  (0) 2018.04.06
apk 파일 디컴파일 하기  (0) 2018.04.06
안드로이드 개발자라면 꼭 봐야할 사이트들  (0) 2018.04.02

Mastering Kotlin standard functions: run, with, let, also and apply

Some of the Kotlin’s standard functions are so similar that we are not sure which to use. Here I will introduce a simple way to clearly distinguish their differences and how to pick which to use.

Scoping functions

The functions that I’ll focus on is runwithT.runT.letT.also and T.apply. I call them scoping functions as I view their main functionality as provide an inner scope for the caller function.

The simplest way to illustrate scoping is the run function

fun test() {
var mood = "I am sad"

run {
val mood = "I am happy"
println(mood) // I am happy
}
println(mood) // I am sad
}

With this, inside the test function, you could have a separate scope where mood is redefined to I am happy before printing, and it is fully enclosed within the run scope.

This scoping function itself seems not very useful. But there’s another nice bit it has than just the scope; it returns something i.e. the last object within the scope.

Hence the below would be neat, where by we can apply the show() to both views as below, without calling it twice.

    run {
if (firstTimeView) introView else normalView
}.show()

3 attributes of scoping functions

To make scoping functions more interesting, let me categorize their behavior with 3 attributes. I will use these attributes to distinguish them from each others.

1. Normal vs. extension function

If we look at with and T.run, both functions are actually pretty similar. The below does the same thing.

with(webview.settings) {
javaScriptEnabled = true
databaseEnabled = true
}
// similarly
webview.settings.run {
javaScriptEnabled = true
databaseEnabled = true
}

However, their different is one is a normal function i.e. with, while the other is an extension function i.e. T.run.

So the question is, what is the advantage of each?

Imagine if webview.settings could be null, they will look as below.

// Yack!
with(webview.settings) {
this?.
javaScriptEnabled = true
this?.databaseEnabled = true
}
}
// Nice.
webview.settings?.run {
javaScriptEnabled = true
databaseEnabled = true
}

In this case, clearly T.run extension function is better, as we could apply check for nullability before using it.

2. This vs. it argument

If we look at T.run and T.let, both functions are similar except for one thing, the way they accept the argument. The below shows the same logic for both functions.

stringVariable?.run {
println("The length of this String is $length")
}
// Similarly.
stringVariable?.let {
println("The length of this String is ${it.length}")
}

If you check the T.run function signature, you’ll notice the T.run is just using made as extension function calling block: T.(). Hence all within the scope, the T could be referred as this.In programming, this could be omitted most of the time. Therefore in our example above, we could use $length in the println statement, instead of ${this.length}. I call this as sending in this as argument.

However for T.let function signature, you’ll notice that T.let is sending itself into the function i.e. block: (T). Hence this is like a lambda argument sent it. It could be referred within the scope function as it. So I call this as sending in it as argument.

From the above, it does seems like T.run is more superior over T.let as it is more implicit, but there are some subtle advantages of T.let function as below: -

  • The T.let does provide a clearer distinguish use the given variable function/member vs. the external class function/member
  • In the event that this can’t be omitted e.g. when it is sent as a parameter of a function, it is shorter to write than this and clearer.
  • The T.let allow better naming of the converted used variable i.e. you could convert it to some other name.
stringVariable?.let {
nonNullString ->
println("The non null string is $nonNullString")
}

3. Return this vs. other type

Now, let’s look at T.let and T.also, both are identical, if we look into the internal function scope of it.

stringVariable?.let {
println("The length of this String is ${it.length}")
}
// Exactly the same as below
stringVariable?.also {
println("The length of this String is ${it.length}")
}

However their subtle different is what they return. The T.let returns a different type of value, while T.also returns the T itself i.e. this.

Both are useful for chaining function, where byT.let let you evolve the operation, and T.also let you perform on the same variable i.e. this.

Simple illustration as below

val original = "abc"
// Evolve the value and send to the next chain
original.let {
println("The original String is $it") // "abc"
it.reversed() // evolve it as parameter to send to next let
}.let {
println("The reverse String is $it") // "cba"
it.length // can be evolve to other type
}.let {
println("The length of the String is $it") // 3
}
// Wrong
// Same value is sent in the chain (printed answer is wrong)
original.also {
println("The original String is $it") // "abc"
it.reversed() // even if we evolve it, it is useless
}.also {
println("The reverse String is ${it}") // "abc"
it.length // even if we evolve it, it is useless
}.also {
println("The length of the String is ${it}") // "abc"
}
// Corrected for also (i.e. manipulate as original string
// Same value is sent in the chain
original.also {
println("The original String is $it") // "abc"
}.also {
println("The reverse String is ${it.reversed()}") // "cba"
}.also {
println("The length of the String is ${it.length}") // 3
}

The T.also may seems meaningless above, as we could easily combine them into a single block of function. Thinking carefully, it has some good advantages

  1. It can provide a very clear separation process on the same objects i.e. making smaller functional section.
  2. It can be very powerful for self manipulation before being used, making a chaining builder operation.

When both combine the chain, i.e. one evolve itself, one retain itself, it becomes something powerful e.g. below

// Normal approach
fun makeDir(path: String): File {
val result = File(path)
result.mkdirs()
return result
}
// Improved approach
fun makeDir(path: String) = path.let{ File(it) }.also{ it.mkdirs() }

Looking at all attributes

By looking at the 3 attributes, we could pretty much know the function behavior. Let me illustrate on the T.apply function, as it has not be mentioned above. The 3 attributes of T.apply is as below…

  1. It is an extension function
  2. It send this as it’s argument.
  3. It returns this (i.e. itself)

Hence using it, one could imagine, it could be be used as

// Normal approach
fun createInstance(args: Bundle) : MyFragment {
val fragment = MyFragment()
fragment.arguments = args
return fragment
}
// Improved approach
fun createInstance(args: Bundle)
= MyFragment().apply { arguments = args }

Or we could also making unchained object creation chain-able.

// Normal approach
fun createIntent(intentData: String, intentAction: String): Intent {
val intent = Intent()
intent.action = intentAction
intent.data=Uri.parse(intentData)
return intent
}
// Improved approach, chaining
fun createIntent(intentData: String, intentAction: String) =
Intent().apply { action = intentAction }
.apply { data = Uri.parse(intentData) }

Function selections

Hence clearly, with the 3 attributes, we could now categorize the functions accordingly. And based on that, we could form a decision tree below that could help decide what function we want to use pending on what we need.


Hopefully the decision tree above clarifies the functions clearer, and also simplifies your decision making, enable you to master these functions usage appropriately.

Feel free to provide some good real example of how you use these functions as response to this blog. I would love to hear from you. This may benefits others.


I hope you appreciate this post and it’s helpful for you. Do share with others.

You could check out my other interesting topics here.

Follow me on medium, Twitter or Facebook for little tips and learning on Android, Kotlin etc related topics. ~Elye~



출처 : https://medium.com/@elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84

'Development > Kotlin' 카테고리의 다른 글

Kotlin Sha256  (0) 2019.10.16
When Intelli is not working.  (0) 2019.07.04
Find numbers in string in kotlin  (0) 2019.07.02
Kotlin Study Link  (0) 2018.04.03

multidex용 앱 구성


multidex 구성을 사용하도록 앱 프로젝트를 설정하려면 앱이 지원하는 최소 Android 버전에 따라 앱 프로젝트에서 다음 내용을 변경해야 할 수 있습니다.

minSdkVersion이 21 이상으로 설정되어 있을 경우 아래와 같이 모듈 수준의 build.gradle 파일에서 multiDexEnabled를 true로 설정하기만 하면 됩니다.

android {
    defaultConfig
{
       
...
        minSdkVersion
21
        targetSdkVersion
26
       
multiDexEnabled true
   
}
   
...
}

그러나 minSdkVersion이 20 이하로 설정되어 있으면 다음과 같이 multidex 지원 라이브러리를 사용해야 합니다.

  • multidex를 활성화하고 multidex 라이브러리를 종속성으로 추가할 수 있도록 아래와 같이 모듈 수준 build.gradle 파일을 변경합니다.

    android {
        defaultConfig
    {
           
    ...
            minSdkVersion
    15
            targetSdkVersion
    26
           
    multiDexEnabled true
       
    }
       
    ...
    }

    dependencies
    {
     
    compile 'com.android.support:multidex:1.0.1'
    }
  • Application 클래스 재정의 여부에 따라 다음 중 하나를 수행합니다.
    • Application 클래스를 재정의하지 않을 경우 매니페스트 파일을 편집하여 <application> 태그에서 android:name을 다음과 같이 설정합니다.

      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         
      package="com.example.myapp">
         
      <application
                 
      android:name="android.support.multidex.MultiDexApplication" >
              ...
         
      </application>
      </manifest>
    • Application 클래스를 재정의할 경우 다음과 같이 MultiDexApplication을 확장하도록 변경합니다(해당할 경우).

      public class MyApplication extends MultiDexApplication { ... }
    • 또는 Application 클래스를 재정의하지만 기본 클래스를 변경할 수 없을 경우 attachBaseContext() 메서드를 재정의하고 MultiDex.install(this)을 호출하여 multidex를 활성화합니다.

      public class MyApplication extends SomeOtherApplication {
       
      @Override
       
      protected void attachBaseContext(Context base) {
           
      super.attachBaseContext(context);
           
      Multidex.install(this);
       
      }
      }

앱을 빌드할 때 Android 빌드 도구는 기본 DEX 파일(classes.dex)과 지원하는 DEX 파일(classes2.dexclasses3.dex 등)을 필요에 따라 구성합니다. 그 후 빌드 시스템이 모든 DEX 파일을 APK로 패키징합니다.

런타임에서 multidex API는 특수 클래스 로더를 사용하여 (기본 classes.dex 파일)에서만 검색하는 대신) 메서드에서 사용할 수 있는 모든 DEX 파일을 검색합니다.


출처 : https://developer.android.com/studio/build/multidex.html?hl=ko#avoid





dex2jar 를 이용해 apk 파일을 디컴파일 해 볼 수 있다.


d2j-dex2jar.bat -f -o [파일명].jar [APK 파일명].apk




ex... apk 파일 명이 abc일 경우.. abc.jar로 만들때


d2j-dex2jar.bat -f -o abc.jar abc.apk


-->> abc.jar 파일 생성됨.


이후


jd-gui

와 같은 툴을 이용해 보면 된다.

public class IconBadge {

/*****************************************
* 사용자 Static Method
*****************************************/
public static String getLauncherClassName(Context context) {
PackageManager pm = context.getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
for (ResolveInfo resolveInfo : resolveInfos) {
String pkgName = resolveInfo.activityInfo.applicationInfo.packageName;
if (pkgName.equalsIgnoreCase(context.getPackageName())) {
String className = resolveInfo.activityInfo.name;
return className;
}
}
return null;
}

//배지 카운트 업데이트
public static void updateIconBadge(Context context, int notiCnt) {
Intent badgeIntent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
badgeIntent.putExtra("badge_count", notiCnt);
badgeIntent.putExtra("badge_count_package_name", context.getPackageName());
badgeIntent.putExtra("badge_count_class_name", getLauncherClassName(context));
context.sendBroadcast(badgeIntent);
}

}


Android Weekly #303

Android Coroutine Recipes (www.youtube.com)

Android GDE Dmytro Danylyk presents on Kotlin coroutines.


Link

사용자 위경도 값을 이용해

DB에 저장되어있는 위경도와 비교해 가까운 순으로 정렬


SELECT (ABS(user.lat - A.LATITUDE) + ABS(user.lng - A.LONGITUDE)) * 100 as distance,A.FIRMNM FROM AllLottoStore as A

ORDER BY ABS(user.lat - A.LATITUDE) + ABS(user.lng - A.LONGITUDE) ASC

where distance < 1 


* 100 ==> km로 구분하기 위해..

*100 없어도 문제없음.



where distance < 1 

주변 1km 안에 있는 리스트.




추가 관련 사이트 링크




'Development > Android' 카테고리의 다른 글

Android Badge Count Update  (0) 2018.04.02
Android Coroutine Recipes  (0) 2018.04.02
Android SQLite 프로그램 다운로드 URL  (0) 2018.03.30
마켓 스크린샷 만들기 링크  (0) 2018.03.30
Android Study Link  (0) 2018.03.27

Realm


https://academy.realm.io/kr/section/android/



박상권의 삽질블로그

http://gun0912.tistory.com/



꿈 많은 개발자가 되자 - Taehwan

https://thdev.tech/


'Development > Android' 카테고리의 다른 글

Android SQLite 프로그램 다운로드 URL  (0) 2018.03.30
마켓 스크린샷 만들기 링크  (0) 2018.03.30
sqlite 에서 pk 여러개 쓰기  (0) 2014.06.20
안드로이드 아이콘 뱃지  (0) 2014.06.19
기기 해상도 구하기  (0) 2014.06.09

+ Recent posts