프로젝트의 시간이 길어질 수록 사용하지 않는 resource가 많아지는 문제가 있습니다.

리펙토링 하면서 이전 리소스에 대해서 지울 수도 있지만, 명시적으로 지워준다면 id를 만들지 않기 때문에 더 좋을 수도 있죠.

build.gradle 에서

android {
    buildTypes {
        release {
            shrinkResources true
        }
    }
}

으로 빌드시에 resource정리를 하는 방법도 있지만, 명시적으로 지우는 것을 해볼까 합니다.

android studio 에서 Refactor -> Remove Unused Resources... 라는 메뉴가 있습니다.

해당 기능을 통해서 layout, string, drawable, color, dimen 등등 사용하지 않는 resource를 지울 수 있습니다.

단, 문제가 하나 있는데,

dynamic resource로 접근하는 부분에 대해서는 걸러주지 않습니다.

그 부분을 해결하기 위해서는

resource 유지를 위해서 keep 처리를 해야 하는데, tools:keep 을 적용하면 됩니다.

예를 들어서, resource.getIdentifiericon_position_의 prefix로 되는 resource들을 다 유지하고 싶다면,

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" 
    tools:keep="@drawable/icon_position_*">
</resources>

으로 xml resouce파일을 만들어서 관리하면 됩니다. 이 방법은 shrinkResources 로 dynamic resource에 접근하는 것들에 대한 유지 방법과 같습니다.

android개발하다 보면 onActivityResult로 결과를 받아오는 경우가 많습니다.

A activity에서 B activity로 startActivityForResult 로 호출 후, B activity에서의 결과를 onActivityResult로 받게 되죠.

그런데, 

implementation 'androidx.activity:activity-ktx:1.2.0-alpha04'
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha04'

에서 다른 기능이 생겼습니다.

호출과 동시에 lambda function으로 다로 onActivityResult로 결과를 받지 않아도 됩니다.

 

일반적인 방법으로는

Intent(this@MainActivity, SubActivity::class.java).run {
                            startActivityForResult(this, REQUEST_CODE_SUBACTIVITY)
}

와 같은 방법으로 호출하면,

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    when (requestCode) {
        REQUEST_CODE_SUBACTIVITY -> {
            if (resultCode == Activity.RESULT_OK) {
                val resultValue = data?.getStringExtra("result") ?: ""
                binding.textCallback.text = resultValue + " Normal"
            }
        }
    }
 }

와 같이 결과를 받습니다.

 

그런데, activity-ktx:1.2.0-alpha, fragment-ktx:1.3.0-alpha에 추가된 방법으로 한다면

registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
                    when (it.resultCode) {
                        Activity.RESULT_OK -> {
                            val resultValue = it.data?.getStringExtra("result") ?: ""
                            textCallback.text = resultValue + " KTX"
                        }
                        Activity.RESULT_CANCELED -> {
                        }
                    }
                }.launch(
                        Intent(this@MainActivity, SubActivity::class.java)
                )

와 같이 진행할 수 있습니다.

onActivityResult의 override된 mehtod로 결과를 받지 않아도... 간결화된 코드로 가독성이 좋아졌다고 볼 수 있습니다.

 

StartActvityForResult이외에

StartActivityForResult
StartIntentSenderForResult
RequestMultiplePermissions
RequestPermission
TakePicturePreview
TakePicture
TakeVideo
PickContact
GetContent
...

 

 

얼마전 제 블로그의 포스트에서 Dagger2를 이용하는 방법을 간단하게 적어보았습니다.

Android 개발에서 Dagger2이용해보기.

그런데 여기서 @Scope에 대한 설명이 없었던 것 같습니다.

@Scope ... 실질적으로는 Dagger2에서는 @Singleton annotation을 많이 사용합니다. Singleton은 굳이 자세히 설명을 안해도 다들 잘 알고 계시리라 봅니다. 객체 주입에서 @Singleton annotation을 적용해 두면.. 전체 App의 Scope안에서 Singleton객체가 생성되어 주입 됩니다. 그렇다면 다른 custom scope는 없을까요? 물론 @Scope annotation의 custom을 만들어서 사용합니다. 예를 들어서 Activity life cycle에서만 존재할 수 있는 객체 주입을 위해선 @PerActivity라던지 아니면 fragment life cycle에서만 객체 주입이 유지될 수 잇는 @PerFragment같은 custome scope annotation을 만들어 사용할 수 있습니다.



