페이지

2011년 5월 27일 금요일

Alarm Controller, PendingIntent

▦ AlarmController
AlarmController Class와 매치되는 XML은 alarm_controller.xml (AlarmController.java)
        setContentView(R.layout.alarm_controller);

button Listener 설정 (AlarmController .java)
        Button button = (Button)findViewById(R.id.one_shot);
        button.setOnClickListener(mOneShotListener);
        button = (Button)findViewById(R.id.start_repeating);
        button.setOnClickListener(mStartRepeatingListener);
        button = (Button)findViewById(R.id.stop_repeating);
        button.setOnClickListener(mStopRepeatingListener);

oen short alarm button 을 클릭하면 한번만 30초 후 알람을 호출 한다. (AlarmController .java)
누르자 마자 "one-shot alarm will go off ~~~ "토스트 메시지 나온고, 30초 뒤에 "the one-shot alarm has gone off" 토스트 메시지가 나오게 된다.

    private OnClickListener mOneShotListener = new OnClickListener() {
        public void onClick(View v) {

// 알람이 동작할때, BroadcastReceiver로 인텐트를 브로트 캐스트 하길 원한다.
// 여기서 우리는 인텐트를 만든다 명시적인 클레스 이름으로 우리가 가지고 있는
// Receiver(AndroidManifest.xml 안에 공용으로 존재하는)를 설명하고 호출되면,
// IntentSender는 브로드캐스트처럼 인텐트가 실행된다.
            Intent intent = new Intent(AlarmController.this, OneShotAlarm.class);
            PendingIntent sender = PendingIntent.getBroadcast(AlarmController.this,
                    0, intent, 0);

            // 지금으로부터 30초 뒤에 알람이 켜지길 원한다.
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(System.currentTimeMillis());
            calendar.add(Calendar.SECOND, 30);

            // 알람 일정
            AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
            am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);

            // 우리가 한 일에 대해 사용자에게 알려준다.
            if (mToast != null) {
                mToast.cancel();
            }
            mToast = Toast.makeText(AlarmController.this, R.string.one_shot_scheduled,
                    Toast.LENGTH_LONG);
            mToast.show();
        }
    };

PendingIntent (위임된, 보류된? 인텐트)커뮤니케이션에는 메세지(Intent), 송신자(startActivity, startService 호출), 수신자(Intent filter 가지고 있음) 라는 3가지 기본 요소가 있다.
PendingIntent는 인텐트를 전송하고자 하는 '송신자'가 인텐트를 생성한 후, 인텐트를 나중에 대신 전달 하고자 할때 사용
예) 친구에게 내 카드를 주며, 돈을 대신 찾아 달라는 것. 카드 악용을 맞기 위해 권한 설정

  ※ IntentSender는 PendingIntent와 유사하며, 권한 관리 설정을 할수 없음. 사용시 PendingIntent 생성뒤 getIntentSender() 호출하여야 함.
참고 : http://blog.naver.com/huewu?Redirect=Log&logNo=110084228131

단순히 activity를 상속 받는 것이 아닌, Broadcast와 같이 activity를 상속받지 않은 class의 경우, startActivity(intent)를 사용하지 못하는데, 이때 PendingIntent를 사용 할수 있다.

예제) pi를 이용하여 클래스이름.class를 호출한다.
Intent i = new Intent( mContext, 보낼클래스이름.class );
PendingIntent pi =  
PendingIntent.getActivity(mContext, 0, i, PendingIntent.FLAG_ONE_SHOT);  
   try {
    Toast.makeText(mContext, str, 0).show();
    pi.send();
  } catch (CanceledException e) {
            e.printStackTrace();
  }
