출저  : http://www.crowbarsolutions.com/importing-libraries-into-android-studio/


IMPORTING LIBRARIES INTO ANDROID STUDIO

Not all Android libraries out there provide a Maven dependency to include it into your project. Sometimes you will just have to resort to the original method of just including the source code in your project.

For this example, I will be importing the SlidingMenu library for Android by Jeremy Feinstein.

First of all, allow me to illustrate the folder structure of your entire project:

importlibrary

To achieve this structure, you will have to create library folder in the root of your project, and import the code library you want to include into it as a module. Note that if the code library you are trying to import doesn’t already have abuild.gradle file, you may need to import it into Eclipse first and generate the necessary build.gradle file (as of writing this post, Android Studio is unable to generate build.gradle files for eclipse projects).

Next, based on the naming conventions I established in the image above ensure you have the following:

In your APP’s build.gradle file make sure you have:

dependencies {
    // Your other dependencies go here
    compile project(':libraries:SlidingMenu')
}

This tells Gradle that your App has a dependency on SlidingMenu.

In SLIDING MENU’s build.gradle file make sure it has the following:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.7.+'
    }
}

apply plugin: 'android-library'

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.android.support:support-v4:19.0.0'
}

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.1"

    defaultConfig {
        minSdkVersion 7
        targetSdkVersion 16
    }

    sourceSets {
        main {
            java.srcDirs = ['src/main/java']
            res.srcDirs = ['src/main/res']

            manifest.srcFile 'src/main/AndroidManifest.xml'
        }
    }
}

This tells Gradle how to compile and build the Sliding Menu module. We’re telling it that Sliding Menu depends on the Android V4 Support library, the SDK version target to build against, and finally, the folders paths where the source code, resources, and manifest files are located.

Your PROJECT’s settings.gradle file should look like this:

include ":libraries:SlidingMenu", ':App'

This tells Gradle the modules it should build for your entire project, and the order to do it in. Obviously we want to build Sliding Menu before we build our app, because Sliding Menu is a dependency and it expects it  to be already compiled.

In android studio press the Tools -> Android -> Sync Project with Gradle Files button, then rebuild your project. If all went well you should be able to import the com.jeremyfeinstein.slidingmenu.lib.SlidingMenu library into your app’s source files.


단계별 예제로 배우는 안드로이드 기초부터 중급까지.

http://kairo96.gitbooks.io/android/


쉽게 풀어쓴 딥 러닝의 거의 모든것

http://slownews.kr/41461


로보틱스와 머신러닝/인공지능 무료 교재 추천 15권

http://slownews.kr/36701


수학을 포기한 직업 프로그래머가 머신러닝 학습을 시작하기 위한 학습법 소개

http://www.moreagile.net/2015/05/how-to-start-machine-learning-study.html?m=1


수학공부 사이트 : 삶은 달걀

http://blog.daum.net/eigenvalue/9214797


SVM

http://www.statsoft.com/Textbook/Support-Vector-Machines

http://docs.opencv.org/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html


블로터 기사 - 요즘 뜬다는 '딥 러닝', 대체 그게 뭐지?

http://www.bloter.net/archives/201445



역시 잡스니깐 이런 이력서가 가능한 것 같다.

지금 당장은 이런 위트있고 자신감있는 이력서는 못 나오겠지만, 훗날 이런 커리어를 위트있게 쓸 수 있는 사람이 되어야 겠다.



이렇게 힘들게 자기 꿈을 위해 노력하는데, 나는 그저 배부른 소리만 하고 있었다.

































'유머' 카테고리의 다른 글

마이클 패러데이  (0) 2015.04.07
우리가 이상형을 못 만나는 이유  (0) 2011.06.16
컴퓨터 공학과의 현실  (1) 2011.05.14
키우던 가제가 죽어서 슬프단 말이야.  (0) 2011.04.17
대한민국 공대의 현실  (0) 2011.04.12

이클립스에서 안드로이드 SDK 업데이트를 한 후, Layout파일의 Graphical Layout 부분이 제대로 표시 되지 않는 문제가 발생했다.

Graphical Layout 하단에 다음과 같은 문구가 나옴.


This version of the rendering library is more recent than your version of ADT plug-in. Please update ADT plug-in.



안드로이드의 ADT를 업데이트하고 나면 간단하게 해결 됨.


  1. Click Help > Install New Software.
  2. In the Work with field, enter: https://dl-ssl.google.com/android/eclipse/
  3. Select Developer Tools / Android Development Tools.
  4. Click Next and complete the wizard.




1. Oracle

SELECT * 

  FROM [TABLE] 

  WHERE ROWNUM <= 10 


2. MSSQL

 SELECT TOP 10 * FROM [TABLE] 


3. MySQL

 SELECT * FROM [TABLE] LIMIT 0, 10




'데이터베이스' 카테고리의 다른 글

apmsetup7 설치 및 euc_kr 설정  (0) 2013.03.17
MySQL 5 설치하기  (2) 2009.05.31

1. 앱 소스에 Sender ID는 API Project의 프로젝트 번호 입력


2. API 및 인증 -> API에서 Google Cloud Messaging for Android API Enable


3. Google Developers Console 사이트에서 API 및 인증 -> 사용자 인증 정보 클릭

공개 API 액세스 -> 새 키 만들기 -> 서버키 생성


Authorization:key는 Google Developers Console 사이트에서 "서버 애플리케이션용 키" 생성해서 사용

구글서버에 저장하고 적용하는데 시간이 다소 소요된다.

서버키가 맞지 않을 경우 Android GCM Unauthorized 401 error with PHP 에러 발생






control + , or ESC : 자동완성

control + . : 자동완성 (목록을 보여주지 않는 형태로 다음 자동완성 문구를 입력해준다)

control + / : 자동완성 후 place holder 들 중 다음 place holder로 커서를 이동