http://fernandocejas.com/wp-content/uploads/2015/04/composed_dagger_graph1.png


그럼 @Scope 를 이용한 예를 들어 볼 까 합니다.

이전에 예를 들었던 포스트인

Fragment에서 onActivityResult 결과 받기.

의 내용을 Dagger2를 이용한 방법으로 변경할려고 합니다. 주된 내용은 기존의 내용에서 EventBus객체를 Singleton pattern으로 생성해서 사용했습니다. 그럼 Dagger2를 이용해서 해당 샘플을 변경하면 어떻게 될까요?

우선 EventBus.java 입니다.

public class EventBus extends Bus {
private Handler handler = new Handler(Looper.getMainLooper());
@Override
public void post(final Object event) {
if (Looper.myLooper() == Looper.getMainLooper()) {
super.post(event);
} else {
handler.post(new Runnable() {
@Override
public void run() {
EventBus.super.post(event);
}
});
}
}
}

보시는 것과 같이 일반 객체와 별 다를 게 없습니다.


그럼 EventBusModule.java 입니다.

@Module
public class EventBusModule {
@Singleton
@Provides
EventBus provideEventBus() {
return new EventBus();
}
}

해당 모듈에서 EventBus를 제공해줄 때 @Singleton annotation이 붙었습니다. 이건 해당 객체를 Singleton으로 제공해 준다는 겁니다.


그리고 EventBusModule의 객체를 Inject를 하기 위한 Bridge역활을 해주는 ApplicationComponent.java 입니다.

@Singleton
@Component(
modules = {
ApplicationModule.class,
EventBusModule.class
}
)
public interface ApplicationComponent {
EventBus getEventBus();
}

해당 Component도 @Singletone으로 적용해두었습니다.


해당 Component자체도 Singleton scope에서 사용하겠다는 내용 입니다.


만약 Activity life cycle에서만 사용할 수 있는 scope를 만든다면

@Scope
@Retention(RUNTIME)
public @interface PerActivity {
}

로 만든다면 원하는 scope에다가 @PerActivity annotation을 적용하면 됩니다.


예제는..

https://github.com/drcarter/RetriveActivityResult 에서 retrive_activity_result_dagger 브랜치를 보시면 됩니다.

https://github.com/drcarter/RetriveActivityResult/tree/retrive_activity_result_dagger

안드로이드 앱을 개발하다보면 logcat에서 많이 접하게 되는 오류중에 하나가 

java.lang.OutOfMemoryError: bitmap size exceeds VM budget

이 오류이지 않을 까 합니다. 쉽게는 메모리 오류.  앱에서 사용할 수 있는 메모리보다 bitmap을 사용하는데 메모리를 많이 사용하게 되어서 나타나는 오류입니다. 예를 들어서 메모리를 20mb를 사용할 수 있는데 bitmap을 로드할 때 사용할 사용한 메모리가 20mb를 넘어선 것이지요. 그럼 이 상황을 해결할 방법은 어떤게 있을까요?? 


1. sampling option 및 서버에서의 작은 이미지 내려주기.

[BitmapFactory.Options.inSampleSize]

inSampleSize 옵션은, 애초에 decode를 할 때 얼마만큼 줄여서 decoding을 할 지 정하는 옵션 입니다.

inSampleSize 옵션은 1보다 작은 값일때는 무조건 1로 세팅이 되며, 1보다 큰 값, N일때는 1/N 만큼 이미지를 줄여서 decoding 하게 됩니다.

즉 inSampleSize가 2라면 1/2 만큼, 4 이면 1/4만큼 이미지를 줄여서 decoding 해서 Bitmap으로 만들게 주게 됩니다.

decoding의 속도는 2의 지수만큼 비례할 때 속도가 빠르다고 합니다. 


저같은 경우는 Bitmap이미지의 크기가 특정 크기를 넘어가면 inSample옵션을 주어서 이미지의 크기를 줄여서 로드하는 방법을 사용했습니다.

public int inSampleSize

Added in API level 1

If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1. Note: the decoder uses a final value based on powers of 2, any other value will be rounded down to the nearest power of 2.


BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap src = BitmapFactory.decodeFile(imagePath, options);


이렇게 BitmapFactory.Options.inSampleSize의 옵션을 사용하는 방법도 있겠지만, 서버에서 이미지를 처음부터 작게 내려주는 것도 방법일겁니다. 만약 thumbnail이미지의 사이즈가 좀 크다 싶으면 서버 개발자와 상의해서 thumbnail이미지를 작게 하는 것도 좋은 방법이겠지요.


2. recycle잘하기.

Bitmap을 recycle을 해야 하는 이유에 대해서는 우선 Android 3.0 (HoneyComb) 이전과 이후의 메모리 모델에 대해서도 이해를 해야 합니다. 간단하게 3.0 이전.. Gingerbread까지는 Bitmap에 Dalvik heap 영역에 bitmap에 로드되지 않고 native heap 영역에 bitmap에 로드 되었습니다. 그래서 GC(Garbage Collection)이후에도 native heap 영역에 로드된 bitmap은 아직 메모리에 해제 되지 않습니다. HoneyComb 부터는 Dalvik heap 영역에 bitmap이 로드되기 때문에 GC 이후에 해제 됩니다. 그럼 Gingerbread까지는 그래서 bitmap에 대해서 recycle을 해줘야 합니다.


- Bitmap 자체가 멤버변수로 된 경우

public class activity extends Activity
{
	ImageView iv;
	Bitmap bitmap;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		iv = (ImageView) findViewById(R.id.imageview);
		bitmap = BitmapFactory.decodeResource(R.drawable.icon);

		iv.setImageBitmap(bitmap);
	}

	@Override
	protected void onDestroy()
	{
		bitmap.recycle();
		bitmap = null;

		super.onDestroy();
	}
}


- ImageView 자체에서 instance를 확인할 경우.

public class activity extends Activity
{
	ImageView iv;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		iv = (ImageView) findViewById(R.id.imageview);
		iv.setImageBitmap(BitmapFactory.decodeResource(R.drawable.icon));
	}

	@Override
	protected void onDestroy()
	{
		Drawable d = iv.getDrawable();
		if (d instanceof BitmapDrawable)
		{
			Bitmap bitmap = ((BitmapDrawable) d).getBitmap();
			bitmap.recycle();
			bitmap = null;
		}
		d.setCallback(null);

		super.onDestroy();
	}
}


3. memory leak 확인하기.

개발 중 메모리릭이 생기는지 안생기는지에 대해서 확인해 보는 방법도 있습니다.

adb shell dumpsys meminfo [packagename]

을 하면 아래와 같은 결과가 출력 됩니다. Pss total은 공유되는 메모리를 포함한 크기이고, Private Dirty는 다른 프로세스와는 공유할 수 없는 메모리(페이지) 크기라는 것. 여기서 Private Dirty는 다르게 생각 해 보면, 이 프로세스가 제거되고나면 바로 반환되어 시스템이(또는 다른 프로세스가) 사용할 수 있는 메모리라고 생각 할 수도 있습니다. 

자게한 내용은 

Android Memory Management: Understanding App PSS

에서 보면 확인해 볼 수 있습니다.



다른 방법으로는 DDMS를 이용하는 방법입니다.

DDMS에서 Heap 영역의 변화를  확인해 볼 수 있습니다.


이외에 hprof 파일 분석을 통한 방법으로 memory leak 을 확인해 볼 수 있는데, 이에 대한 내용은.

제 다른 글 내용인 [Android]ANDROID PERFORMANCE OPTIMIZATION 에서 확인해 보실 수 있습니다.

Android에서 보통 support-v4 library를 많이 사용하죠. ViewPager와 Fragment등등 때문에...

그런데 이번에 ActionBar를 하위 버전에서 사용할 수 있도록 suppert-v7이 변경되어서 나왓습니다.

google에서 가면 갈수록 api가 상위버전에서만 사용할 수 있는 것들을 하위 버전에서 사용할 수 있도록 해주니 좋긴 좋군요. 그런데 하위버전에서 안되서 기존의 있는 sdk를 이용하여 custom하게 만들어서 사용하던 분들은 약간의 짜증?? 이 날 수도 있겠죠 ㅋㅋ 저같은 경우는 ViewPager가 안나왔을 때 ViewPager와 같은 기능을 만들어서 잘 사용하고 있더니 suppert-v4에 ViewPager를 넣어서 내놓더군요..... 욕심에 제가 만든걸 잘 사용하다가 결국엔 ViewPager로만 사용하게 되었던 ^^