참고 : http://www.cyworld.com/bluekirao_Ov/3218155
intFLAG_CANCEL_CURRENT이전에 생성한 PendingIntent 는 취소하고, 새롭게 하나를 만듭니다. (친구에게 예전에 빌려준 카드를 정지 시키고 새롭게 하나 신청합니다.)
intFLAG_NO_CREATE현재 생성된 PendingIntent 를 반환 합니다. (친구 보고 내가 빌려준 카드를 당장 가져와 보라고 요청합니다. 이 후에, 해당 카드를 회수 할 수도 있습니다.)
intFLAG_ONE_SHOT이 플래그를 이용해 생성된 PendingIntent 는 단 한번 밖에 사용될 수 없습니다. (일회용 카드)
intFLAG_UPDATE_CURRENT만일 이미 생성된 PendingIntent 가 존재 한다면, 해당 Intent 의 내용을 변경합니다. (친구에게 전화해서, 인출할 돈의 액수를 다시 알려줍니다.)
PendingIntent getBroadcast (Context context, int requestCode, Intent intent, int flags)
브로드캐스트 실행할 PendingIntent를 반환한다. Context.sendBroadcast() 호출하는것과 같다.
매개변수
  context : 브로드 캐스트 실행할 PendingIntent의 Context
  requestCode : sender에게 요청 코드(현재 사용되지 않음)
  intent : 브로드캐스트 할 Intent
  flags :  FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT 또는 Intent.fillIn()에 의해 지원되는       다른 flag들. 실제 전달될때 제공되는 Intent의 어떤 불특정 부분을 제어할수 있다.반환값 : 주어진 매개변수와 일치하는 PendingIntent를 새로 생성하거나 존재할때 반환. FLAG_NO_CREATE 가 제공될경우에만 null을 반환할수 있다.
Start Repeating Alarm button  클릭하면 반복적으로 알람을 호출하게 된다.(
AlarmController .java)
    private OnClickListener mStartRepeatingListener = new OnClickListener() {
        public void onClick(View v) {
            // 위와는 달리 IntentSender 자체를 여러번 전송할 수 있도록 설정한다.
            Intent intent = new Intent(AlarmController.this, RepeatingAlarm.class);
            PendingIntent sender = PendingIntent.getBroadcast(AlarmController.this,
                    0, intent, 0);

            long firstTime = SystemClock.elapsedRealtime();
            firstTime += 15*1000;

            AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
            am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                            firstTime, 15*1000, sender);

            if (mToast != null) {
                mToast.cancel();
            }
            mToast = Toast.makeText(AlarmController.this, R.string.repeating_scheduled,
                    Toast.LENGTH_LONG);
            mToast.show();
        }
    };

Stop Repeating Alarm button  클릭하면 반복적으로 알람을 정지하게 된다.(AlarmController .java)
    private OnClickListener mStopRepeatingListener = new OnClickListener() {
        public void onClick(View v) {
            // Create the same intent, and thus a matching IntentSender, for
            // the one that was scheduled.
            Intent intent = new Intent(AlarmController.this, RepeatingAlarm.class);
            PendingIntent sender = PendingIntent.getBroadcast(AlarmController.this,
                    0, intent, 0);
           
            // And cancel the alarm.
            AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
            am.cancel(sender);

            // Tell the user about what we did.
            if (mToast != null) {
                mToast.cancel();
            }
            mToast = Toast.makeText(AlarmController.this, R.string.repeating_unscheduled,
                    Toast.LENGTH_LONG);
            mToast.show();
        }
    };

AlarmManager일정 간격으로 스케쥴링 하고 싶을때 사용하는 서비스 (스레드로도 구현 가능하나 데드락 고민필요)
서비스 이므로, 항상 활성화 시키며, 어플리케이션 종료나 비활성화시 해제해주지 않으면 계속 뜬다.

사용방법
1. 명시적 인텐트 설정
  Intent intent = new Intent( MyClass.this, AlarmReceiver.class);
2. 브로드 캐스트 송신자 설정
  PendingIntent sender = PendingIntent.getBroadcast( MyClass.this, 0, intent, 0);
3. 시간 설정
  long firstTime = System.currentTimeMillis();
4. 서비스 객체 얻기
  AlarmManager alarm = (AlarmManager) Context.getSystemService( Context.ALARM_SERVICE );
5. 알람등록(반복)
  alarm.setRepeating( AlarmManager.RTC_WAKEUP, firstTime, 10000, sender);

수신 하기 : 사용하기 전에 Receiver를 등록 해야 한다.
ex) <application android ~~~~ >
         <receiver android:name="AlarmReceiver" android:process=":remote" />

1. BroadcastReceiver을 상속한 클래스 구성
  public class AlarmReceiver extends BroadcastReceiver {
   ...
  }

2. onReceive 오버라이딩 (실제 동작)
  public void onReceive( Context context, Intent intent) {
   ...
  }

참고 : http://blog.daum.net/hopefullife/87

1.스레드를 사용하여 특정 시간 후 작업 처리 방법
핸들러에 스레드 연결,