shift + control + / : 이전 place holder로 커서 이동


option+command+up arrow: 소스 파일과 헤더 파일을 전환해준다.

command + [ : 선택된 텍스트 왼쪽으로 이동 (윈도우에서 보통 Shift+Tab으로 쓰이는 것)

command + ] : 선택된 텍스트 오른쪽으로 이동 (윈도우에서 보통 Tab으로 쓰이는 것)

command + F : 찾기

command + G : 다음 찾기 (윈도우에서 보통 F3이 많이 사용되는 것)

command + D : 북마크에 추가 

(북마크를 삭제하거나 이름을 바꾸고 싶으면 에디터 왼쪽에 Groups & Files 에 Bookmarks 항목에서 삭제하거나 이름을 바꿀 수 있다.)

shift + command + W: 현재 파일 닫기


command + B : 빌드

command + enter: 빌드 및 실행 (Build and Go)

command + \ : 브레이크포인트 (toggle breakpoint)

shift + command + I : Step Into

shift + command + O: Step Over

shift + command + T: Step Out


control + command + S: 스냅샷 만들기


attr android:activatedBackgroundIndicator 기본 색깔이 파란색으로 되어있는데 이 색깔을 변경하고 싶으면 Custom Style의 activatedBackgroundIndicator Attribute를 수정해야 한다. 

<style name="AppTheme" parent="@android:style/Theme.Holo.Light">
        <item name="android:activatedBackgroundIndicator">@drawable/list_activated_background</item>
</style>


drawable 리소스 폴더에 list_activated_background 파일 생성

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">  
   <item android:state_activated="true" android:drawable="@color/OrangeLight" />
   <item android:state_checked="true" android:drawable="@color/OrangeDark" />
   <item android:state_pressed="true" android:drawable="@color/OrangeDark" />
   <item android:drawable="@android:color/transparent" />  
</selector>


참조

http://stackoverflow.com/questions/19038322/change-color-of-androidactivatedbackgroundindicator






문제점

 아래처럼 소켓의 Connect 메소드를 사용할 경우 서버가 접속불가능한 상태에서는 Timeout 시간이 너무 길다. 

m_clientSocket.Connect(ipEnd);


해결방법

public static class SocketExtensions
{
    /// <summary>
    /// Connects the specified socket.
    /// </summary>
    /// <param name="socket">The socket.</param>
    /// <param name="endpoint">The IP endpoint.</param>
    /// <param name="timeout">The timeout.</param>
    public static void Connect(this Socket socket, EndPoint endpoint, TimeSpan timeout)
    {
        var result = socket.BeginConnect(endpoint, null, null);

        bool success = result.AsyncWaitHandle.WaitOne(timeout, true);
        if (success)
        {
            socket.EndConnect(result);
        }
        else
        {
            socket.Close();
            throw new SocketException(10060); // Connection timed out.
        }
    }
}


참조

http://stackoverflow.com/questions/1062035/how-to-configure-socket-connect-timeout



버터나이프 GitHub 사이트

https://github.com/inmite/android-butterknife-zelezny


How to install

  • in Android Studio: go to Preferences → Plugins → Browse repositories and search forButterKnife Zelezny

or

  • download it and install via Preferences → Plugins → Install plugin from disk


사용법

1. build.gradle에서 compile 'com.jakewharton:butterknife:6.1.0' 추가

 dependencies {

    compile fileTree(dir: 'libs', include: ['*.jar'])

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

    compile 'com.jakewharton:butterknife:6.1.0'

}


2. Edit창에서 오른쪽 버튼 클릭하고 Generate -> Generate ButterKnife Injections 클릭

혹시나 Generate ButterKnie Injections가 안보일 경우 컴파일 후 다시 시도.


Worker workerObject = new Worker(); Thread workerThread = new Thread(workerObject.DoWork); // Start the worker thread. workerThread.Start();

...

...

workerThread.Start(); <--- 오류 발생


오류 내용

 스레드가 실행 중이거나 종료되었습니다. 다시 시작할 수 없습니다. 


해결

 Thread는 한번 사용되면 재사용될 수 없다. 따라서 Thread 객체를 새로 생성해서 사용해야 된다.

참조 사이트

Displaying Bitmaps Efficiently

http://developer.android.com/training/displaying-bitmaps/index.html


출저 : http://www.androidpub.com/2426245



안드로이드 개발자 공식 사이트에 있는 트레이닝 세션을 번역해 보았습니다. 


http://yonght.tumblr.com/post/40418244176


트레이닝의 내용이 대체로 많이 쓰이고 좋은 내용이 많은 것 같아. 공부하면서 하나씩 올려보려고 합니다. 


안드로이드 앱을 만들 때 가장 많이 하는 일 중에 하나가 사진을 찍어서 올리거나 인터넷에 있는 사진을 받아다 사용자에게 보여주는 일입니다. 스마트폰이 가진 중요한 기능 중의 하나가 카메라가 내장되어 있다는 것이고 이것이 인터넷과 연결되어 다른 사용자들에게 쉽게 공유할 수 있다는 것이기 때문이죠. 그래서 모바일 앱의 주요 컨텐츠 생산이나 소비 형태도 사진으로 많이 이루어져 있습니다.

드로이드 개발자 공식 사이트에서도 상당히 앞쪽 부분에 사진을 다루는 비트맵에 대한 트레이닝 세션을 만들어 놓았습니다. 공부차 공식 블로그의 내용을 간단히 추려서 옮겨 봅니다. 원문과 샘플코드 다운로드는 Displaying Bitmaps Efficiently에서 보실 수 있습니다. 