자 그럼 ActionBar를 사용하기 위한 suppert-v7의 이용 방법 입니다.


전 eclipse 3.7 Indigo와 ADT 21을 이용합니다. 현재 eclipse는 4.3 kepler가 최신이고, ADT는 22입니다. 


1. Android SDK Manager를 이용하여 Android Suppert Library를 rev.18로 업데이트 한다.

2. Android Project from Existing Code

3. suppert-v4 하위에 있는 appcompat library 프로젝트 추가.

 - SDK가 설치된 하위 폴더의 extra->android->compatibility->v7->appcompat 추가.

   ex)/Volumes/Macintosh DATA/03.sdk/android-sdk-macosx/extras/android/compatibility/v7/appcompat


4. 추가된 부분 확인 - 아래 그림과 같이 support-v7-appcompat의 library프로젝트가 추가된 것을 확인할 수 있습니다.

5. Sample Project만들기.

 - 간단한 샘플 프로젝트를 만든 뒤 Properties->Android->Library에서 좀전에 추가한 support-v7-appcompat프로젝트를 추가합니다. 그리고 Project Build Target은 4.1.2 (API 16)이상으로 해야 합니다. suppoert-v7-appcompat이 4.1.2(API 16)으로 되어 있기 때문에...


6. AndroidManifest.xml의 Theme변경

android:theme="@style/AppTheme" -> android:theme="@style/Theme.AppCompat"

으로 변경합니다. 어떤 구조로 되어 있는지는 suppert-v7-appcompat의 resource인 themes.xml파일을 살펴보시면 됩니다.


7. ActionBarActivity 

import android.support.v7.app.ActionBarActivity;

public class MainActivity extends Activity -> public class MainActivity extends ActionBarActivity

으로 변경


8. menu 추가

 - ActionBarCompat용 menu리소스를 추가 합니다. 기존과 틀린점이 있다면 xmlns:action_sample="http://schemas.android.com/apk/res-auto" 의 action_sample namespace입니다. 하위 아이템을 보면 [action_sample:showAsAction="always" ]의 추가된 namespace로된 속성값이 있습니다. ActionBarCompat의 namespace로 온 속성을 사용하기 위함입니다.

- action.menu.xml 내용




android:id="@+id/menu_sample"
android:title="@string/action_sample"
android:icon="@drawable/ic_launcher"
action_sample:showAsAction="always"/>



	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.action_menu, menu);
		return true;
	}

}


9. event 발생

 - 추가된 actionbar의 아이콘을 클릭했을 때 toast message를 보여주도록 했습니다.

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {

		switch (item.getItemId()) {
		case R.id.menu_sample: {
			Toast.makeText(this, R.string.action_sample, Toast.LENGTH_SHORT)
					.show();
			break;
		}
		}

		return super.onOptionsItemSelected(item);
	}


Android 의 TextView에는 shadow 효과가 기본적으로 있습니다. shadow효과로 다양한 TextStyle을 만들 수 있는데 이번 포스트에서는 shadow효과의 다양한 value에 의해서 어떤 효과가 나오는지 확인해 볼려고 합니다.


우선 TextView에 있는 shadow 효과에 사용되는 xml attribute와 method를 확인해 보면

android:shadowColor

Place a shadow of the specified color behind the text.

Must be a color value, in the form of "#rgb", "#argb", "#rrggbb", or "#aarrggbb".

This may also be a reference to a resource (in the form "@[package:]type:name") or theme attribute (in the form "?[package:][type:]name") containing a value of this type.

This corresponds to the global attribute resource symbol shadowColor.

android:shadowDx

Horizontal offset of the shadow.

Must be a floating point value, such as "1.2".

This may also be a reference to a resource (in the form "@[package:]type:name") or theme attribute (in the form "?[package:][type:]name") containing a value of this type.

This corresponds to the global attribute resource symbol shadowDx.

android:shadowDy

Vertical offset of the shadow.

Must be a floating point value, such as "1.2".