예제) 10초 후 일 처리
private Handler mHandler;
mHandler.postDelayed( new Runnable() {
   public void run() {
     ...
   }
}, 1000);

2. 다른 스레드에서 UI관련 함수 실행을 원할 경우
UI와 관련된 함수는 대부분 UI스레드에서만 호출 될 수 있다.
  view.post(Runnable action)
  : view에서도 편리함을 위해 메시지를 post 해주는 함수 존재

참고 : http://blog.naver.com/pjsin865?Redirect=Log&logNo=120066422409

Theme.Wallpaper - 배경화면을 백그라운드로

배경화면을 백그라운드로 설정하는 예제

AndroidManifest.xml 에서 테마로 Wallpaper가 설정 되어 있다.
        <activity android:name=".app.WallpaperActivity"
                android:label="@string/activity_wallpaper"
                android:theme="@style/Theme.Wallpaper">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.SAMPLE_CODE" />
            </intent-filter>
        </activity>

Styles.xml에 Theme.Wallpaper 가 정의 되어 있으며 부모로 android:style/Theme.Wallpaper을 설정했다. -> 배경화면 설정 
    <style name="Theme.Wallpaper" parent="android:style/Theme.Wallpaper">
        <item name="android:colorForeground">#fff</item>
    </style>

WallpaperActivity Class와 매치되는 XML은 translucent_background.xml (WallpaperActivity.java)
        setContentView(R.layout.translucent_background);

Translucent Blur - Activity 반투명 테마

배경이 흐릿하게 보이는 예제.


AndroidManifest.xml 에서 테마로 Transparent가 설정 되어 있다.
        <activity android:name=".app.TranslucentBlurActivity"
                android:label="@string/activity_translucent_blur"
                android:theme="@style/Theme.Transparent">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.SAMPLE_CODE" />
            </intent-filter>
        </activity>

Styles.xml에 Theme.Transparent가 정의 되어 있으며 불투명 설정, 에니메이션 등을 설정.
     <style name="Theme.Transparent">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
        <item name="android:windowBackground">@drawable/transparent_background</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:colorForeground">#fff</item>
    </style>

TranslucentBlurActivity Class와 매치되는 XML은 translucent_background.xml (TranslucentBlurActivity.java)
        setContentView(R.layout.translucent_background);

translucent_background.xml 파일
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:gravity="center_vertical|center_horizontal"
    android:text="@string/translucent_background"/>

윈도우의 설정을 불러와서 Blur(흐림효과) 설정을 해준다.
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
                WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

LayoutParams의 속성의 종류

  • FLAG_BLUR_BEHIND
  •  : 윈도우 뒤의 모든것을 흐리게 한다.
  • FLAG_DIM_BEHIND
  •  : 윈도우 뒤의 모든것을 어둡게 한다.
  • FLAG_NOT_FOCUSABLE
  •  : 윈도우 에서 키 입력 포커스를 갖지 않는다. 사용자가 키나 다른 버튼의 이벤트를 보낼수 없다. 어떤 포커스 윈도우 대신에 뒤에 남을 것이다.
  • FLAG_NOT_TOUCHABLE
  •  : 윈도우는 터치 이벤트를 절대 받을수 없다.
  • FLAG_NOT_TOUCH_MODAL
  •  : 윈도우가 포커스 될때 조차(FLAG_NOT_FOCUSABLE이 설정되지 않음) 윈도우 외부의 어떤 포인터 이벤트도 윈도우 뒤로 보내는것을 허락한다.
  • FLAG_LAYOUT_IN_SCREEN
  •  : 윈도우의 전체 화면 내에서, 경계(별명으로 상태표시줄) 주위의 장식을 무시한다.
  • FLAG_DITHER
  •  : 진동 설정
  • FLAG_KEEP_SCREEN_ON
  •  : 사용자가 윈도우 표시되는 동안, 화면을 켜고 밝게 해준다.
  • FLAG_FULLSCREEN
  •  : 모든 화면 장식(상태표시줄 등)이 창이 표시 되는 동안 숨긴다.
  • FLAG_FORCE_NOT_FULLSCREEN
  •  : FLAG_FULLSCREEN 과 화면 장식(상태표시줄 같은) 보여지는 것을 무시한다.
  • FLAG_IGNORE_CHEEK_PRESSES
  •  : 사용자의 뺨이 화면에 닫는 등의 이벤트를 감지 하지 않기 원할때 필터 설정.

