말도 많고...
그동안 문제도 생겼던... ㅜㅜ/
아..그래도 이제 거의다 완성이 되가는 ㅋㅋ
과연 내일 베타테스트를 진행할 수 있을런지.. 음...


안드로이드 개발을 하게 되다 보면
너무 다양한 디바이스에 대해서 서로 다른 설정을 해 줄 필요도 있게 되겠죠.
간단하게 디바이스 정보를 확인하는 방법 입니다.


import android.os.Build;

Log.i("BOARD", Build.BOARD);
Log.i("BRAND", Build.BRAND);
Log.i("CPU_ABI", Build.CPU_ABI);
Log.i("DEVICE", Build.DEVICE);
Log.i("DISPLAY", Build.DISPLAY);
Log.i("FINGERPRINT", Build.FINGERPRINT);
Log.i("HOST", Build.HOST);
Log.i("ID", Build.ID);
Log.i("MANUFACTURER", Build.MANUFACTURER);
Log.i("MODEL", Build.MODEL);
Log.i("PRODUCT", Build.PRODUCT);
Log.i("TAGS", Build.TAGS);
Log.i("TYPE", Build.TYPE);
Log.i("USER", Build.USER);



  안드로이드의 특징중에 하나를 꼽는다면 백그라운드 실행이라고 할 수 있겠습니다. 아이폰과 다르게 멀티테스킹이 가능한
안드로이드는 그만큼 활용도가 많다는 것입니다. 하지만 그것에 따른 다른 주의 사항이 있습니다.
그 중에 하나가 바로 wifi모드를 유지하는 것입니다.

  안드로이드는 대기 모드로 들어가게 되면 배터리 소모를 줄이기 위해서 wifi를 자동으로 꺼버리게 됩니다. 하지만 무선으로
데이터를 주고 받는 중이거나, 스티리밍을 하고 있는 중간에 대기 상태로 들어가게 되고 자동으로 wifi가 꺼지게 된다면 3G
의 무선 데이터 모드로 바뀌게 되겠지요. 그렇게 된다면 3G 데이터의 사용이 많아지게 되고 나중엔 사용자의 요금에 지대한
영향을 줄 것으로 생각됩니다.
  백그라운드 실행 중에도 wifi 상태를 유지하기 위해서는 

android.net.wifi.WifiManager.WifiLock

을 이용해서 wifi상태를 유지시켜줘야 합니다.
자세한 설명음
http://developer.android.com/reference/android/net/wifi/WifiManager.WifiLock.html
이 곳에 가시면 확인할 수 있습니다.

간단히 사용방법을 보게 된다면
WifiManager.WifiLock wifiLock = null;
//등록
if (wifiLock == null) {
                WifiManager wifiManager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
	wifiLock = wifiManager.createWifiLock("wifilock");
	wifiLock.setReferenceCounted(true);
	wifiLock.acquire();
}
//해제
if (wifiLock != null) {
                wifiLock.release();
	wifiLock = null;
}

이렇게 하면 됩니다.
대기 상태에서도 wifi를 유지하고 있게 된다면, 배터리 소모가 빠르고 많아진다는 단점이 있지만, 그만큼 3G 데이터를 사용하는것이 적어진다는 것에 대한 장점도 있게 됩니다.

  두번째로 주의할 점은, 대기상태가 오래 된다면 cpu의 활동을 정지시켜 버립니다. 이것도 배터리 소모를 줄이기 위한 것이기는 하지만, 단적인 예로 들어서 스트리밍으로 음악을 듣고 있는 중에서 화면을 꺼버린 대기 모드일 경우에 cpu를 정지 시킨다면 음악을 들을 수 없게 되겠지요. 그래서 wifi상태를 유지 시켜주기 위한 WifiLock이 있듯이 cpu상태를 활동상태로 유지시켜주는 WakeLock이 있습니다.

android.os.PowerManager.WakeLock

자세한 설명은
http://developer.android.com/reference/android/os/PowerManager.WakeLock.html
이곳에 가셔서 확인해 볼 수 있습니다.

이것을 사용하는 방법은 간단히
PowerManager.WakeLock wakeLock = null;
//등록
if (wakeLock == null) {
	PowerManager powerManager = (PowerManager) context.getSystemService(context.POWER_SERVICE);
	wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "wakelock");
	wakeLock.acquire();
}
//해제
if (wakeLock != null) {
	wakeLock.release();
	wakeLock = null;
}

이렇게 하면 됩니다.

이 두가지를 유지시켜 준다면, 백그라운드로 실행을 하면서 대기 모드로 전환이 된다고 해도, 해당 어플이 죽거나 하는 일은 없겠지만, 그만큼 배터리 소모가 많아지기 때문에 안드로이드폰을 오래 사용할 수는 없겠지요.


이미지 효과로 이미지 크기의 절반을 반대 되는 이미지를 만들고,
그 반대된 이미지에 대해서는 반사 된 듯한 효과를 주는 소스 입니다.


package com.android.reflection2;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;
import android.graphics.Shader.TileMode;
import android.os.Bundle;
import android.widget.ImageView;