This may also be a reference to a resource (in the form "@[package:]type:name") or theme attribute (in the form "?[package:][type:]name") containing a value of this type.

This corresponds to the global attribute resource symbol shadowDy.

android:shadowRadius

Radius of the shadow.

Must be a floating point value, such as "1.2".

This may also be a reference to a resource (in the form "@[package:]type:name") or theme attribute (in the form "?[package:][type:]name") containing a value of this type.

This corresponds to the global attribute resource symbol shadowRadius.

이와 같습니다. shadowColor는 shadow의 색상, shadowDx는 shadow의 X방향 offset, shadowDy는 shadow의 Y방향 offset, shadowRadius는 shadow의 반지름이 됩니다.

샘플코드를 확인해 보겠습니다.

<LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:padding="10dip" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:shadowColor="#7F000000"
            android:shadowDx="3"
            android:shadowDy="3"
            android:shadowRadius="0.01"
            android:text="Shadow Style"
            android:textColor="#000000" />
</LinearLayout>

이와 같이 하면 결과는

이와 같습니다. 검은 Shodow Style 아래에 회색의 shadow가 있는 것을 확인할 수 있습니다. 그림자 위치를 더 멀리 하고 싶아면 shadowDx와 shadowDy값을 더 많이 주면 됩니다.

위의 결과에 shadowRadius값을 변경했을 때 코드는

<LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:padding="10dip" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:shadowColor="#7F000000"
            android:shadowDx="3"
            android:shadowDy="3"
            android:shadowRadius="1.5"
            android:text="Shadow Style"
            android:textColor="#000000" />
</LinearLayout>

이와 같이 했을 경우 결과는

이렇게 됩니다. shadowRadius값에 따라서 shadow모양이 변경된 것을 볼 수 있습니다.

그럼 이번에는 shadow의 방향을 바꾸도록 하겠습니다.

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#FFFFFF"

        android:padding="10dip" >
        <TextView             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:shadowColor="#7F000000"             android:shadowDx="3"             android:shadowDy="-3"             android:shadowRadius="1.5"             android:text="Shadow Style"             android:textColor="#000000" />     </LinearLayout>

이와 같이 했을 때 결과는

이와 같습니다.그림자가 오른쪽 위 방향으로 변경되었습니다. shadowDx와 shadowDy의 값의 +- 에 따라서 값이 shadow방향이 변경 됩니다. 소위 발하는 그림자가 45` 방향이면 shadowDx는 +, shadowDy는 -을 주고, 135`방향을 경우는 둘다 +의 값을 주면 됩니다.


이번에는 shoadow를 이용한 blur 효과 비슷하게 주는 방법입니다.

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#000000"
        android:padding="10dip" >

        <TextView             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:shadowColor="#FFFFFF"             android:shadowDx="0"             android:shadowDy="0"             android:shadowRadius="3"             android:text="Shadow Style"             android:textColor="#FFFFFF" />     </LinearLayout>

이와 같이 shadowDx와 shadowDy의 값을 0.. shadowRadius값만 +로 주었을 때 결과는

이와 같습니다. 글자 주변으로 blur 효과가 나타는 것을 볼 수 있습니다.


이번에는 네온사인?? 같은 효과 입니다.

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#000000"
        android:padding="10dip" >

        <TextView             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:shadowColor="#FFFFFF"             android:shadowDx="0"             android:shadowDy="0"             android:shadowRadius="2"             android:text="Shadow Style"             android:textColor="#000000" />     </LinearLayout>
    <LinearLayout         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:background="#000000"         android:padding="10dip" >
        <TextView             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:shadowColor="#00FF00"             android:shadowDx="0"             android:shadowDy="0"             android:shadowRadius="2"             android:text="Shadow Style"             android:textColor="#000000" />     </LinearLayout>

이와 같이 했을 때 결과는


이와 같습니다. 이건 단지 배경과 글자색을 같게 하고 그림자 색상만 다르게 했을 때 입니다. 