Translucent - Activity 반투명 테마

Activity 가 실행될때 기존에 있던 Activity 를 반투명한 배경으로 보여준다.

        <activity android:name=".app.TranslucentActivity"
                android:label="@string/activity_translucent"
                android:theme="@style/Theme.Translucent">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.SAMPLE_CODE" />
            </intent-filter>
        </activity>

= Styles.xml
   <style name="Theme.Translucent" parent="android:style/Theme.Translucent">
        <item name="android:windowBackground">@drawable/translucent_background</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:colorForeground">#fff</item>
    </style>

WallpaperManager

Wallpaper 이미지 가져오기 및 이미지 필터 적용하기.


        final WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
        final Drawable wallpaperDrawable = wallpaperManager.getDrawable();
        final ImageView imageView = (ImageView) findViewById(R.id.imageview);
        imageView.setDrawingCacheEnabled(true);        imageView.setImageDrawable(wallpaperDrawable);

=> WallpaperManager 인스턴스를 가져와서 ImageView에 그려준다.

        Button randomize = (Button) findViewById(R.id.randomize);
        randomize.setOnClickListener(new OnClickListener() {
            public void onClick(View view) {
                int mColor = (int) Math.floor(Math.random() * mColors.length);
                wallpaperDrawable.setColorFilter(mColors[mColor], PorterDuff.Mode.MULTIPLY);
                imageView.setImageDrawable(wallpaperDrawable);
                imageView.invalidate();
            }
        });

=> 랜덤으로 적용된 이미지 필터를 ImageView에 적용한다.

        wallpaperManager.setBitmap(imageView.getDrawingCache());

=> 변경한 이미지를 Wallpaper 에 적용한다.

void setDrawingCacheEnabled(boolean enabled)
: 그림 캐쉬 설정/미설정. 그림 캐쉬가 설정되면, 다음에 getDrawingCache() 또는 buildDrawingCache()에 대해 호출되어 View에서 비트맵을 그릴것이다.캐쉬가 설정되었을때 draw(android.graphics.Canvas) 호출은 캐쉬로부터 그리지 않을 것이다. 캐쉬로 부터 이득을 얻으려면, 반드시 비트맵이 Null이 아닌 경우 화면에 그리는 getDrawingCache() 를 호출하여 그리는 캐쉬 요청해야한다.

Math

Math.random()
= "0.0 이상에서 1.0 미만" 의 double형 실수 값을 반환합니다.
   즉, 0.0 은 나올 수 있지만 1.0 은 나올 수 없습니다.
Math.ceil()
= 올림.

Math.floor()
= 내림.

Math.round()
= 반올림.


[ 예 제 ]

Math.ceil(1.4)   = 2
Math.ceil(1.6)   = 2
Math.ceil(-1.4)  = -1
Math.ceil(-1.6)  = -1

Math.floor(1.4)  = 1
Math.floor(1.6)  = 1
Math.floor(-1.4) = -2
Math.floor(-1.6) = -2

Math.round(1.4)  = 1
Math.round(1.6)  = 2
Math.round(-1.4) = -1
Math.round(-1.6) = -2

Activity 화면 방향 설정 - setRequestedOrientation

Activity 의 화면을 동적으로 설정 할수 있습니다.

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
= 세로방향.

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
= 가로방향.


        ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
        ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
        ActivityInfo.SCREEN_ORIENTATION_USER,
        ActivityInfo.SCREEN_ORIENTATION_BEHIND,
        ActivityInfo.SCREEN_ORIENTATION_SENSOR,
        ActivityInfo.SCREEN_ORIENTATION_NOSENSOR,
        ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE,
        ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT,
        ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE,
        ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT,
        ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR,

2011년 5월 25일 수요일

FreezesText - EditText

EditText 에서 android:freezesText = "true" 설정하면 화면 모드 전환시 EditText가
현재 상태를 계속 유지 할수있다.
( 현재 커서 위치, 입력된 Text 임시 저장 )

간단한 예제를 살펴보자.

    <EditText android:id="@+id/saved"
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@drawable/green"
        android:text="@string/initial_text"
        android:freezesText="true">
        <requestFocus /> - 해당 EditText 에 포커스를 주기 위해서 추가함.    </EditText>