public class Reflection extends Activity {
	/** Called when the activity is first created. */

	ImageView view1;

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

		view1 = (ImageView) findViewById(R.id.ImageView01);

		Bitmap bitmapOriginal = BitmapFactory.decodeResource(getResources(),
				R.drawable.android);

		int nWidth = bitmapOriginal.getWidth();
		int nHeight = bitmapOriginal.getHeight();

		Matrix matrix = new Matrix();
		matrix.preScale(1, -1);

		Bitmap bitmapReflection = Bitmap.createBitmap(bitmapOriginal, 0,
				nHeight / 2, nWidth, nHeight / 2, matrix, false);

		Bitmap bitmapOrigianlAndReflection = Bitmap.createBitmap(nWidth,
				(nHeight + nHeight / 2), Config.ARGB_8888);

		Canvas canvas = new Canvas(bitmapOrigianlAndReflection);
		canvas.drawBitmap(bitmapOriginal, 0, 0, null);
		Paint deafaultPaint = new Paint();
		canvas.drawRect(0, nHeight, nWidth, nHeight + 5, deafaultPaint);
		canvas.drawBitmap(bitmapReflection, 0, nHeight + 5, null);

		Paint paint = new Paint();
		LinearGradient shader = new LinearGradient(0, bitmapOriginal
				.getHeight(), 0, bitmapOrigianlAndReflection.getHeight() + 5,
				0x70ffffff, 0x00ffffff, TileMode.CLAMP);
		paint.setShader(shader);
		paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
		canvas.drawRect(0, nHeight, nWidth, bitmapOrigianlAndReflection
				.getHeight() + 5, paint);

		view1.setImageBitmap(bitmapOrigianlAndReflection);
	}
}

결과 화면은 이런 식으로 나옵니다.



안드로이드에서 레이아웃을 만들 때 반투명 효과를 줄 필요가 있지요.
이미지에 alpha값을 넣어서는 그것을 backgound로 넣어서는 효과를 줄 수도 있지만,
Paint클래스에 있는 setAlpha라는 메소드를 이용해서 alpha값을 넣어서 반투명 효과를 줄 수가 있습니다.
레이아웃이나 다른 여러가지에도 반투명 효과는 동일하게 주어질 수 있는 것이죠.

방법은

Paint paint = new Paint();
paint.setColor(Color.Black);
paint.setAlpha(50);

이런식으로 객체를 만들어서 이것을 배경으로 사용하시면 됩니다.

결과 화면은

이런 화면이 만들어지게 됩니다.



안드로에드에서 버튼에 대한 효과를 주는 방법이 있습니다.
ImageButton에 효과를 주는 방법인데... 구글 안드로이드 개발 사이트에서도 명시 되어 있습니다.
그런데 보면서 좀... 혼라?? 스러웠다고 해야 할까요... 그래서 좀 정리를 해볼려고 합니다.

To indicate the different button states (focused, selected, etc.), you can define a different image for each state. E.g., a blue image by default, an orange one for when focused, and a yellow one for when pressed. An easy way to do this is with an XML drawable "selector."

영어는 잘 못하지만.. 대충 내용은 focused, selected, normal 상태의 버튼을 정의하고 싶으면 xml에다 selector라는 것을 사용해서 미리 정의라하는... 그런 내용이죠... 버튼 색상이 나오는데... 그것에 대한 내용은 
이 두 곳에 가시면 설명을 볼 수 있습니다.

그리고는 설명에서는 이렇게 xml을 정의하라고 나옵니다.
      
                
                
            

그리고는 res/drawable/ 폴더에다가 만들어서 사용하라는 내용은 있는데... 저의 짧은 지식으로는 정확하게 이해하기가 힘들더군요... 

예전에는 안드로이드 개발할 때 /res 밑에 drawable 폴더가 1개밖에 없었던 기억이 있었는데... 지금은 기본 프로젝트를 생성해도 /res 밑에 drawable 폴더가 "/res/drawable-hdpi", "/res/drawable-mdpi", "/res/drawable-ldpi" 이렇게 3개가 존재합니다. 구글 document에서는 /res/drawable/ 에다가 xml을 만들라고 합니다...
그럼 그렇게 하면 됩니다... ㅜㅜ/// 정말 말 그대로 하면 되는데... 괜히 /res/drawable-hdpi... mdpi... ldpi... 이런데다가 만들어봐서 했는데 안되더군요 ㅋㅋ

그림에서 보는 것 처럼.. /res/drawable/ 폴더를 만들고 그 곳에 원하는 xml파일을 만듭니다... 예를 들어서 
"play_button.xml"이라는 파을을 만들고 안의 내용을
      
                
                
            

이렇게 안의 내용을 정의 해 두고...
play_button_pressed와 play_button_focused.. 그리고 play_button_normal은... drawable-hdpi, mdpi, ldpi에 paly_button_pressed.png, play_button_focused.png, play_button_noraml.png 로 된 이미지 파일이 있어야 합니다. 