출처: 안드로이드 개발 사이트(http://develper.android.com). 번역: 용현택


안드로이드에서 처음에 아무생각없이 Bitmap 오브젝트를 이용해 사진을 불러오려다. 

java.lang.OutofMemoryError: bitmap size exceeds VM budget

라는 메세지와 부딪히게 될 것이다. 당연히 메모리가 부족해서 나는 에러 이고 몇가지 이유가 있을 수 있는데 대강 다음의 이유로 뻗는 것이다. 

- 안드로이드 장비의 메모리는 무한정이 아니다. 안드로이드 장비가 하나의 앱에 허용하는 메모리는 16MB이하를 사용하도록 하고 있다. 대부분의 디바이스들에서는 16MB보다 높게 제한이 걸려있긴 하지만 이보다 작은 메모리를 사용하도록 최적화 해야 할 것이다. 따라서 이 제한을 넘게되면 에러가 난다. 

- 이미지는 메모리를 굉장히 많이 잡아 먹는다. 특히 요즘폰들은 화소가 높아서. 갤럭시 넥서스 같이 500만 화소 카메라로 찍게되면 2592*1936픽셀의 사진이 생겨나는데 ARGB_8888로 셋팅되어 있다면 한 픽셀당 4바이트를 사용해서 결과적으로 19MB를 차지하게 된다.한두장만 사용해도 장비의 메모리 제한은 가벼웁게 넘어버린다. 

- 여러개의 이미지를 한방에 로드하려는 경우가 많다. 예를들어 ListView나 GridView, ViewPager 같은 경우에는 한 화면에 여러개의 이미지를 보여주어야 하고 스크롤에 대비해서 미리 이미지들을 가지고 있어야 되는 경우도 많기 때문이다. 

그러면 큰 이미지를 어떻게 로드해서 화면에 보여주는게 효과적일지, 디스크나 인터넷으로 부터 비동기식으로 이미지를 받아와 처리하는 방법, 이미지를 캐싱하는 방법에 대해서 설명하도록 하겠다.

1. 큰 이미지를 (효율적으로)화면에 보여주자.

위에서도 얘기했지만 고해상도의 이미지를 불러와 그대로 메모리에 넣고 화면에 보여주는 것은 바로 OutOfMemory로 가는 지름길이다. 그러면 어떻게 할 것인가. 원래 이미지의 해상도와 상관없이 화면에 보여질 해상도 만큼 줄여서 읽어들이면 되지 않을까? 그러려면 원래 이미지의 해상도와 화면에 보이려는 ImageView의 해상도를 알아내어 품질을 떨어뜨리면 된다. 

읽어드리려는 이미지의 해상도를 알아내기 위해서는 BitmapFactory.Options의 inJustDecodeBounds = true로 셋팅해놓고 읽어 들이면 된다. 그러면 이미지를 메모리에 올려놓지 않고 해상도만 알아낼 수 있다. 다음의 코드를 보자. 

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

이미지를 메모리에 로드하지 않고 크기만 알아내는 코드이다. 여기서 decodeResource 함수는 decodeFile처럼 BitmapFactory.decode* 메소드들로 바꾸어서 쓸 수 있다. 이제 BitmapFactofy.Options의 inSampleSize 파라메터를 이용해서 이미지의 해상도를 줄일 수 있다. inSampleSize는 이미지의 몇분의 1로 해상도를 줄일지를 나타낸다. 예를들어 inSampleSize를 4로 셋팅하면 2048x1536의 이미지를 읽어들일 때 512*384로 1/4크기로 줄여들여 읽어들인다. 자 이제 다음 코드처럼 이미지를 보여줄 화면의 크기만큼 해상도를 떨어뜨려 읽을 수 있다. 

 // Get the dimensions of the View
int targetW = mImageView.getWidth();
int targetH = mImageView.getHeight();
  
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
  
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
  
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
  
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
mImageView.setImageBitmap(bitmap);

위와 같이 실제 이미지를 읽어들일 때는 inJustDecodeBounds를 false로 해둔다. inSampleSize의 경우 2의 배수로 사용할 경우 퍼포먼스가 가장 좋긴 하지만 퍼포먼스보다 메모리를 조금이라도 아끼는게 중요하니 2의 배수가 아니더라도 줄일 수 있으면 더 줄이는게 좋다. 

2. 멀티 쓰레드로 이미지를 읽어들이자. 

이미지를 디스크나 네트워크로 부터 읽어들일 때는 메인 UI 쓰레드에서 읽어들이면 안된다. 시간이 얼마나 걸릴지도 모르는 것이고 마냥 기다리게 되면 사용자가 터치를 해도 반응이 없어서 닫으려고 할 것이기 때문이다. 따라서 이미지를 읽어들이는 작업은 별도의 쓰레드에서 해야 하는데 가장 쉬운 방법은 AsyncTask를 이용하는 것이다. 

다음은 AsyncTask를 이용하여 이미지를 읽어들이는 예제이다. 

 class BitmapWorkerTask extends AsyncTask {
    private final WeakReference imageViewReference;
    private int data = 0;

    public BitmapWorkerTask(ImageView imageView) {
        // Use a WeakReference to ensure the ImageView can be garbage collected
        imageViewReference = new WeakReference(imageView);
    }

    // Decode image in background.
    @Override
    protected Bitmap doInBackground(Integer... params) {
        data = params[0];
        return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
    }

    // Once complete, see if ImageView is still around and set bitmap.
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (imageViewReference != null && bitmap != null) {
            final ImageView imageView = imageViewReference.get();
            if (imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}

별도의 쓰레드에서 진행되므로 작업중에 사용자가 다른창으로 이동하거나 할 수 있다. ImageView의 WeakReference를 가지고 있게하여 사용자가 다른창으로 이동하거나 하면 작업이 끝나지 않았더라도 ImageView가 가비지 콜렉팅되게 하였다. 다만 onPostExcute에서 WeakReference에서 ImageView를 가져와 ImageView가 아직 살아있는지 여부를 체크하게 하였다. 

이제 이미지를 별도의 쓰레드에서 비동기식으로 로딩하려면 다음과 같이 실행해주면 된다. 

public void loadBitmap(int resId, ImageView imageView) {
    BitmapWorkerTask task = new BitmapWorkerTask(imageView);
    task.execute(resId);
}

일반 뷰에서는 위와 같이 읽어 들이면 되지만 ListView나 GridView에서 사용하게 될 경우 문제가 발생하게 된다. ListView나 GridView는 메모리를 아끼기 위해 유저가 스크롤 하거나 할 때 이미 만들어 놓았던 뷰를 재활용하기 때문이다. 따라서 이미지 로딩 작업이 끝났을 때 업데이트 하려는 뷰가 이미 다른 이미지를 로딩하며 재활용된 뷰일 수도 있고 이미지 로딩이 언제 끝나느냐에 따라서 이미지를 업데이트 하는 작업이 꼬일 수도 있다. 

 Multithreading for Performance에서는 이 이미지 뷰를 가장 최근에 건드렸던 AsyncTask가 어떤 놈인지 기억해 두었다가 작업이 끝났을 때 그 AsyncTask가 가장 최근놈이 맞는지를 체크하는 방법으로 해결한다. 우리도 비슷한 방법으로 해결해 보자. 

아까 만들었던  workertask를 저장할 수 있는 Drawable클래스를 하나 만든다. 이경우에는 ImageView가 가지고 있는 BitmapDrawable을 사용할 거고 따라서 작업이 끝났을 때 ImageView는 자신이 갖고 있는 BitmapDrawable을 통하여 어느 workertask가 가장최근 놈인지 알 수 있다. 

static class AsyncDrawable extends BitmapDrawable {
    private final WeakReference bitmapWorkerTaskReference;

    public AsyncDrawable(Resources res, Bitmap bitmap,
            BitmapWorkerTask bitmapWorkerTask) {
        super(res, bitmap);
        bitmapWorkerTaskReference =
            new WeakReference(bitmapWorkerTask);
    }

    public BitmapWorkerTask getBitmapWorkerTask() {
        return bitmapWorkerTaskReference.get();
    }
}

그리고 BitampWorkerTask를 실행하기 전에, 타겟 ImageView를 가지고 있는 AsyncDrawable을 하나 만들거다. 

public void loadBitmap(int resId, ImageView imageView) {
    if (cancelPotentialWork(resId, imageView)) {
        final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
        final AsyncDrawable asyncDrawable =
                new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
        imageView.setImageDrawable(asyncDrawable);
        task.execute(resId);
    }
}

여기서 cancelPotentialWork 메소드에서 이미 다른 task가 ImageView를 참조하고 있고 돌아가고 있는지를 체크할 수 있다. 그래서 아직 돌고 있는 놈이 있으면 새로운 task를 실행하기 전에 돌고 있는 task를 cancel시켜 버린다. 다음은 cancelPotentialWork의 구현이다. 

public static boolean cancelPotentialWork(int data, ImageView imageView) {
    final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

    if (bitmapWorkerTask != null) {
        final int bitmapData = bitmapWorkerTask.data;
        if (bitmapData != data) {
            // Cancel previous task
            bitmapWorkerTask.cancel(true);
        } else {
            // The same work is already in progress
            return false;
        }
    }
    // No task associated with the ImageView, or an existing task was cancelled
    return true;
}

위의 코드에서 getBitmapWorkerTask() 메소드는 이 이미지뷰를 업데이트하기 위해 아직 실행중인 task를 리턴하는 메소드이다. 

private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
   if (imageView != null) {
       final Drawable drawable = imageView.getDrawable();
       if (drawable instanceof AsyncDrawable) {
           final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
           return asyncDrawable.getBitmapWorkerTask();
       }
    }
    return null;
}

마지막으로 작업이 끝나면 BitmapWorkTask에서 이미 cancel됐는지 여부를 체크하고 그렇지 않을 때는 업데이트 하도록 한다. 

class BitmapWorkerTask extends AsyncTask {
    ...

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled()) {
            bitmap = null;
        }

        if (imageViewReference != null && bitmap != null) {
            final ImageView imageView = imageViewReference.get();
            final BitmapWorkerTask bitmapWorkerTask =
                    getBitmapWorkerTask(imageView);
            if (this == bitmapWorkerTask && imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}

이제 뷰를 재활용하는 ListView나 GridView에서  있더라도 이 샘플을 사용할 수 있게 되었다. 이제 loadBitmap을 getView()와 같은 곳에서 콜해서 이미지를 로드하면 된다. 

3. 이미지를 캐싱하자.

ListView나 GridView, ViewPager에서는 보통 여러장의 이미지를 동시에 로딩하게 된다. 그리고 사용자가 스크롤을 하게 되면 그 중에 화면에 보이지 않게 되는 이미지의 뷰는 재활용 될 것이고, 메모리가 별로 없기 때문에(이것들이 메모리를 많이 차지하는 작업들이라..)  예전에 로딩된 이미지는 곧 가비지 콜렉팅 될 것이다. 그럼 매번 다시 스크롤해서 올라가고 하면 하게 될 때마다 예전에 불렀던 이미지를 새로 다시 로드하고 하게 하는건 네트웍이 느린 안드로이드 폰에서는 뻘짓이다.  그래서 메모리나 디스크에 캐싱하는 방법을 사용한다. 

- 메모리 캐시를 사용해보자

안드로이드에서는 LruCache를 제공한다. LruCache는 LinkedHashMap을 사용하여 최근에 사용된 object의 strong reference를 보관하고 있다가 정해진 사이즈를 넘어가게 되면 가장 최근에 사용되지 않은 놈부터 쫓아내는 LRU 알고리즘을 사용하는 메모리 캐시다. 예전에는 bitmap cache에 SoftReference나 WeakReference를 사용하는 방식을 썼으나 안드로이드 2.3부터 가비지 콜렉터가 공격적으로 이놈들의 메모리를 가비지 콜렉팅하면서 몹쓸 방법이 됐다.  게다가 이 방법은 3.0이전 버전에서 메모리 해제를 제대로 못해 크래쉬문제도 있다. 

그러니 LruCache를 사용하자. LruCache의 캐시사이즈를 정하기 위해서는 다음 요소들을 고려해야 한다. 

  • 우리 앱에서 앞으로 메모리를 얼마나 써야 되는가. 
  • 얼마나 많은 이미지들이 한 화면에 보일 것인가. 얼마나 많은 이미지들이 다음에 보여주기 위해 준비되어야 하는가. 
  • 화면 해상도가 어떻게 되는가. 
  • 각 이미지마다 메모리를 얼마나 차지하는가. 
  • 이미지는 얼마나 자주 액세스 되는가. 
  • 질보다 양? 양보다 질? 어떤 경우에는 많은 양의 저해상도 이미지를 미리 보여주고 백그라운드로 고해상도 이미지를 로드하는 방법이 좋을 수도 있다. 

딱히 어느정도 캐시사이즈가 적당한지 공식은 없고 앱의 메모리 사용량을 측정해보면서 적당히 정해야 한다. 당연한 말이겠지만 너무 사이즈를 작게하면 괜히 오버헤드만 발생하게 되고 사이즈를 너무 크게했다가 OutOfMemory Exception을 보게 될거다. 아래는 LruCache를 사용한 예제이다.

private LruCache mMemoryCache;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Get memory class of this device, exceeding this amount will throw an
    // OutOfMemory exception.
    final int memClass = ((ActivityManager) context.getSystemService(
            Context.ACTIVITY_SERVICE)).getMemoryClass();

    // Use 1/8th of the available memory for this memory cache.
    final int cacheSize = 1024 * 1024 * memClass / 8;

    mMemoryCache = new LruCache(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            // The cache size will be measured in bytes rather than number of items.
            return bitmap.getByteCount();
        }
    };
    ...
}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
    if (getBitmapFromMemCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }
}

