728x90

Android Studio 에서 compileSdkVersion 을 바꾸면 아래와 같이 comile Library 버전을 맞춰줘야 에러가 없어진다.

그래서 찾아보기가 만만치 않아서 적어둔다.


compileSdkVersion 22
targetSdkVersion 22
compile 'com.android.support:support-v4:22.0.0'
compile 'com.android.support:appcompat-v7:22.0.0'

compileSdkVersion 23
targetSdkVersion 23
compile 'com.android.support:support-v4:23.0.0'
compile 'com.android.support:appcompat-v7:23.0.0'

compile 'com.android.support:appcompat-v7:23.1.1'

compile 'com.android.support:appcompat-v7:23.4.0'

compileSdkVersion 25
targetSdkVersion 25
compile 'com.android.support:appcompat-v7:25.1.0'

compileSdkVersion 26
targetSdkVersion 26
compile 'com.android.support:appcompat-v7:26.+'

블로그 이미지

Link2Me

,
728x90

https://developer.android.com/studio/build/application-id?hl=ko  을 읽어보면 내용이 잘 나온다.


개발할 때 동일한 앱을 두개 띄우고 서로간에 기능을 확인하고 싶다면

applicationId "com.tistory.link2me.asynchttpjson" 와 같이 applicationId 를 변경하면 또하나의 앱이 설치된다.

즉, 패키지명과 applicationId 를 다르게 하고서 개발 테스트를 하면 좋을 거 같다.


사무실과 집에 있는 PC 환경이 다르지만 src 폴더만 복사해서 코딩하면 되므로 편리하다.


집에 있는 PC build.gradle 및 Android Studio 3.1.3

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.tistory.link2me.asynchttpjson"
        minSdkVersion 19
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support:design:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    implementation 'com.loopj.android:android-async-http:1.4.9'
    implementation 'com.github.bumptech.glide:glide:3.8.0'
    implementation 'com.android.support:recyclerview-v7:26.1.0'
    implementation 'com.android.support:cardview-v7:26.1.0'
} 


사무실 노트북 build.gradle 및 Android Studio 2.3.3

 apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.0"

    defaultConfig {
        applicationId "com.tistory.link2me.asynchttpjson"
        minSdkVersion 19
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:26.+'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'com.loopj.android:android-async-http:1.4.9'
    compile 'com.github.bumptech.glide:glide:3.8.0'
    compile 'com.android.support:recyclerview-v7:24.2.0'
    compile 'com.android.support:cardview-v7:24.2.0'
}



조만간에 집에 있는 PC에서 Android Studio 2.3.3 과 3.1.3 을 동시에 이용할 수 있는 환경을 만들어서 테스트를 해볼 생각이다.

노트북에 있는 관련 파일을 모두 복사하고 환경 세팅을 서로 다르게 하면 둘 다 이용이 가능할 거 같다.


컴파일 속도나 인식속도는 Android Studio 3.1.3 이 엄청 빠르다.

그런데 기존 테스트 코드를 Import Moulde 하면 인식을 잘 못하는 경향이 있다. 버그(?)

그리고 Eclipse 코드를 읽어오기가 Android Studio 2.3.3 에서는 잘 되기 때문에 일단 코드를 읽은 다음에 Android Studio 환경에 맞게 수정하는 것이 편하기도 하고 노트북 속도 문제도 있어서 2.3.3 에서 업그레이드를 중지한 상태다.

블로그 이미지

Link2Me

,
728x90

앱의 데이터가 자동으로 백업될 수 있다는 걸 몰랐다.

출처 : https://m.blog.naver.com/PostView.nhn?blogId=netrance&logNo=221224761858&targetKeyword=&targetRecommendationCode=1


안드로이드 6.0부터는 AndroidManifest.xml 파일에서 application 요소의 android:allowBackup 속성을 자동으로 true로 설정된다.
이로 인해 사용자도 모르게 데이터가 구글 클라우드에 자동으로 백업된다.


<application
    android:allowBackup="false"
    android:icon="@drawable/icon"
    android:fullBackupContent="false"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme.NoActionBar">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

블로그 이미지

Link2Me

,
728x90

Error generating final archive: Debug certificate expired on 3/20/10 2:35 PM!


debug.keystore 를 찾아서 debug certificate를 지우고 다시 빌드하면 해결된다.


디버그 인증서 만료기한은 1년이다.






블로그 이미지