public class SaveRestoreState extends Activity
{
    @Override
 protected void onCreate(Bundle savedInstanceState) {
        // Be sure to call the super class.
        super.onCreate(savedInstanceState);
        // See assets/res/any/layout/save_restore_state.xml for this
        // view layout definition, which is being set here as
        // the content of our screen.
        setContentView(R.layout.save_restore_state);
        // Set message to be appropriate for this screen.
        ((TextView)findViewById(R.id.msg)).setText(R.string.save_restore_msg);
    }
    /**
     * Retrieve the text that is currently in the "saved" editor.
     */
    CharSequence getSavedText() {
        return ((EditText)findViewById(R.id.saved)).getText();
    }

    /**
     * Change the text that is currently in the "saved" editor.
     */
    void setSavedText(CharSequence text) {
        ((EditText)findViewById(R.id.saved)).setText(text);
    }
}

Intent 유용한 Flag

Activity 간의 호출을 위해 Intent 를 사용한다.
하지만 아래와 같이 그냥 호출만 하게되면 호출 순서대로 차곡차곡
Activity Stack 에 쌓이게 된다.
startActivity(new Intent(ReorderThree.this, ReorderFour.class));
 
스택에 쌓이는 Activity 의 순서를 바꿔주기 위해서 안드로이드에서
FLAG_ACTIVITY 라는것을 제공해 주고있다.
 
            Intent intent = new Intent(ReorderFour.this, ReorderTwo.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);            startActivity(intent);
몇가지의 FLAG_ACTIVITY 들을 제공해 주고있다.
 
FLAG_ACTIVITY_SINGLE_TOP
-> 스택에 자기 자신 하나만 기록되게 한다.
FLAG_ACTIVITY_NO_HISTORY
-> 스택에 자신이 기록되지 않게 한다.
FLAG_ACTIVITY_REORDER_TO_FRONT
-> 스택에 자신을 최상위로 올려준다.
FLAG_ACTIVITY_CLEAR_TOP
-> 스택에 호출된 자신 외에는 모두 종료시킨다.
 
자세한 설명은
 

2011년 5월 23일 월요일

액티비티에서 결과값 받기 - Intent

A 라는 액티비티에서 B 라는 액티비티를 호출 후
B 액티비티에서 어떤 작업을 수행 후 결과값을 A 에게 보내줄때도
Intent 가 사용된다.

- B 액티비티 호출.
            Intent intent = new Intent(ReceiveResult.this, SendResult.class);
            startActivityForResult(intent, GET_CODE);

- B 액티비티에서 결과값 리턴.
            setResult(RESULT_OK, (new Intent()).setAction("Corky!"));

- A 액티비티에서 결과값 받기.
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == GET_CODE) {
            Editable text = (Editable)mResults.getText();
            if (resultCode == RESULT_CANCELED) {
                text.append("(cancelled)");
            } else {
                text.append("(okay ");
                text.append(Integer.toString(resultCode));
                text.append(") ");
                if (data != null) {
                    text.append(data.getAction());         <== 여기에서 결과값을 읽어옴.                }
            }
            text.append("\n");
        }
    }

전화번호부 예제 - QuickContactsDemo