public Bitmap getBitmapFromMemCache(String key) {
    return mMemoryCache.get(key);
}

이 예제에서 앱에서 사용하능한 메모리의 1/8을 캐시에 할당하였다. 일반적으로 hdpi 디바이스에서는 이 크기가 4MB(32/8)정도 된다. 800x480이미지가 1.5MB정도 되므로 GridView를 사용한다면 2.5 페이지의 이미지를 메모리에 캐싱할 수 있게 된다. 

이미지를 로드할 때 LruCache에서 먼저 찾아보고 있으면 그걸로 바로 업데이트 하고 아니면 백그라운드 쓰레드에서 로딩한다. 

public void loadBitmap(int resId, ImageView imageView) {
    final String imageKey = String.valueOf(resId);

    final Bitmap bitmap = getBitmapFromMemCache(imageKey);
    if (bitmap != null) {
        mImageView.setImageBitmap(bitmap);
    } else {
        mImageView.setImageResource(R.drawable.image_placeholder);
        BitmapWorkerTask task = new BitmapWorkerTask(mImageView);
        task.execute(resId);
    }
}

BitmapWorkerTask도 메모리 캐시를 사용하는 걸로 변경. 

class BitmapWorkerTask extends AsyncTask {
    ...
    // Decode image in background.
    @Override
    protected Bitmap doInBackground(Integer... params) {
        final Bitmap bitmap = decodeSampledBitmapFromResource(
                getResources(), params[0], 100, 100));
        addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
        return bitmap;
    }
    ...
}