Link2Me

,
728x90

Eclipse 에서 컴파일을 하면 최신폰 정보를 보여주지 못한다.

Eclipse 사용버전이 낮아서 그럴 수도 있다.



Android Studio 에서는 폰 정보가 바로 확인된다.


Eclipse 로 컴파일은 성공인데 어플 로그인을 하다가 어플이 죽는다.

원인을 찾아야 하는데 원인을 파악하기가 쉽지 않다.


그래서 소스를 Android Studio 에서 아래와 같이 모듈 Import 로 가져오기를 하고 컴파일을 해서 확인하면 어디에서 문제가 발생하는지 LogCat에 잘 보여준다.


Eclipse 버전이 낮은 정보에서 컴파일 한 경우에는 소스를 완전 수정해야 하는 사항이 많아서 그냥 단순하게 에러 확인용도로만 사용한다.

KeyStore 정보가 서로간에 연동이 안되는 것 같아서 업그레이드에도 문제가 되어 조심스럽게 다루고 있다.

블로그 이미지

Link2Me

,
728x90

사진을 촬영하여 이미지를 업로드하기 위한 기능을 테스트하려고 한다.

사진 촬영하여 CROP 하는 곳에서 제대로 처리를 못하고 있어서 라이브러리를 이용해보려고 한다.


안드로이드 스튜디오에서 앱 build.Gradle 을 아래와 같이 수정했더니 에러가 발생한다.


 apply plugin: 'com.android.application'