TextView의 shadowDx, shadowDy, shadowRadius값에 따라서 TextView의 효과를 확인해보았습니다. 그런데 저는 제일 많이 쓰는 것은 단지 ShadowDx=2 shadowDy=2 shadowRadius=2 인것 같습니다. 이건 단지 개인별로 차이가 있겟지만요 ^^




 오랜만에 제 블로그에 글을 써봅기 시작합니다 ^^

 안드로이드 개발을 시작한지... 좀 되었네요 ㅎㅎ... 관심있어서 공부한 시간은 빼고 앱을 처음 만들어서 런칭했을 때가 2010년이니 시간이 참 많이도 지났네요 ㅎㅎ 제 블로그에 제가 회사다니면서 만든 앱을 적어둔 것도 있지만 안그런 것도 많아서ㅋ

 그럼 제가 개인적으로 이번에 만들어본 어플을 정리해 볼까 합니다.

우선 마켓은 

https://play.google.com/store/apps/details?id=com.magimon.quicktouch

이곳입니다.

이름은 퀵터치(QuickTouch)입니다. 앱 이름을 정하는 것도 참 힘들더군요 ㅡㅡ...

 주된 기능은 다른 앱이 실행되더라도 항상 퀵터치 뷰가 보여지고, 뷰안에서 모바일 데이터, 배터리, 메모리 등을 모니터링 합니다. 그리고 항상 빨리 실행하고 싶은 앱을 추가해서 다른 앱을 실행하더라도 그 위치에서 바로 실행할 수 있습니다. 머 이게 주된 기능이라고 보면 될듯 하네요.

 모바일 데이터를 모니터링 해주는 앱은 많지만, 이것을 확인할려면 위젯이나 안드로이드의 notification bar에서 확인해야 합니다. 다른 앱이 실행중이면 위젯은 가려져서 확인할 수 없고, notification bar에서는 화면을 내려봐야 사용된 내용을 확인할 수 있죠. 이런것도 단순히 항상.. 실시간으로 확인해 보는 것입니다. 모바일 게임을 하면서 항상 데이터를 확인할 수 있죠.

 안드로이드느 백그라운드에서 앱이 많이 실행됩니다. 여러가지 서비스도 많이 돌고, 넥서스 시리즈가 아닌 국내 제조사의 폰들은 자체적으로 또 많은 추가적인 서비스를 넣죠. 요즘 최신 디바이스들이 메모리가 2기가 가까이 되지만 메모리를 기본적으로 많이 사용하고있죠. PC를 생각해도 메모리를 많이 사용하면 PC전체가 조금 느려지기도 하고 .. 그래서 메모리 사용량을 실시간으로 모니터링해 보여주고, 메모리를 사용자 설정보다 많이 사용하게 되면 메모리를 clear하라는 경고를 알려줍니다. 

 하상 퀵터치 뷰가 맨위에 존재하다 보니 이걸 통해서 언제든지 사용자가 등록해둔 앱을 빨리 실행해 볼 수도 있습니다. 기본적으로 하나의 앱을 실행하는 도중에 다른앱을 실행할려면 백키나 홈키를 통해서 빠져 나온 뒤 실행해야 하지만, 이것은 바로바로 실행할 수 있죠. 조금의 시간이라도 절약할 수 있는 겁니다 ^^


 

 

 

 

 

 


아직 수정하고 손봐야 할 곳들이 많습니다. 추가했으면 하는 기능은 댓글로 남겨주시거나 메일로 보내주셔도 됩니다 ^^ 소중한 의견은 앱의 발전에 큰 도움이 됩니다 ㅋ



MapView 에서 현재 화면의 중앙 latitude와 longitude 값을 얻는 것은 간단 합니다.

getMapCenter() 메소드를 통해서 GeoPoint를 얻기만 하면 되니까요...
그럼 화면의 최상단과 최하단의 latitude, longitude 값은 어떻게 얻을까요?
아래와 같이 하면 됩니다.

Projection proj = mMapView.getProjection();
GeoPoint topLeft = proj.fromPixels(0, 0);

GeoPoint bottomRight = proj.fromPixels(mMapView.getWidth() - 1, mMapView.getHeight() - 1);

double topLat = topLeft.getLatitudeE6() / 1E6;
double topLon = topLeft.getLongitudeE6() / 1E6;
double bottomLat = bottomRight.getLatitudeE6() / 1E6;
double bottomLon = bottomRight.getLongitudeE6() / 1E6;



이렇게 하면 현재 mapview 화면의 상단 하단의 latitude와 longitude 값을 구할 수 있습니다.
 

+ Recent posts