- 디스크 캐시 이용하기

메모리 캐시는 빠르기는 하지만 메모리가 얼마 되지 않기 때문에 이것만 가지고는 부족하다. 그리고 전화가 오거나 하면 앱이 백그라운드로 가버리면서 캐시가 사라져 버리게 된다. 디스크 캐시를 사용하면 데이터가 지속적으로 남아있고 용량도 좀 더 많이 쓸 수 있다. 하지만 당연히 메모리 캐시보다 느리다. 그래도 네트웍에서 읽어들이는 것에 비하면 어딘가. 그리고 ContentProvider를 사용하는게 자주 액세스 되는 이미지를 캐시에 저장하기에 좋다. 아래 코드는 위의 메모리 캐시에 디스크 캐시를 추가한 버전이다. 

private DiskLruCache mDiskLruCache;
private final Object mDiskCacheLock = new Object();
private boolean mDiskCacheStarting = true;
private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
private static final String DISK_CACHE_SUBDIR = "thumbnails";

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Initialize memory cache
    ...
    // Initialize disk cache on background thread
    File cacheDir = getDiskCacheDir(this, DISK_CACHE_SUBDIR);
    new InitDiskCacheTask().execute(cacheDir);
    ...
}

class InitDiskCacheTask extends AsyncTask {
    @Override
    protected Void doInBackground(File... params) {
        synchronized (mDiskCacheLock) {
            File cacheDir = params[0];
            mDiskLruCache = DiskLruCache.open(cacheDir, DISK_CACHE_SIZE);
            mDiskCacheStarting = false; // Finished initialization
            mDiskCacheLock.notifyAll(); // Wake any waiting threads
        }
        return null;
    }
}

class BitmapWorkerTask extends AsyncTask {
    ...
    // Decode image in background.
    @Override
    protected Bitmap doInBackground(Integer... params) {
        final String imageKey = String.valueOf(params[0]);

        // Check disk cache in background thread
        Bitmap bitmap = getBitmapFromDiskCache(imageKey);

        if (bitmap == null) { // Not found in disk cache
            // Process as normal
            final Bitmap bitmap = decodeSampledBitmapFromResource(
                    getResources(), params[0], 100, 100));
        }

        // Add final bitmap to caches
        addBitmapToCache(imageKey, bitmap);