android {
    compileSdkVersion 22
    buildToolsVersion "25.0.0"

    defaultConfig {
        applicationId "com.tistory.link2me.imageupload"
        minSdkVersion 16
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:support-v4:22.0.0'
    compile 'com.android.support:appcompat-v7:22.0.0'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'com.squareup.okhttp3:okhttp:3.9.0'
    compile 'com.squareup.picasso:picasso:2.5.2'
    compile 'com.google.firebase:firebase-messaging:10.2.6'
    compile 'com.isseiaoki:simplecropview:1.1.6'
}


roundIcon이 API 25에서 추가된 것이라 에러가 발생한다.

AndroidMenifest.xml 파일 내에 있는 android:roundIcon="@mipmap/ic_launcher"
를 제거해주고 Clean Project를 하면 에러가 사라진다.


AppCompatActivity는 안드로이드 하위버전을 지원하는 액티비티다.
Support Library에 있는 클래스들은 안드로이드 하위버전을 지원하기 위해 존재한다.
안드로이드 4.0 이상부터 지원하겠다고 하면 AppCompatActivity을 쓸 이유가 없다. 그냥 Activity를 쓰면 된다.

public class MainActivity extends AppCompatActivity {

public class MainActivity extends Activity {
로 변경했다.


2017.9.21

- simplecropview 라이브러리를 추가해서 CROP 하는 것은 실패했다.

  구글, 블로그에 나온 방법으로 코드를 구현하여 해결했다.

블로그 이미지

Link2Me

,
728x90

Some file crunching failed, see logs for details afer update gradle

안드로이드 스튜디오에서 Activity 를 추가하는 도중에 이런 메시지가 나온다.


gradle.properties 파일에서 이렇게 수정하라고 Stackoverflow 에 나오길래 했는데도 안된다.
android.buildCacheDir=D:/android-studio/build-cache


app build.gradle file 에 android 부분에 아래 코드를 추가하니까 해결된다.

android {
    aaptOptions { 
        cruncherEnabled = false 
    }
}


블로그 이미지

Link2Me

,
728x90

AsyncTask 를 Activity 내 Inner Class 로 만든 경우에 메모리 누수를 방지하기 위하여 static 으로 처리하고 WeakReference 를 사용하는 예제를 찾아봤다.


https://gist.github.com/rorist/459787 에 나온 방법과 https://medium.com/google-developer-experts/finally-understanding-how-references-work-in-android-and-java-26a0d9c92f83 는 비슷한 방법이 나온다.


내가 참조하여 사용한 방법은 https://stackoverflow.com/questions/19551484/android-do-i-have-to-have-weakreference-for-inner-class-asynctask 에 나온 걸 활용했다.


잘못 사용하고 있는지 여부는 좀 더 테스트를 해보련다.


public static class saveContactsFromDbData extends AsyncTask<String, Void, String> {
    private WeakReference<SaveContactsActivity> weakActivity;
    SaveContactsActivity activity;

    long start; // 서버에서 가져오는 시간 측정
    @SuppressLint("SimpleDateFormat")
    SimpleDateFormat FORMATTER = new SimpleDateFormat("mm:ss.SSS");

    int newcnt = 0;
    int upcnt = 0;
    int no_cnt = 0;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();           
        weakActivity = new WeakReference<SaveContactsActivity>(activity);
    }
   
    @Override
    protected String doInBackground(String... params) {

        start = System.currentTimeMillis();

        JSONArray peoples = null;
        try {
            JSONObject jsonObj = new JSONObject(params[0]);
            peoples = jsonObj.getJSONArray(TAG_RESULTS);

            return null;

        } catch (Exception e) {
            return new String("Exception: " + e.getMessage());
        }

    }

    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        if (weakActivity.get() != null) {
            // 메모리 비우기
            contactMap.clear();
        }

    }
}


블로그 이미지

Link2Me

,
728x90

안드로이드는 모바일 디바이스에서 동작하기 때문에 제한된 메모리 용량을 지녀, 누수(leak)가 많이 발생하면 사용 가능한 메모리가 부족하게 된다.

앱에 메모리 누수가 있는 경우, 객체는 메모리에서 반환될 수 없다.
결과적으로 안드로이드 시스템은 더 많은 메모리를 요청한다. 그러나 한계가 있다.
결국 시스템은 앱에 더 많은 메모리를 할당하는 것을 거부한다. 이렇게 되면 앱은 메모리 부족으로 인해 강제 종료된다.


strong/weak reference
자바의 garbage collector는 더 이상 참조되지 않는 객체를 자동으로 수거하여 프로그래머가 직접 메모리를 관리하지 않아도 되도록 해준다. 하지만 모든 경우에 대해 garbage collector가 깨끗하게 사용하지 않는 객체들을 정리해주는 것은 아니다. 때로는 참조가 계속 남아있는 경우가 있을 수 있고 이런 경우에 객체는 수거되지 않고 memory leak으로 이어질 수 있다. 이와 같이 참조를 부주의하게 사용하여 발생할 수 있는 memory leak현상을 막기 위해서는 객체에 대한 참조를 유연하게 다루어 필요하지 않은 객체들이 수거될 수 있도록 해야한다.


GC(Garbage collector)는 참조 카운트가 0인 인스턴스들 즉, unReachable에 대한 객체에 대해서만 메모리를 회수한다.
만약 Activity 인스턴스가 Heap 루트로부터 어떤 strong reference에 묶여있는 경우라면, GC(Garbage collector)는 이를 메모리에서 제거할 수 없고, 해당 인스턴스는 leaked Activity 오브젝트가 된다.


메모리 누수가 발생하는 상황

- 프로세스-앱의 상태와 관계없이 글로벌 스태틱 오브젝트가 존재하고 액티비티의 참조들의 체인을 유지할 때

- 쓰레드-액티비티 생명주기를 무시하고 strong reference가 남아있을 때

- AsyncTask 를 선언하고 인스턴스화하는 것을 액티비티 내 익명 클래스에서 진행할 경우,

  Activity가 종료되어도(destroy) 백그라운드에서 계속 존재하게 되며 GC가 수거하지 못한다.

- AsyncTask를 생성했던 Activity가 먼저 destroy되는 경우(다른 UI로 전환) 메모리 릭이 발생할 수 있다.

  이미 자신을 실행시켰던 Activity가 존재하지 않는데 AsyncTask가 UI 처리같은 걸을 요구하면

  메모리상에 존재하지 않는 것을 참조하게 되어 메모리릭이 발생한다.


메모리 누수를 피하는 법

출처 : https://android-developers.googleblog.com/2009/01/avoiding-memory-leaks.html

- GC(garbage collector)가 메모리 누수에 대한 보험은 아니다

- 라이프 사이클을 제어할 수 없다면, Activity 내에서 non-static inner classes 를 피하라.

- AsyncTask는 doInBackground 메소드만 백그라운드 스레드에서 실행되며, 나머지는 메인 스레드에서 실행된다.
백그라운드 작업시간이 긴 경우에는 UI 에서 실행중임을 알 수 있도록 ProgressBar 를 보여줘서
Activity 가 전환되지 않도록 하라.

- context-activity 대신 context-application 을 사용하라.

  Activity Context의 Reference 생명 주기는 반드시 Activity 생명 주기와 동일해야 한다.

  뷰를 수정하거나 할때는 Activity Context를 나머지 경우에는 Application Context를 사용하라.

  Context 에는 2가지 종류가 있다. Application context, Activity context ==> http://dev.youngkyu.kr/36 참조


static 변수 사용을 지양하라.

- static은 객체 지향적이지 않다.
- 지나치게 많은 static 변수를 사용하게 되면 이들로부터 메모리 회수를 할 수 없어서 가상머신이 메모리 부족을 겪을 수 있다.
- static 변수는 프로그램이 실행되고 있는 내내 살아있게 된다.
- 하나의 인스턴스로 생성하게 되면, 호출을 시키게 되면 그 함수 호출이 끝난 후 인스턴스는 소멸된다.
  훨씬 메모리를 절약하게 된다.
- static 메서드는 interface를 구현하는데 사용될 수 없다.
- 여러개의 인스턴스를 만드는 것을 피하고 싶다면 싱글톤 디자인 패턴을 이용하는 것이 훌륭한 대안이 될 수 있다.


bitmap 메모리 누수 관련 글

http://www.androidpub.com/1282821



Context 메모리 누수 피하는 방법 관련 글

http://blog.naver.com/huewu/110082062273



참고 사이트

http://www.kmshack.kr/2017/03/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%88%84%EC%88%98-%ED%8C%A8%ED%84%B4/


안드로이드 앱이 메모리 누수(Leak)를 만드는 8가지 방법

http://sjava.net/2016/05/%EB%B2%88%EC%97%AD-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%95%B1%EC%9D%B4-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%88%84%EC%88%98leak%EB%A5%BC-%EB%A7%8C%EB%93%9C%EB%8A%94-8%EA%B0%80%EC%A7%80/



블로그 이미지

Link2Me

,
728x90

삼성폰에서 Unrecognized profile 2130706433 for video/avc 메시지가 출력된다.

구글링을 해보니까 해결책은 아직 없는것 처럼 나오고 이런 증상을 보이는 폰의 종류들이 나온다.


Samsung Galaxy S6 and Samsung Galaxy S6 Edge+.


Same issue with note 5 upgraded to Android 6.0.1., i have another note 5 with Android 5.1 and is working fine.


Samsung S7 running Android 6.0.1. Screen is black or sometimes flickers dark green on VrVideoView player.


해결책인지는 모르겠는데 적어둔다.

https://developers.google.com/vr/android/reference/com/google/vr/sdk/base/Constants



블로그 이미지

Link2Me

,
728x90

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> //위치정보 확인함
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/> //위치정보 확인함
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> //wifi 연결을 확인함
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> //wifi 체인지를 확인함
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> //네트웍이 연결된것을 확인할수 있게함
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> //부팅완료를 확인할수있게함
<uses-permission android:name="android.permission.INTERNET"/> // 인터넷을 사용함
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> // 외장메모리 사용
<uses-permission android:name="android.permission.RECODER_AUDIO"/> //녹음이 가능하게 함
ACCESS_CHECKIN_PROPERTIES      체크인데이터베이스의_속성테이블로_액세스
ACCESS_COARSE_LOCATION         코스_로케이션_액세스_(Cell-ID/WiFi)
ACCESS_FINE_LOCATION           파인로케이션_액세스(GPS)
ACCESS_LOCATION_EXTRA_COMMANDS 로케이션_옵션_커맨드_액세스
ACCESS_MOCK_LOCATION           목_로케이션_프로바이더_생성_(테스트용)
ACCESS_NETWORK_STATE           네트워크_상태_접근
ACCESS_SURFACE_FLINGER         서피스_플링거_접근
ACCESS_WIFI_STATE              WiFi상태_접근
ADD_SYSTEM_SERVICE             시스템서비스_추가
BATTERY_STATS                  배터리_상태
BLUETOOTH                      블루투스
BLUETOOTH_ADMIN                블루투스_어드민
BRICK                          디바이스_실효성_지정
BROADCAST_PACKAGE_REMOVED      제거된_패키지에_대한_notification_브로드캐스트
BROADCAST_SMS                  SMS에_대한_브로드캐스트
BROADCAST_STICKY               인텐트_브로드캐스트
CALL_PHONE                     통화
CALL_PRIVILEGED                통화(긴급전화_포함)
CAMERA                         카메라
CHANGE_COMPONENT_ENABLED_STATE 컴포넌트의_실효성_변경
CHANGE_CONFIGURATION           컨피그_변경
CHANGE_NETWORK_STATE           통신상태_변경
CHANGE_WIFI_STATE              WiFi상태_변경
CLEAR_APP_CACHE                어플리케이션_캐시_클리어
CLEAR_APP_USER_DATA            어플리케이션의_유저데이터_클리어
CONTROL_LOCATION_UPDATES       위치정보_갱신
DELETE_CACHE_FILES             캐시파일_제거
DELETE_PACKAGES                패키지_제거
DEVICE_POWER                   전원상태에_대한_로우레벨_접근
DIAGNOSTIC                     진단리소스_읽고쓰기
DISABLE_KEYGUARD               키_가드_끄기_DUMP_덤?
EXPAND_STATUS_BAR              상태표시줄_확장
FACTORY_TEST                   팩토리_테스트
FLASHLIGHT                     플래시라이트
FORCE_BACK                     포스백
GET_ACCOUNTS                   어카운트_획득
GET_PACKAGE_SIZE               패키지_획득
GET_TASKS                      태스크_획득
HARDWARE_TEST                  하드웨어테스트
INJECT_EVENTS                  유저이벤트_키/트랙볼
INSTALL_PACKAGES               패키지_인스톨
INTERNAL_SYSTEM_WINDOW         내부_시스템윈도_활용
INTERNET                       인터넷
MANAGE_APP_TOKENS              어플리케이션_토큰관리
MASTER_CLEAR                   마스터_클리어
MODIFY_AUDIO_SETTINGS          오디오설정_편집
MODIFY_PHONE_STATE             전화상태_편집
MOUNT_UNMOUNT_FILESYSTEMS      파일시스템_편집
PERSISTENT_ACTIVITY            액티비티_지속
PROCESS_OUTGOING_CALLS         전화_발신처리_접근
READ_CALENDAR                  캘린더_읽어오기
READ_CONTACTS                  주소록_읽어오기
READ_FRAME_BUFFER              프레임버퍼_읽어오기
READ_INPUT_STATE               입력상태_읽어오기
READ_LOGS                      로그_읽어오기
READ_OWNER_DATA                owner_data읽어오기
READ_PHONE_STATE               통화상태_읽어오기_READ_SMS_SMS읽어오기
READ_SYNC_SETTINGS             동기설정_읽어오기
READ_SYNC_STATS                동기상태_읽어오기
REBOOT                         reboot
RECEIVE_BOOT_COMPLETED         boot완료
RECEIVE_MMS                    MMS수신
RECEIVE_SMS                    SMS수신
RECEIVE_WAP_PUSH               WAP수신
RECORD_AUDIO                   오디오_수신
REORDER_TASKS                  태스크_Z오더
RESTART_PACKAGES               패키지_리스타트
SEND_SMS                       SMS송신
SET_ACTIVITY_WATCHER           액티비티_왓쳐지정
SET_ALWAYS_FINISH              액티비티_전체_종료
SET_ANIMATION_SCALE            스케일_애니메이션_지정
SET_DEBUG_APP                  디버그어플리케이션_지정
SET_ORIENTATION                스크린_로테이션지정
SET_PREFERRED_APPLICATIONS     자주_사용하는_어플리케이션_지정
SET_PROCESS_FOREGROUND         포어그라운드_처리지정
SET_PROCESS_LIMIT              제한처리_지정
SET_TIME_ZONE                  타임존_지정
SET_WALLPAPER                  배경화면_지정
SET_WALLPAPER_HINTS            배경화면_힌트_지정
SIGNAL_PERSISTENT_PROCESSES    지속처리_시그널_지정
STATUS_BAR                     상태표시줄_지정
SUBSCRIBED_FEEDS_READ          서브스트립드_피즈_읽어오기
SUBSCRIBED_FEEDS_WRITE         서브스트립드_피즈_쓰기
SYSTEM_ALERT_WINDOW            알림_윈도우
VIBRATE                        진동
WAKE_LOCK                      알람
WRITE_APN_SETTINGS             APN설정_쓰기
WRITE_CALENDAR                 캘린더_쓰기
WRITE_CONTACTS                 주소록_쓰기
WRITE_GSERVICES                G서비스_쓰기
WRITE_OWNER_DATA               owner_data쓰기
WRITE_SETTINGS                 설정_쓰기
WRITE_SMS                      SMS쓰기
WRITE_SYNC_SETTINGS            동기설정_쓰기


출처 : http://iyeti.kr/673

블로그 이미지

Link2Me

,
728x90

컴파일 하려고 했더니 에러가 발생한다.

Error running app:
Instant Run requires 'Tools | Android | Enable ADB integration' to be enabled.



해결방법

Enable your ADB Integration. Go to Tools --> Android --> set checked in Enable ADB Integration



블로그 이미지

Link2Me

,
728x90

permission denied for this window type/BadTokenException


윈도우 팝업창이 뜨지 않고 에러가 발생하면서 죽는다.

검색해보네 API Level 19 이상에서는

WindowManager.LayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT

을 사용하지 말고

LayoutParams.TYPE_TOAST or TYPE_APPLICATION_PANEL

를 사용하라고 나온다.


그래서 아래와 같이 변경했더니 앱이 죽지 않고 팝업창이 잘 뜬다.


mParams = new WindowManager.LayoutParams(
   width,
   WindowManager.LayoutParams.WRAP_CONTENT,
   WindowManager.LayoutParams.TYPE_TOAST,
   WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
           | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
           | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
           | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON,
   PixelFormat.TRANSLUCENT);

블로그 이미지

Link2Me

,
728x90

상단에 액션바가 차지하고 있어서 눈에 거슬린다.

상단 액션바를 안보이게 처리하는 방법을 알아봤는데 어떨 때는 되고 안될때도 있는데 API 버전에 따라 다른거 같기도 하다.


AndroidManifest.xml 파일에서 수정할 부분

android:theme="@style/Theme.AppCompat.NoActionBar"


<application
  android:allowBackup="true"
  android:icon="@mipmap/ic_launcher"
  android:label="@string/app_name"
  android:supportsRtl="true"
  android:theme="@style/AppTheme">
  <activity android:name=".Intro">
      <intent-filter>
          <action android:name="android.intent.action.MAIN" />

          <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
  </activity>

 <application
  android:allowBackup="true"
  android:icon="@mipmap/ic_launcher"
  android:label="@string/app_name"
  android:supportsRtl="true"
  android:theme="@style/Theme.AppCompat.NoActionBar">
  <activity android:name=".Intro">
      <intent-filter>
          <action android:name="android.intent.action.MAIN" />

          <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
  </activity>


이것만 수정하고 컴파일을 하면 화면이 검은 바탕색으로 변경되어 버린다.


activity_main.xml 파일 수정

배경색 추가를 한다. 배경색을 하얀색으로 변경하면 보이던 글자가 안보이는 현상이 생겼다.

그래서 색상을 맞춘다고 @color/whitegray  = #f0f0f0 로 만들었다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/whitegray">


문제는 또 발생한다. 모든 xml 파일 상단에 배경색을 저장해줘야 하는 문제점이 보인다.

검정색 글씨로 보여야 되는데 하얀색 글자로 보이면서 가독성이 엄청 떨어져 보인다.

배경색을 lightgray 로 변경했더니 하얀색 글자가 보이기는 하는데 영 불편하다.


결국 해결한 방법은


<application
  android:allowBackup="true"
  android:icon="@mipmap/ic_launcher"
  android:label="@string/app_name"
  android:supportsRtl="true"
  android:theme="@style/AppTheme">
  <activity android:name=".Intro">
      <intent-filter>
          <action android:name="android.intent.action.MAIN" />

          <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
  </activity>


부분은 그대로 두고 참조하는 style.xml 파일 내용을 수정한다.

<item name="windowNoTitle">true</item> 라인을 추가한다.


<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="windowNoTitle">true</item>
    </style>

</resources>



해결방법 2.

=== strings.xml ===

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Light" />
    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>

=== AndroidManifest.xml ===

 <application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>






블로그 이미지

Link2Me

,
728x90

Activity 화면 갱신처리를 하는 방법때문에 다양한 걸 검색해서 찾았다.


public void onClick (View v){
    Intent intent = getIntent();
    finish();
    startActivity(intent);
}


이 코드는 현재 화면을 다시 Refresh 하는 코드다.

따라서 검색어를 입력하고 검색결과를 찾는 경우에는 부적합하다.

데이터를 삭제하고 화면을 갱신해야 하는 경우에는 유용하다.


The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread.

서버에서 데이터 및 사진이미지를 가져와서 ListView 에 갱신처리하는 걸 구현하는데 이런 메시지가 나오면서 간혹 앱이 강제종료된다.

무엇이 문제일까?

 AsyncTask.execute(new Runnable() 에서 처리한 결과가 listViewAdapter.notifyDataSetChanged(); 보다 늦게 나오면서 생기는 문제였다.

 결국 이런 로직을 사용하면 안된다는 것이다.

 처리순서가 순차적으로 되지 않고 아래 코드가 먼저 실행되면서 발생하는 문제였다.

     protected void showList() {
        try {
            JSONObject jsonObj = new JSONObject(searchJSON);
            peoples = jsonObj.getJSONArray(TAG_RESULTS);

            personDataItem.clear(); // 서버에서 가져온 데이터 초기화
            for(int i=0;i<peoples.length();i++){
                JSONObject c = peoples.getJSONObject(i);
                final String uid = c.getString(TAG_UID);
                final String name = c.getString(TAG_NAME);
                final String mobileNO = c.getString(TAG_MobileNO);
                final String officeNO = c.getString(TAG_OfficeNO);
                // 이미지 사이즈가 커서 생기는 문제??
                final Bitmap myIcon = PHPComm.autoresize_decodeResource(getResources(), R.mipmap.photo_base, 160);

                final String photoURL = Value.IPADDRESS + "/photos/" + uid + ".jpg";
                System.out.println("Server Photo URL ===" + photoURL);
                AsyncTask.execute(new Runnable() {
                    @Override
                    public void run() {
                        if(isExists(photoURL) == true){
                            Bitmap rBmp = loadWebImage(photoURL);
                            System.out.println("Server Photo Image ==="+ uid +" | "+ rBmp);
                            System.out.println("Photo Image height ==="+ rBmp.getHeight());
                            int width = (int)(rBmp.getWidth() * 160.0 / rBmp.getHeight());
                            rBmp = Bitmap.createScaledBitmap(rBmp, width, 160,true);

                            // 서버에서 가져온 데이터 저장
                            listViewAdapter.addItem(rBmp,uid,name,mobileNO,officeNO);
                        } else {
                            // 서버에 사진 이미지가 없으면 기본 이미지를 포함한 정보 저장
                            listViewAdapter.addItem(myIcon,uid,name,mobileNO,officeNO);
                        }
                    }
                });

            }

            runOnUiThread(new Runnable() { // 화면에 반영하기 위하여 runOnUiThread()를 호출하여 실시간 갱신한다.
                @Override
                public void run() {
                    // 갱신된 데이터 내역을 어댑터에 알려줌
                    listViewAdapter.notifyDataSetChanged();
                }
            });

        } catch (JSONException e) {
            e.printStackTrace();
        }

    }


도움이 되는 내용이 있어서 적어둔다.

http://www.vogella.com/tutorials/AndroidListView/article.html




블로그 이미지

Link2Me

,
728x90

Intent intent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+ mData.mobile));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);