public class QuickContactsDemo extends ListActivity {
    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
            Contacts._ID, // 0
            Contacts.DISPLAY_NAME, // 1
            Contacts.STARRED, // 2
            Contacts.TIMES_CONTACTED, // 3
            Contacts.CONTACT_PRESENCE, // 4
            Contacts.PHOTO_ID, // 5
            Contacts.LOOKUP_KEY, // 6
            Contacts.HAS_PHONE_NUMBER, // 7
    };
    static final int SUMMARY_ID_COLUMN_INDEX = 0;
    static final int SUMMARY_NAME_COLUMN_INDEX = 1;
    static final int SUMMARY_STARRED_COLUMN_INDEX = 2;
    static final int SUMMARY_TIMES_CONTACTED_COLUMN_INDEX = 3;
    static final int SUMMARY_PRESENCE_STATUS_COLUMN_INDEX = 4;
    static final int SUMMARY_PHOTO_ID_COLUMN_INDEX = 5;
    static final int SUMMARY_LOOKUP_KEY = 6;
    static final int SUMMARY_HAS_PHONE_COLUMN_INDEX = 7;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
                + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
                + Contacts.DISPLAY_NAME + " != '' ))";
        Cursor c =
                getContentResolver().query(Contacts.CONTENT_URI, CONTACTS_SUMMARY_PROJECTION, select,
                null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
        startManagingCursor(c);
        ContactListItemAdapter adapter = new ContactListItemAdapter(this, R.layout.quick_contacts, c);
        setListAdapter(adapter);
    }
    private final class ContactListItemAdapter extends ResourceCursorAdapter {
        public ContactListItemAdapter(Context context, int layout, Cursor c) {
            super(context, layout, c);
        }
        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            final ContactListItemCache cache = (ContactListItemCache) view.getTag();
            TextView nameView = cache.nameView;
            QuickContactBadge photoView = cache.photoView;
            // Set the name
            cursor.copyStringToBuffer(SUMMARY_NAME_COLUMN_INDEX, cache.nameBuffer);
            int size = cache.nameBuffer.sizeCopied;
            cache.nameView.setText(cache.nameBuffer.data, 0, size);
            final long contactId = cursor.getLong(SUMMARY_ID_COLUMN_INDEX);
            final String lookupKey = cursor.getString(SUMMARY_LOOKUP_KEY);
            cache.photoView.assignContactUri(Contacts.getLookupUri(contactId, lookupKey));
        }
        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            View view = super.newView(context, cursor, parent);
            ContactListItemCache cache = new ContactListItemCache();
            cache.nameView = (TextView) view.findViewById(R.id.name);
            cache.photoView = (QuickContactBadge) view.findViewById(R.id.badge);
            view.setTag(cache);
            return view;
        }
    }
    final static class ContactListItemCache {
        public TextView nameView;
        public QuickContactBadge photoView;
        public CharArrayBuffer nameBuffer = new CharArrayBuffer(128);
    }
}

임시 저장 - SharedPreferences

SharedPreferences 는 임시변수나 현재 UI 정보같은 작은 크기의 정보를 저장하기 적합하다.

조금 더 큰 데이터는 직접 파일에 쓰거나 SQL 을 사용하여 DB 에 저장하도록 하여야 한다.

    @Override
    protected void onPause() {
        super.onPause();
        SharedPreferences.Editor editor = getPreferences(0).edit();
        editor.putString("text", mSaved.getText().toString());
        editor.putInt("selection-start", mSaved.getSelectionStart());
        editor.putInt("selection-end", mSaved.getSelectionEnd());
        editor.commit();
    }

    @Override
    protected void onResume() {
        super.onResume();
        SharedPreferences prefs = getPreferences(0);
        String restoredText = prefs.getString("text", null);
        if (restoredText != null) {
            mSaved.setText(restoredText, TextView.BufferType.EDITABLE);
            int selectionStart = prefs.getInt("selection-start", -1);
            int selectionEnd = prefs.getInt("selection-end", -1);
            if (selectionStart != -1 && selectionEnd != -1) {
                mSaved.setSelection(selectionStart, selectionEnd);
            }
        }
    }

액티비티 호출하기 - intent

            Intent intent = new Intent();
            intent.setClass(Forwarding.this-호출하는 액티비티, ForwardTarget.class-호출할 액티비티);
            startActivity(intent);
            finish();

액티비티를 다이얼로그로 띄우기 - DialogActivity

Activity 를 Dialog 로 띄우는 간단한 예제.

CustomDialog 보다 구현하기 편하고 심플하다.

public class DialogActivity extends Activity {

    @Override
 protected void onCreate(Bundle savedInstanceState) {
        // Be sure to call the super class.
        super.onCreate(savedInstanceState);
       
        requestWindowFeature(Window.FEATURE_LEFT_ICON);
        setContentView(R.layout.dialog_activity);
        getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
                android.R.drawable.ic_dialog_alert);
    }
}


AndroidManifest.xml 파일에서 테마를 지정해 준다.

        <activity android:name=".app.DialogActivity"
                android:label="@string/activity_dialog"
                android:theme="@android:style/Theme.Dialog">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.SAMPLE_CODE" />
            </intent-filter>
        </activity>

타이틀바를 내맘대로 - CustomTitle

액티비티 화면 상단에 나타나는 타이틀 바를 내맘대로 바꿀수 있다.

코드는 생각보다 간단하다.

        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);        setContentView(R.layout.custom_title);
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title_1);

R.layout.custom_title_1.xml  파일에 타이틀 바에서 보여주고 싶은 것을 구성한다.