        return bitmap;
    }
    ...
}

public void addBitmapToCache(String key, Bitmap bitmap) {
    // Add to memory cache as before
    if (getBitmapFromMemCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }

    // Also add to disk cache
    synchronized (mDiskCacheLock) {
        if (mDiskLruCache != null && mDiskLruCache.get(key) == null) {
            mDiskLruCache.put(key, bitmap);
        }
    }
}

public Bitmap getBitmapFromDiskCache(String key) {
    synchronized (mDiskCacheLock) {
        // Wait while disk cache is started from background thread
        while (mDiskCacheStarting) {
            try {
                mDiskCacheLock.wait();
            } catch (InterruptedException e) {}
        }
        if (mDiskLruCache != null) {
            return mDiskLruCache.get(key);
        }
    }
    return null;
}

// Creates a unique subdirectory of the designated app cache directory. Tries to use external
// but if not mounted, falls back on internal storage.
public static File getDiskCacheDir(Context context, String uniqueName) {
    // Check if media is mounted or storage is built-in, if so, try and use external cache dir
    // otherwise use internal cache dir
    final String cachePath =
            Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
                    !isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :
                            context.getCacheDir().getPath();

    return new File(cachePath + File.separator + uniqueName);
}

메모리 캐시에서의 로딩은 메인 쓰레드에서 진행된 반면 디스크 캐시는 백그라운드 로딩을 사용하였다. 디스크 작업은 언제 끝날지 모르므로 백그라운드를 사용하자. 그리고 이미지 프로세싱이 끝나면 메모리 캐시에도 업데이트를 해주었다.

=======================================================

이상입니다.  나머지 부분은 위에서 만든 코드를 실제 GridView나 ViewPager에 적용하는 내용인데 이건 직접 해보시면 될 것 같습니다. 사실 이 부분은 많이 쓰이는 부분이기 때문에 구글에서 검색하면 수많은 오픈소스를 만나실 수 있습니다.

오픈소스를 사용하셔도 되지만 위의 샘플코드를 가져다가 쓰는게 그렇게 어렵지 않고 또 이미 이해한 코드이기 때문에  커스터마이즈 하기도 좀더 수월하지 않을까 싶습니다. 또 위의 내용을 읽다보면 안드로이드가 이미지(비트맵)을 다루는 다양한 방식과 한계에 대해서도 이해하게 되는 부분이 있으리라고 생각합니다. 도움이 되셨길 바랍니다.

 웹서핑을 하다가 "성공한 사람들이 출근전 반드시 하는 7가지" 라는 글을 읽게 되었다.

나의 경우에는 아침에 일찍 일어나기가 정말 쉽지 않은데, 대부분의 성공한 사람들은 아침에 일찍 일어나 여러가지 일들을 수행한다고 한다. 다른 사람들에 비해 하루를 더 길게 사용한다는 의미이다. 그래서 더 많은 일들을 하게 되고, 좋은 결과를 얻게되어 성공한 게 아닌가 싶다.



출저 : http://dailygrim.tistory.com/m/post/180


BitmapDrawable d = (BitmapDrawable)((ImageView) findViewById(R.id.뷰이름)).getDrawable();

Bitmap b = d.getBitmap();


 Bitmap형식의 b로 받아온다.

 소싯적부터 봐왔던 마소잡지 인터뷰 내용입니다.

마소 2014년 12월호에 실렸습니다. ㅎㅎㅎ 게을러서 이제서야 올리네요.



마소 대문에도 나오다니. 진짜 가문의 영광입니다. 




인터뷰 내용

http://www.imaso.co.kr/news/article_view.php?article_idx=20141124135414




WeakReference


약한 참조. 어떤 객체에 대한 참조가 WeakReference 밖에 남아있지 않으면, 그 객체는 GC의 대상이 된다.


SoftReference


WeakReference 보단 강한 참조. 기본적으로 WeakReference와 동일. 하지만 메모리의 남은 공간이 넉넉하다면 GC의 대상이 되지 않는다.



WeakReference  용어 그대로 약한 레퍼런스이다. 메모리 관리를 위해 고안된것으로 레퍼런스를 WeakReference로 하면 gc에 해당 레퍼런스가 관여되지 않는다.
private WeakReference<Launcher> mLauncher; // 변수선언
void setLauncher(Launcher launcher) {
    mLauncher = new WeakReference<Launcher>(launcher); // 참조를 WeakReference로 저장함.

}
if (mLauncher != null) {

    final Launcher launcher = mLauncher.get(); // 사용 시에는 get을 호출하여 null을 반드시 체크하여 사용

        if (launcher != null) {

            launcher.loadWallpaper();

        }

    }


참고로, 강제로 GC시키는 방법은
System.gc();

출저 : http://androidanddevelop.blogspot.kr/2012/09/android-memory-weakreference.html





학벌 안좋다고 불평하고 그들과 동일한 대우를 바라는 것은 역차별이다.

현실에 대한 불만만으로는 아무것도 극복할 수 없으며, 그들보다 두 배로 더 노력하면 된다.


나도 지방대 출신이지만 김봉진 CEO 말에 적극 동감한다.

그들이 좋은 대학에 가기 위해 노력한 부분에 대해 부정해서는 안되며, 사회에서는 그런 부분들이 인정되기 때문에 성공의 기회가 더 많이 주어지는 것 같다. 우리 같은 사람들은 성공하기 위해서는 엄청난 노력을 해야된다. 


바쁘게 산다고 블로그를 2년정도 방치해두었다 ㅠ

사실 핑계이긴 하지만 페이스북, 에버노트 같은 서비스들이 생기면서 자연스레 블로그를 안하게 된 것 같은데.

사실 이런 서비스들 때문에 블로그를 할 이유가 없어진게 가장 큰 이유인 듯 하다.