위 코드는 기존에는 문제없이 잘 동작했었는데, 안드로이드 6.0 이상에서는 에러가 발생한다.

아래 코드로 아직 해결이 안된 상태다.


if (ActivityCompat.checkSelfPermission(getBaseContext(), Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED)
{
    Intent calIntent = new Intent(Intent.ACTION_CALL);
    calIntent.setData(Uri.parse("tel:"+ mData.mobile));
    calIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(calIntent);
}
else
{
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
    {
        requestPermissions(new String[]{Manifest.permission.CALL_PHONE}, 1);
    }
}



블로그 이미지

Link2Me

,
728x90

Android 패키지 파일을 분할하는 중에 문제가 발생하였습니다.

실행하려는 폰의 앱이 서버에 있는 앱보다 버전이 낮으면 아래와 같은 메시지를 띄운다.


서버와 앱 버전 체크를 하고 나서 파일 다운로드를 시도하면서 이런 메시지를 뿌린다.

Android 패키지 파일을 분할하는 중에 문제가 발생하였습니다.


defaultConfig {
    applicationId "com.android.USBController"
    minSdkVersion 19
    targetSdkVersion 27
    versionCode 3
    versionName "1.2"

}


버전 코드를 더 낮게 해서 컴파일 하는 것은 아닌지 체크를 해봐야 한다.


Android 앱 개발중 Release 버젼으로 .apk 파일을 생성해 모바일에 직접 설치하고 싶을 때
“패키지 파일을 분할하는 중에 문제가 발생하였습니다” 라는 에러가 나면서 설치되지 않는다면
APK 파일의 minSdkVersion (개발중인 안드로이드 버전)이
설치되는 폰의 Android Version 보다 높기 때문이다.
반대로 얘기하면, 실행하려는 폰이 개발된 앱보다 버젼이 낮기 때문이다.

블로그 이미지

Link2Me

,
728x90

class DownloadFileAsync extends AsyncTask<String, String, String> {
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        showDialog(DIALOG_DOWNLOAD_PROGRESS);
    }

    @Override
    protected void onPostExecute(String unused) {
        dismissDialog(DIALOG_DOWNLOAD_PROGRESS);



해결방법


class DownloadFileAsync extends AsyncTask<String, String, String> {

private ProgressDialog pDialog;

    @Override
    protected void onPreExecute()
    {
        super.onPreExecute();
        pDialog = new ProgressDialog(context);
        pDialog.setMessage("Please wait...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(true);
        pDialog.show();
    }

    @Override
    protected void onPostExecute(String unused) {
        pDialog.dismiss();

}

블로그 이미지

Link2Me

,
728x90

아래 코드는 아직 해결이 안된 상태다.

하지만 적어두어야 해결책을 찾으면 수정할 수 있으니 그냥 적는다.


Notification n = new Notification();
n.flags |= Notification.FLAG_AUTO_CANCEL;
// 아이콘 모양
n.icon = R.drawable.icon_small;
// 메시지 내용
n.tickerText = text;
System.out.println("msg======" + text);
// 메시지가 나타나는 시간
n.when = System.currentTimeMillis();
// 메시지의 제목 NotificationCompat.Builder
n.setLatestEventInfo(context,
        context.getResources().getString(R.string.app_name), text,
        pendingIntent(context));
// 메시지를 띄워준다.
nm.notify(mLastId, n);


해결방법

NotificationCompat.Builder 를 사용해서 변경한다.

import android.support.v4.app.NotificationCompat;


NotificationCompat.Builder n = new NotificationCompat.Builder(context);
n.setSmallIcon(R.drawable.icon_small);
n.setTicker(text); //알림이 뜰때 잠깐 표시되는 Text
n.setWhen(System.currentTimeMillis()); // 알림이 표시되는 시간
n.setNumber(10); // 미확인 알림의 개수
n.setContentTitle(context.getResources().getString(R.string.app_name));
n.setContentText(text); //상단바 알림 내용
n.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
n.setContentIntent(pendingIntent(context));
n.setAutoCancel(true); //터치하면 자동으로 지워지도록 설정하는 것

nm.notify(mLastId, n.build()); // 알림을 구분할 상수


import android.support.v4.app.NotificationCompat; 를 했는데 에러메시지가 나오면

project properties->java build path->libraries click add external jar



이렇게 하면 에러메시지는 사라지는데 컴파일을 해서 동작시키면 앱이 죽어버린다.



블로그 이미지

Link2Me

,
728x90

구글링을 해서 전화수신 기능을 테스트하다보니 ITelephony 에서 에러가 나온다.


해결방법은 첨부파일을 다운로드 받아서 Android Studio app/src/main/ 폴더에서 압축을 풀면 된다.

ITelephony_aidl.zip

app\src\main\java\com\android\internal\telephony\ITelephony.aidl 에 파일이 복사된다.

압축파일은 다른 폴더로 옮기거나 삭제한다.


이제 에러 표시가 되는 곳에서 Alt + Enter 키를 누르면 아래 화면이 나온다. 여기에서 Create interface 'ITelephony' 를 선택한다.



com.android.internal.telephony 를 입력한다.



그러면 Interface 파일이 생성된다.

아래 코드를 복사하여 붙여넣기 한다.

붙여넣기는 http://stackoverflow.com/questions/31473793/where-to-copy-itelephony-java-in-android-studio-and-how-to-import-it-please-don 에서 복사해서 넣으면 된다.


package com.android.internal.telephony;

public interface ITelephony {
    void answerRingingCall();

    boolean endCall();

    void silenceRinger();

    boolean showCallScreenWithDialpad(boolean showDialpad);
}


이렇게 하면 에러 메시지가 사라진다.


블로그 이미지

Link2Me

,