아래는 TextView 2개를 타이틀바 왼쪽과 오른쪽에 배치한 레이아웃이다.


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/screen"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView android:id="@+id/left_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:text="@string/custom_title_left" />
    <TextView android:id="@+id/right_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="@string/custom_title_right" />
</RelativeLayout>

액티비티를 다이얼로그로 띄우기 - CustomDialogActivity

Dialog 테마를 사용해서 Activity 를 Dialog 처럼 배경위에 띄울 수 있다.

다른 Activity 에서 아래 CustomDialogActivity 를 Intent 로 호출하면 Dialog 창이 뜬다.


[ CustomDialogActivity.java ]

public class CustomDialogActivity extends Activity {
    @Override
 protected void onCreate(Bundle savedInstanceState) {
        // Be sure to call the super class.
        super.onCreate(savedInstanceState);
       
        // See assets/res/any/layout/dialog_activity.xml for this
        // view layout definition, which is being set here as
        // the content of our screen.
        setContentView(R.layout.custom_dialog_activity);
    }
}

[ custom_dialog_activity.xml ]

<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:gravity="center_vertical|center_horizontal"
    android:text="@string/custom_dialog_activity_text"/>

위의 두 파일을 보면 Activity 에서 TextView 를 보여주는것 외에는 별다른점이 없다.

어디에서 CustomDialog 를 띄워 주는 것일까?

이번 예제에서 가장 중요한 핵심은 AndroidManifest.xml 파일에 있다.

AndroidManifest.xml  파일에서 CustomDialogActivity 를 정의한 부분을 자세히 보자.

[ AndroidManifest.xml ]

        <activity android:name=".app.CustomDialogActivity"
                android:label="@string/activity_custom_dialog"
                android:theme="@style/Theme.CustomDialog">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.SAMPLE_CODE" />
            </intent-filter>
        </activity>

activity 에 테마를 적용하는것을 볼수있다.

[ style.xml ]

    <style name="Theme.CustomDialog" parent="android:style/Theme.Dialog">
        <item name="android:windowBackground">@drawable/filled_box</item>
    </style>


[ filled_box.xml ]

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#f0600000"/>
    <stroke android:width="3dp" color="#ffff8080"/>
    <corners android:radius="3dp" />
    <padding android:left="10dp" android:top="10dp"
        android:right="10dp" android:bottom="10dp" />
</shape>

Activity 변경 애니메이션 효과 - overridePendingTransition

안드로이드 2.0 ( api level 5 ) 부터 액티비티가 보여지고, 없어질때 뷰처럼 애니메이션을
설정할 수 있다.

사용법도 간단하다.
startActivity(); 를 하고, overridePendingTransition( R.anim.new_activity, R.anim.old_activity );

애니메이션이 설정되지 않은 경우는 새 액티비티는 오른쪽에서 슬라이드-인 되고,
기존 액티비티는 왼쪽으로 슬라이드-아웃 된다.

애니메이션은 기존 방식과 동일하게 res/anim 폴더에 xml 로 작성하던가,
Animation 객체를 생성해 사용해도 된다.

[ fade - animation ]

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
       android:interpolator="@android:anim/accelerate_interpolator"
       android:fromAlpha="0.0" android:toAlpha="1.0"
       android:duration="@android:integer/config_longAnimTime" />

[ hold - animation ]

<translate xmlns:android="http://schemas.android.com/apk/res/android"
       android:interpolator="@android:anim/accelerate_interpolator"
       android:fromXDelta="0" android:toXDelta="0"
       android:duration="@android:integer/config_longAnimTime" />

[ zoom_enter- animation ]

<set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/decelerate_interpolator">
    <scale android:fromXScale="2.0" android:toXScale="1.0"
           android:fromYScale="2.0" android:toYScale="1.0"
           android:pivotX="50%p" android:pivotY="50%p"
           android:duration="@android:integer/config_mediumAnimTime" />
</set>

[ zoom_exit - animation ]

<set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/decelerate_interpolator"
        android:zAdjustment="top">
    <scale android:fromXScale="1.0" android:toXScale=".5"
           android:fromYScale="1.0" android:toYScale=".5"
           android:pivotX="50%p" android:pivotY="50%p"
           android:duration="@android:integer/config_mediumAnimTime" />
    <alpha android:fromAlpha="1.0" android:toAlpha="0"
            android:duration="@android:integer/config_mediumAnimTime"/>
</set>