앞으로는 나만의 지식 창고 및 디지털 일기장의 목적으로 블로그를 꾸준히 사용해야 겠다.



HashMap은 HashTable과는 다르게 Thread-safe하지 않다.
그래서 put이나 get을 사용할 때 명시적으로 동기화를 시켜주어야 한다.
하지만 Collections.SynchronizedMap()이라는 메소드로 thread-safe하게 만들 수 있다.

이 경우에,
Simple operation (put, get) 등은 synchronized로 감싸주지 않아도 된다.
하지만 iterator를 사용해서 탐색을 할 경우에는 따로 명시적으로
Synchronized를 써주어야 한단다.

Map m = Collections.synchronizedMap(new HashMap());
      ...
  Set s = m.keySet();  // Needn't be in synchronized block
      ...
  synchronized(m) {  // Synchronizing on m, not s!
      Iterator i = s.iterator(); // Must be in synchronized block
      while (i.hasNext())
          foo(i.next());
  }

http://java.sun.com/javase/6/docs/api/java/util/Collections.html#synchronizedMap(java.util.Map)



android studio compilesdkversion android-21 requires compiling with jdk 7


JDK, JRE 7이상 버전 깔고 

JDK 위치 변경

/Library/Java/JavaVirtualMachines/jdk1.7.0_60.jdk/Contents/Home


1. http://www.apmsetup.com 에서 apmsetup7 을 다운받는다.

 

2. 설치경로를 설정후 설치한다.

 

3. \APM_Setup 의 php.ini 세팅

    -> default_charset = "euc_kr"     (주석풀고)

   

4. \APM_Setup\Server\MySQL5\data\my.ini  를 \APM_Setup\Server\MySQL5 로 복사

    -> 원래 my.ini 파일 위치가 잘못 되었다함...(한글깨짐 현상이 이문제 때문이었다함.)

 

5. my.ini 설정

    -> 여기 첨부파일(my.ini)복사 덮어쓰기 (\APM_Setup\Server\MySQL5 폴더에)

 

6. \APM_Setup\Server\Apache\conf\httpd.conf 설정

    -> 맨 밑에 #Include conf/extra/httpd-languages.conf 주석해제

 

7. \APM_Setup\Server\Apache\conf\extra\httpd-languages.conf 설정

    -> 여기 첨부파일(httpd-languages.conf)복사 덮어쓰기

 

8. http://localhost/myadmin/ 접속

    -> id : root    pw : apmsetup

    -> mysql 데이터베이스의 user 테이블 패스워드 변경

    -> 브라우져 닫고 아파치, mysql 서버 재시작

    -> http://localhost/myadmin/ 변경한 비번으로 다시접속

    -> 사용자 디비 추가

  

9. 사용자 소스 설치 \APM_Setup\htdocs 폴더에...



http://blog.naver.com/PostView.nhn?blogId=mirazi9&logNo=140138890762


'데이터베이스' 카테고리의 다른 글

데이터베이스별 TOP 10개만 가져오는 쿼리문  (0) 2015.03.30
MySQL 5 설치하기  (2) 2009.05.31


string -> int

String s = "0";

int i = Integer.parseInt(s);



Int -> String

int i = 0;

String s = Integer.toString(i);



-----------------------------------------------------------------------------------------------------------

추가 팁 

int - String 하기 전에 아래 함수를 공통 함수에 넣어놓고 미리 체크하면 예외 발생을 막을수 있음 