그런 다음에... Layout에서 ImageButton을 만들고 그곳에서 ImageButton의 property의 "Background"에다가
@drawable/play_button 이라고 입력하면 끝납니다.

이 방법때문에... 좀 힘들게 진행했네요... 어떻게 보면...정말 간단한건데...

이젠... 이생각이 듭니다... 그럼 ImageButton마다 일일이 이런 xml을 파일을 만들어 줘야 하는건지... 그럼 하나의 Activity안에 ImageButton이 10개면... 버튼 10개에 대한 xml을 따로 만들어 줘야 하는건지... ㅎㅎ
더 쉽게 하는 방법이 있는지 찾아 봐야 겠습니다... ㅜㅜ///
허접한 설명이였습니다 ㅎ



음악을 스트리밍 하다가..볼륨을 조절 할 일이 생기게 되었을 경우.
안드로이드에 볼륨 조절하는 버튼이 있지만...
스트리밍 중에 화면에서 SeekBar를 통해서 조절을 하는 방법도 있다.
AudioManager 클래스에 있는 메소드를 이용하면 가능.

1. 볼륨 조절 버튼으로 조절 하기.

public boolean onKeyDown(int keyCode, KeyEvent event) {                  
        AudioManager mAudioManager = 
            (AudioManager)getSystemService(AUDIO_SERVICE);
        switch (keyCode) {
        case KeyEvent.KEYCODE_VOLUME_UP :
            mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
                                             AudioManager.ADJUST_RAISE, 
                                             AudioManager.FLAG_SHOW_UI);
                return true;
        case KeyEvent.KEYCODE_VOLUME_DOWN:
            mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, 
                                             AudioManager.ADJUST_LOWER, 
                                             AudioManager.FLAG_SHOW_UI);
                return true;
        case KeyEvent.KEYCODE_BACK:
            return true;
        }

        return false;
   }

    public boolean onKeyUp(int keyCode, KeyEvent event) {
        AudioManager mAudioManager = 
           (AudioManager)getSystemService(AUDIO_SERVICE);
        switch (keyCode) {
        case KeyEvent.KEYCODE_VOLUME_UP :
            mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, 
                                             AudioManager.ADJUST_SAME, 
                                             AudioManager.FLAG_SHOW_UI);
                return true;
        case KeyEvent.KEYCODE_VOLUME_DOWN:
            mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, 
                                             AudioManager.ADJUST_SAME, 
                                             AudioManager.FLAG_SHOW_UI);
                return true;
        case KeyEvent.KEYCODE_BACK:
            this.finish();
            return true;
        }
        return false;
    }
2. 화면에서 SeekBar를 통해서 조절하기
seekVolumn = (SeekBar) findViewById(R.id.SeekBar_Volumn);
		final AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
		int nMax = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
		int nCurrentVolumn = audioManager
				.getStreamVolume(AudioManager.STREAM_MUSIC);

		seekVolumn.setMax(nMax);
		seekVolumn.setProgress(nCurrentVolumn);

		seekVolumn.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onProgressChanged(SeekBar seekBar, int progress,
					boolean fromUser) {
				// TODO Auto-generated method stub
				audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
						progress, 0);
			}
		});


http에 request를 보냈는데.. 서버에서 url주소를 redirect해서 보내주는 경우가 있지요. 그럼 개발자가 입력한 주소로는
요청이 안되는 경우가 생깁니다. 이걸 해결하기위해서는 javaj에서 redirect된 주소로 다시 요청을 해줘야 합니다.
방법은

private InputStream openConnectionCheckRedirects(URLConnection c) throws IOException 
{
   boolean redir;
   int redirects = 0;
   InputStream in = null;
   do 
   {
      if (c instanceof HttpURLConnection) 
      {
         ((HttpURLConnection) c).setInstanceFollowRedirects(false);
      }
      in = c.getInputStream(); 
      redir = false; 
      if (c instanceof HttpURLConnection) 
      {
         HttpURLConnection http = (HttpURLConnection) c;
         int stat = http.getResponseCode();
         if (stat >= 300 && stat <= 307 && stat != 306 &&
            stat != HttpURLConnection.HTTP_NOT_MODIFIED) 
         {
            URL base = http.getURL();
            String loc = http.getHeaderField("Location");
            URL target = null;
            if (loc != null) 
            {
               target = new URL(base, loc);
            }
            http.disconnect();
            if (target == null || !(target.getProtocol().equals("http")
               || target.getProtocol().equals("https"))
               || redirects >= 5)
            {
               throw new SecurityException("illegal URL redirect");
            }
            redir = true;
            c = target.openConnection();
            redirects++;
         }
      }
   } 
   while (redir);
   return in;
}

public void makeConnection(URL url){
   URLConnection conn = url.openConnection();
   InputStream is = openConnectionCheckRedirects(conn);

   /* request에 대한 결과 처리 부분*/

   is.close();
}

이런식으로 하면 되겠습니다. 서버에서 제공하는 api가 redirect된 주소로 해서 보내주는 경우가 많기에... 이 방법을 써서 해결하게 되었습니다.




+ Recent posts