public boolean isNumber(String number){  

if (number == "") { 

      return false; 

for (int i = 0; i < number.length(); i++) { 

if (!Character.isDigit(number.charAt(i))) { 

return false; 

    } 

return true; 


String - int 가 질 기억 안난다면 추천하고 싶진 않지만.. 


int i = 0; 

String s = i + "";



위의 팁 처럼 

예외를 막기위해 체크 해줘야 합니다+ㅁ+ㅋ 

그렇지 않으면 java.lang.NumberFormatException: For input string: 의 예외가 나지요~~ 

 if(!newTemp.equals(null)){  // 이 부분에서 나는 것이였다. 

              // 널 체크 추가!! 

            newNumTemp = Integer.parseInt(newTemp); 

            System.out.println("#####newNumTemp="+newNumTemp+"#####"); 

            if(newNumTemp > 0){  // 이것도 추가 해주었다 ㅋ 

                newRegi = (newNumTemp)+1; 

                System.out.println("#####newRegi="+newRegi+"#####"); 

              } 

 } 


이런식으로 체크 해주면 됩니당~^^*

'Java' 카테고리의 다른 글

SynchronizedMap을 통한 thread-safe HashMap 구현  (0) 2015.01.23


'유용한 정보' 카테고리의 다른 글

SVN 사용법 정리  (0) 2015.11.19
DVI 단자 모양  (0) 2013.02.17
인간승리  (0) 2011.09.06
30 Inspiring "About Me" Pages  (0) 2011.09.04
에빙하우스의 망각 곡선  (0) 2011.05.06

요코하마 아카렝카 창고로 가기 위해서 다시 전철을 탔다. 전철 플랫폼이 엄청 넓고 깨끗했다.
(원래 코스모월드 갈 생각이 없었는데, 가는 길에 보이길래 ㅋㅋ 즐겼다.)


여긴 여성 전용 칸이지만 아침에만 적용되는 거라 그냥 탔다 ㅋ
 


하지만 이 칸에 남자는 나 포함해서 2~3명 ㅋㅋ 진짜 여자들만 있다.
 

전철에서 내리니 바로 Queen’s Square가 나왔다. 이 건물 진짜 어마어마하게 크던데.
지상 복합 센터인 듯, 나는 쇼핑에는 별 관심이 없어서 재빠르게 여길 빠져 나왔다. 사람이 너무 많으면 피곤해진다.





밖을 빠져 나오려고 하는데, 시각장애인 가수가 공연을 하고 있었다. 무슨 자선행사 인 듯 보였다.

퀸즈 광장을 지나서 아카렝가 창고로 가는 길에 어마어마한 대관람차가 눈 앞에 ㅋㅋ
저거 꼭 타보고 싶어서 무작정 코스모월드에 입장ㅋㅋ
 

가까이서 본 대관람차. 실제로 보면 진짜 어마 어마 하다.
중간에 대관람차를 가로 지르는 롤러코스터. 이것도 탔는데 나는 정말 이런 중력이 느껴지는 놀이기구는 못 타겠다. ㅠ

코스모월드 상점(?). 코스모월드 내부는 그래 크지가 않다. 대관람차만 어마어마하게 크다.ㅋㅋ
 

1번으로 롤러코스터를 타고.. (너무 긴장하고 정신이 없어서 롤러코스터 사진은 없음 ㅋㅋㅋ)
그 다음으로 대관람차를 탔다. 이것도 은근히 무서웠다.


높은 곳에 올라가니 표정도 굳었음 ㅋㅋㅋ


요코하마시가 한눈에 다 드려다 보여서 좋았다. 날씨만 좀 더 좋았으면 사진도 잘나오고 좋았을 텐데. 아쉬웠다.










대관람차 관광을 끝내고 탄 놀이기구. ㅋ저거 이름이 뭔지 모르겠다.
그냥 제일 기억에 남는 건 저 구간이 미친듯이 아찔했다 ㅋㅋ 눈으로 볼 때는 탈만 할 줄 알았는데.
실제로 타보니깐 이것도 ㅋ못 타겠다. ㅋ

 

요코하마로가는 전철 안. 이 날 사람이 많아서 서서 갔다. 큰 맘먹고 가는 요코하마인데 비가 오다니 ㅠ
resizing_P1000779

비가 와서 날씨가 좋지 않다.
resizing_P1000783

요코하마 도착! 요코하마에서 점심때 까지 차이나타운에 있을 계획이다.
차이나타운으로 가기 위해서 지하철을 탔다. 일본 교통비는 너무 비싼 것 같다. ㅠ
resizing_P1000787resizing_P1000788

금요일 오전이라 그런지 지하철 안에 사람들이 별로 없다.resizing_P1000791

차이나타운 도착! 지하철 내려서 조금만 걸어가면 나온다.resizing_P1000801

일본에서 제일 큰 차이나타운이라는데, 생각보다 크진 않았다. 근데 건물 양식이나 냄새가 진짜 ㅋㅋ중국에 온듯한 느낌?
가게 운영하는 사람들이 전부 중국인 듯 했다. 관광객들 중에 한국인들도 여럿 본 듯하다.
resizing_P1000802

일단 눈에 제일 띄는 상점으로 들어 가자~~
resizing_P1000803resizing_P1000804

삼국지에서 내가 제일 좋아하는 관우 횽..resizing_P1000805

대륙의 도자기 앞에서 사진찍기 ㅋㅋ
resizing_P1000806

중국 특산물 보단, 요코하마 특산물이 엄청 많았는데 가격이 너무 비싸서 사진 못했다. 요코하마 카레랑 치즈 사고 싶었는데 ㅠ
resizing_P1000807resizing_P1000808

무슨 한자인지는 모르겠지만 중국 느낌 나는 관문(?)
저길 지나면 서로 자기 집에서 먹으라고 중국인들이 호객행위를 한다.
resizing_P1000809
resizing_P1000810

resizing_P1000811


차이나타운에 한국 음식점이 ㅋㅋ
resizing_P1000812


다들 저기서 사진 한장씩 찍고 가길래 나도 한장 ㅋㅋ
resizing_P1000813


멀리 보이는 China Museumㅋ 귀찮아서 안에 들어가보진 못했다.
resizing_P1000814

배가 너무 고파서 일 인당 1980엔 하는 중국집 뷔페에 가버렸다. 진짜 뽕을 뽑자는 생각에 엄청 시켰다. 배가 터질 정도로 시켰다. 토할 정도로 시켰다. 근데 ㅋㅋ이 망할놈의 중국 식당.. 뭔가 모르게 주문할 때마다 웨이터 표정이 안 좋았는데.. 남긴 음식에 대해서 추가 요금을 내란다.
정말 입맛에 안 맞아서 남 긴건데 ㅠ 요코하마에서 제일 기분 나쁜 경험 ㅋㅋㅋ
resizing_P1000815resizing_P1000816resizing_P1000817resizing_P1000820resizing_P1000821resizing_P1000822resizing_P1000823resizing_P1000824resizing_P1000825resizing_P1000826resizing_P1000827

이 많은 걸 어떻게 처리해야 되나 고민하는 표정.
진짜 맛 없었다 ㅋㅋㅋ 처음 몇 개는 엄청 맛있었는데, 지금 생각해보면 배가 엄청 고파서 맛있게 느껴진 듯.

resizing_P1000829

기분 나쁜 경험을 뒤로하고, 다시 출발!
가는 길에 뭔가 사원이 나왔다. 가서 보니 관우 횽을 모시는 곳인 듯.
중국에서는 관우 장군을 신으로 모신다고 하던 데 그 이야기가 거짓말이 아닌 듯 했다.

resizing_P1000837resizing_P1000838resizing_P1000842resizing_P1000844resizing_P1000845

나도 관우 형님 모시는 사원 앞에서 사진 한 장 남겼다.
요코하마 차이나 타운 편 마침.

resizing_P1000848

 

저녁에 집 밖에 급히 나가는데 공터에서 유치원 축제를 하고 있었다 ㅋㅋ
정확히 뭔 축제인지는 모르겠네. 행렬에 껴서 같이 놀고 싶었지만 비도 오고 약속도 있고 해서 그냥 지나치면서 사진 몇 장 찍었다.




+ Recent posts