Lazy 오목 Online!

 

- 게임물등급위원회 전체용가 -


 

- 인공지능 플레이 기능 -

- 터치실수를 없애기위해 두번 터치해야 돌 놓아지는 시스템 적용 -

- 온라인상의 다른 유저와 게임기능 -

- 채팅 기능 -

- 렌주룰에의한 금수 완벽 적용(단 AI 플레이시는 제외) -

- 백이 금수(3*3,4*4,6목,장목)를 이용하여 승리할 경우 가산점 부여 -

- 유저랭킹 및 금수랭킹 기능 -


- 전화번호로 직접요청 가능-

- 다른 작업중에도 내 차례가 되면 노티 해주는 기능 -


- 룰정보 확인 -



Lazy 오목용 유저 게시판을 만들었습니다. 
아래 주소로 접속해 주세요.

http://apps.silpir.net
 



업데이트 로그
- v2.2 ad
    - 네트워크 연결 안되어있어도 AI 와 플레이 가능
    - 전체적인 반응속도 대폭 개선
    - 렌주룰완전 적용
    - 서버 안정화

- v2.15 ad
   - 채팅 기능이 추가되었습니다.

- v2.1 ad
   - 흑이 3/3/3,4/4/4 되던거 안되도록 수정
   - 게임에 들어가자마자 메뉴 버튼을 누르면 튕기던 버그 수정
   - 금수로 승리하면 +1 점 추가됩니다.
   - 영어옵션 추가 (번역이 완벽하지 않습니다.)
   - 종료예약 추가
    - 사운드 추가
    - 최근게임리스트 추가
    - 노티가 너무 많이나오던거 수정




- v2.0 ad
   - 흑(선) 플레이시 3*3, 4*4, 6목 모두 안되게 수정
   - 룰정보 페이지 추가 (게임룰,금수룰,점수룰 설명)
   - 커뮤니케이션용 홈페이지 생성 : http://apps.silpir.net
   - 여러 디바이스 대응을 위해서 레이아웃의 크기단위를 dp 로 수정
   - 게임랭킹 기존 11개에서 15개 보이도록 수정


- v1.9 ad
   - 점수 시스템 개선 --> 30일동안 업데이트가 없는 점수데이터는 다른 유저의 점수에 영향을 미치지 않고 삭제됨
   - 랭킹화면에서 원하는 유저를 클릭하면 "게임신청" 이 나와서 직접 신청할수 있는 기능
   - 흑(선) 플레이시 3*3 룰을 적용받는 기능 ( 단 컴퓨터 "autobot" 은 3/3 적용받지 않음 )
   - 현재 기다린 시간 표시해주는 기능
   - 웹 클라이언트와 대국시 점수반영안되게 함.


- v1.82 ad
<광고 삽입>
   - 사용자가 많아지다보니 서버유지가 힘들어져 서버유지 비용을 벌기위해 광고 삽입


- v1.8 beta
<노티 시스템 업데이트>
    - 내가 해야할 차례라면 어플을 꺼놔도 노티가 오게 됩니다. (예를들어 게임대기를 눌러놓고 어플을 꺼놓으면 게임이 시작될때 문자온것과 똑같이 노티로 알려주게 됩니다.)

    - 어플을 처음 실행하면 가장최근에 플레이한 게임으로 자동으로 이동시켜주는 기능이 있었는데 이 기능을 빼고 내가 해야할 게임들의 노티를 띄우도록 하였습니다. (여러게임을 동시에 진행하고 있다면 이 기능이 오히려 불편하기 때문입니다.)


<기타 버그수정>
   - 노티로 오는 전화번호가 가려지지않고 모두 나오던것 수정

   - 노티가 제대로 동작하지 않던것 수정



====== 룰 정보 =======

렌주룰
- LazyOmok 은 렌주룰을 따릅니다.
- 렌주룰은 먼저하는 흑의 유리함을 어느정도 없애기위해 개발된 룰입니다.
- 간단한 룰에대해서는 아래에 정리하였습니다.
- 그 외에 자세한 정보를 원하시면 아래 홈페이지를 이용해 주시기 바랍니다.
- http://www.renjukorea.com

게임룰
승리
- 자신의 돌을 가로,세로 혹은 대각선중의 하나로 5개 연속으로 놓으면 승리하게 됩니다.
- 백은 6개 이상 연속으로 놔도 승리 처리됩니다.
- 게임중 상대 턴인 상태에서 5분이상 기다렸을때 종료하면 승리하게 됩니다.
패배
- 상대가 먼저 승리조건을 만족시키면 패배합니다.
- 게임중 자신의 턴인 상태에서 종료하면 패배합니다.

금수룰
- LazyOmok 에서는 먼저하는 흑의 유리함을 어느정도 없애기 위해서 유저가 흑 플레이시 금수를 적용하고 있습니다.
- LazyOmok 에서 금수는 3*3, 4*4, 6목, 장목 입니다.
- 장목은 돌을 6개 이상 이어나가는것을 말합니다.
- 백과, AI(autobot)는 금수룰을 적용받지 않습니다.
- 만약 이길수 있는 자리에 금수가 겹쳐있다면 금수우선룰에 의해 놓을수 없게 됩니다.

점수룰
- 점수는 승리시 +2 점, 패배시 -2점 입니다.
- 만약 백이 금수로 승리할때에는 승점에 +1 점 추가됩니다.
- 점수는 유저랭킹과 금수승랭킹으로 나뉘어서 저장됩니다.
- 30일동안 점수의 업데이트가 없으면 자동으로 점수데이터가 초기화됩니다.


 
언젠가 아이폰용 한게임 고스돕을 해본적이 있습니다.

상당한 퀄리티에 잘 만들어져 있었으나 한가지 불편한점이 있었습니다.

 

바로 게임도중 끊기면 그 판이 날라간다는 것이지요.

이런 상황이 발생하면 폰 탓만 했는데 그게 아니라는 생각이 들었습니다.

 

아무리 현재 3G 가 좋아졌고 곳곳에 와이파이 존이 있다고 하지만

여러가지 다른 환경적인 요인에 의해서 순간적으로 네트웍이 끊기는 상황은 자주 나타나고 있습니다.

 

이러한 상황에서 끊김없는PC 에서 하던것과 똑같이 온라인게임을 만들면,

위와 같이 해당 게임이 날라가는 상황을 피할수 없게 됩니다.

 

그래서 좀 더 모바일 환경에 맞는 Online게임을 만들수 없을까?

라는 생각에서 나온것이 바로 “Lazy 오목 Online!” 입니다.

 

이 게임은 모바일에서 메시지 주고받듯이 게임을 진행할 수 있습니다.

예를들면 게임을 시작하고 자신의 차례가 되면 아래와 같은 노티가 오게됩니다.

해당 노티를 터치하면 바로 해당 게임으로 넘어가게 되고 플레이를 계속할 수 있게 됩니다.

(단 이러한 노티는 게임을 Home 키를 눌러서 백그라운드 상태로 돌려놨을때만 동작합니다. 즉 현재 게임화면을 보고있으면 노티가 오지 않습니다.)

 

또한 이 게임은 시간제한이 없습니다.

PC 에서처럼 모바일 환경은 언제나 게임에 집중할 수 없기 때문에 시간제한을 없앴습니다.

대신 누구나 종료할수 있도록 만들었습니다.

 

이렇게 시간제한 없이 게으른 플레이를 할 수 있다고 하여서 이름도 “Lazy” 입니다.^^

 

 

by cranix 2011. 2. 14. 13:36

안드로이드에서 기본적으로 지원하지 않는 UI 를 만들때 CustomView 를 사용합니다.

이러한 CustomView 의 기본적인 작성방법을 알아보도록 하겠습니다.

 

CustomView 는 “android.view.View” 클래스를 상속해서 만들어 집니다.

기본적으로 onDraw() 메소드만 재정의해서 xml 에 view 태그만 추가하면 오류없이 출력되는것을 볼 수 있습니다.

 

이번 포스트에서는 간단히 클릭하면 반응하는 CustomView 를 만들어 보도록 하겠습니다.

먼저 CustomView 소스를 확인해 보도록 하겠습니다.

 

- CustomView.java

package net.cranix.android.customviewtest;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;

public class CustomView extends View {

private String text = null;
private int backgroundColor = Color.RED;

private String tempText;


// 속성이 없는 생성자는 소스상에서 직접 생성할때만 쓰인다.
public CustomView(Context context) {
super(context);
Log.w(Constants.TAG,"CustomView("+context+")");
}
/*
* 리소스 xml 파일에서 정의하면 이 생성자가 사용된다.
*
* 대부분 this 를 이용해 3번째 생성자로 넘기고 모든 처리를 3번째 생성자에서 한다.
*/
public CustomView(Context context,AttributeSet attrs) {
this(context,attrs,0);
Log.w(Constants.TAG,"CustomView("+context+","+attrs+")");
}

/*
* xml 에서 넘어온 속성을 멤버변수로 셋팅하는 역할을 한다.
*/
public CustomView(Context context,AttributeSet attrs,int defStyle) {
super(context,attrs,defStyle);

this.text = attrs.getAttributeValue(null,"text");

Log.w(Constants.TAG,"CustomView("+context+","+attrs+","+defStyle+"),text:"+text);
}

/*
* xml 로 부터 모든 뷰를 inflate 를 끝내고 실행된다.
*
* 대부분 이 함수에서는 각종 변수 초기화가 이루어 진다.
*
* super 메소드에서는 아무것도 하지않기때문에 쓰지 않는다.
*/
@Override
protected void onFinishInflate() {
setClickable(true);
Log.w(Constants.TAG,"onFinishInflate()");
}

/*
* 넘어오는 파라메터는 부모뷰로부터 결정된 치수제한을 의미한다.
* 또한 파라메터에는 bit 연산자를 사용해서 모드와 크기를 같이 담고있다.
* 모드는 MeasureSpec.getMode(spec) 형태로 얻어오며 다음과 같은 3종류가 있다.
* MeasureSpec.AT_MOST : wrap_content (뷰 내부의 크기에 따라 크기가 달라짐)
* MeasureSpec.EXACTLY : fill_parent, match_parent (외부에서 이미 크기가 지정되었음)
* MeasureSpec.UNSPECIFIED : MODE 가 셋팅되지 않은 크기가 넘어올때 (대부분 이 경우는 없다)
*
* fill_parent, match_parent 를 사용하면 윗단에서 이미 크기가 계산되어 EXACTLY 로 넘어온다.
* 이러한 크기는 MeasureSpec.getSize(spec) 으로 얻어낼 수 있다.
*
* 이 메소드에서는 setMeasuredDimension(measuredWidth,measuredHeight) 를 호출해 주어야 하는데
* super.onMeasure() 에서는 기본으로 이를 기본으로 계산하는 함수를 포함하고 있다.
*
* 만약 xml 에서 크기를 wrap_content 로 설정했다면 이 함수에서 크기를 계산해서 셋팅해 줘야한다.
* 그렇지 않으면 무조껀 fill_parent 로 나오게 된다.
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// height 진짜 크기 구하기
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = 0;
switch(heightMode) {
case MeasureSpec.UNSPECIFIED: // mode 가 셋팅되지 않은 크기가 넘어올때
heightSize = heightMeasureSpec;
break;
case MeasureSpec.AT_MOST: // wrap_content (뷰 내부의 크기에 따라 크기가 달라짐)
heightSize = 20;
break;
case MeasureSpec.EXACTLY: // fill_parent, match_parent (외부에서 이미 크기가 지정되었음)
heightSize = MeasureSpec.getSize(heightMeasureSpec);
break;
}

// width 진짜 크기 구하기
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = 0;
switch(widthMode) {
case MeasureSpec.UNSPECIFIED: // mode 가 셋팅되지 않은 크기가 넘어올때
widthSize = widthMeasureSpec;
break;
case MeasureSpec.AT_MOST: // wrap_content (뷰 내부의 크기에 따라 크기가 달라짐)
widthSize = 100;
break;
case MeasureSpec.EXACTLY: // fill_parent, match_parent (외부에서 이미 크기가 지정되었음)
widthSize = MeasureSpec.getSize(widthMeasureSpec);
break;
}


Log.w(Constants.TAG,"onMeasure("+widthMeasureSpec+","+heightMeasureSpec+")");

setMeasuredDimension(widthSize, heightSize);
}


/*
* onMeasure() 메소드에서 결정된 width 와 height 을 가지고 어플리케이션 전체 화면에서 현재 뷰가 그려지는 bound 를 돌려준다.
*
* 이 메소드에서는 일반적으로 이 뷰에 딸린 children 들을 위치시키고 크기를 조정하는 작업을 한다.
* 유의할점은 넘어오는 파라메터가 어플리케이션 전체를 기준으로 위치를 돌려준다.
*
* super 메소드에서는 아무것도 하지않기때문에 쓰지 않는다.
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
Log.w(Constants.TAG,"onLayout("+changed+","+left+","+top+","+right+","+bottom+")");
}


/*
* 이 뷰의 크기가 변경되었을때 호출된다.
*
* super 메소드에서는 아무것도 하지않기때문에 쓰지 않는다.
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {

Log.w(Constants.TAG,"onSizeChanged("+w+","+h+","+oldw+","+oldh+")");
}


/*
* 실제로 화면에 그리는 영역으로 View 를 상속하고 이 메소드만 구현해도 제대로 보여지게 된다.
*
* 그릴 위치는 0,0 으로 시작해서 getMeasuredWidth(), getMeasuredHeight() 까지 그리면 된다.
*
* super 메소드에서는 아무것도 하지않기때문에 쓰지 않는다.
*/
@Override
protected void onDraw(Canvas canvas) {
final Paint p = new Paint();
p.setColor(backgroundColor);
canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(), p);
if (text != null) {
p.setColor(Color.BLACK);
canvas.drawText(text, 10, 15, p); // 왼쪽 아래를 0,0 으로 보고있음
}
Log.w(Constants.TAG,"onDraw("+canvas+")");
}


/*
* 현재 view 가 focus 상태일때 key 를 누르면 이 메소드가 호출됨.
* 즉 이 메소드를 사용하려면 setFocusable(true) 여야함.
*
* 그리고 super 메소드에서는 기본적인 키 작업(예를들면 BACK 키 누르면 종료)을 처리하기 때문에 일반적으로 return 시에 호출하는게 좋다.
* 만약 기본적인 작업을 하지않게 하려면 super 함수를 호출하지 않아도 된다.
*
* 다른 event 메소드들도 유사하게 동작한다.
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.w(Constants.TAG,"onKeyDown("+keyCode+","+event+")");
return super.onKeyDown(keyCode, event);
}

/*
* 이 view 에 touch 가 일어날때 실행됨.
*
* 기본적으로 touch up 이벤트가 일어날때만 잡아내며
* setClickable(true) 로 셋팅하면 up,move,down 모두 잡아냄
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.w(Constants.TAG,"onTouchEvent("+event+")");
switch(event.getAction()) {
case MotionEvent.ACTION_UP:
backgroundColor = Color.RED;
text = tempText;
break;
case MotionEvent.ACTION_DOWN:
backgroundColor = Color.YELLOW;
tempText = text;
text = "Clicked!";
break;
case MotionEvent.ACTION_MOVE:
backgroundColor = Color.BLUE;
text = "Moved!";
break;
}
invalidate();
return super.onTouchEvent(event);
}


public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}

- 크기 계산하기

여기서 중요한 메소드는 onMeasure() 메소드 입니다.

이 메소드는 뷰의 전체 크기를 정하는 메소드 인데 안드로이드의 크기 정하는 방법에 따라 구현법이 달라져야 합니다.

 

안드로이드 레이아웃 xml 파일에서 크기를 지정하는 방법은 4가지가 있습니다.

   - fill_parent (상위 View 의 크기에 따름)

   - match_parent (상위 View 의 크기에 따름)

   - fixed (100px 와 같이 픽셀로 박아놨을때)

   - wrap_content (현재 뷰의 내용에 따름)

 

이렇게 4가지 방법의 특성에 따라서 넘어오는 크기의 종류는 3가지로 구분됩니다.

   - MeasureSpec.EXACTLY : fill_parent, match_parent, fixed 와 같이 상위에서 이미 결정되어버린 크기가 넘어올때 선택됩니다.

   - MeasureSpec.AT_MOST : wrap_content 를 선택했을때 선택됩니다.

   - MeasureSpec.UNSPECIFIED : xml 에 의하지 않고 소스상에서 직접 넣었을 때 나옵니다.

 

여기서 EXACTLY 과 UNSPECIFIED 는 외부에서 크기가 구해져서 내려오는 것이기 때문에 따로 계산할 것이 없으나 AT_MOST 는 내부적으로 크기계산을 해 주어야 합니다.

위의 소스에서는 간단하게 100,20 으로 박아놨지만 실제로 CustomView 를 구현하게 된다면 뷰의 특성에 따라 구현이 달라져야 할 것입니다.

 

 

- xml 에서 파라메터 받아내기

안드로이드 리소스 xml 에서 파라메터를 받아내려면 위 소스의 3번째 생성자에 있는것 처럼 아래와 같은 구문을 써야 합니다.

this.text = attrs.getAttributeValue(null,"text");

 

 

- xml 파일 구성하기

이렇게 만든 CustomView 를 xml 파일에서 사용하려면 아래와같은 xml 구성이 필요합니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<view class="net.cranix.android.customviewtest.CustomView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
text="test"
/>
</LinearLayout>

 

- 실행해 보기

이렇게 구성된 뷰를 Activity 에 넣고 실행해 보면 아래와 같은 화면이 나옵니다.

마우스를 클릭,이동 할때마다 색깔이 변경되는것을 볼 수 있습니다.

image

image

image

by cranix 2011. 1. 7. 17:03

image

 

이것은 안드로이드 Tab UI 를 구성하는 구성요소 입니다.

안드로이드 Tab UI 는 이와같이 세 개의 다른 클래스들의 집합으로 이루어져 있습니다.

 

TabHost 는 TabUI 를 구성하는 전체 틀 입니다.

여기에는 특정한 android:id 를 가지는 TabWidget 와 TabSpec 이 포함되어야 합니다.

 

TabWidget 는  TabUI 에서 선택하는 버튼이 나오는 부분을 말하며 이것의 android:id 는 반드시 “@android:id/tabs” 가 되어야 합니다.

 

TabSpec 는 하나의 탭을 구성하는 구성요소들의 집합으로서 View 의 하위구성요소가 아니기 때문에 layout xml 파일에 직접 추가될 수 없습니다. 그래서 java 소스코드상으로 추가해 주어야 하며 layout xml 에는 이를 표시하기 위하여 “@android:id/tabcontent” 라는 android:id 를 가지는 Layout View 가 추가되어 있어야 합니다.

 

 

이렇게 글로만 보면 상당히 어렵게 보이는데 이것을 쉽게 쓰도록 만들어 놓은것이 바로 TabActivity 클래스 입니다.

아래는 TabActivity 를 이용하여 layout xml 파일 없이 TabUI 를 구성하는 예 입니다.

package net.cranix.android.cranixcontact;

import android.app.TabActivity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TabHost;

public class CranixContact extends TabActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

final TabHost tabHost = getTabHost();
tabHost.addTab(
tabHost.newTabSpec("tab1")
.setIndicator("Contacts")
.setContent(new Intent(this,ContactsTabActivity.class))
);
tabHost.addTab(
tabHost.newTabSpec("tab2")
.setIndicator("Calllog")
.setContent(new Intent(this,CalllogTabActivity.class))
);
}
}

위의 소스에는 layout xml 파일이 사용되는 부분이 없지만 TabActivity 내부적으로 기본적인 layout 을 사용하고 있습니다.

그렇다면 TabActivity 에서 사용하는 기본적인 layout 은 무엇일까요?

 

안드로이드 소스를 직접 다운받아서 xml 파일을 뒤져보면 아래와 같은 레이아웃 파일을 발견할 수 있습니다.

<TabHost xmlns:android="http://schemas.android.com/apk/res/android" 
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0" />
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"/>
</LinearLayout>
</TabHost>

이것이 바로 TabActivity 클래스가 기본으로 사용하는 layout xml 파일입니다.

위에서 말로 설명한 부분에 나와있는 대로 구성되어있는것을 확인할 수 있습니다.

 

TabActivity 를 상속받은 Activity 라면 기본적으로 위와같은 layout xml 파일이 contentView 로 자동으로 셋팅됩니다.

이것을 염두해 두고 개발을 해야지 오류를 피할수 있습니다.

 

그럼 내가만든 layout xml 을 TabActivity 에 띄우는 예제를 만들어 보겠습니다.

먼저 layout 을 구성합니다 파일이름은 main.xml 입니다.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:text="@+id/TextView01"
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button android:text="@+id/Button01"
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>

 

이것을 TabActivity 에 띄우는 java 코드는 아래와 같습니다.

package net.cranix.android.testtabactivity;

import android.app.TabActivity;
import android.os.Bundle;
import android.widget.TabHost;

public class TestTabActivity extends TabActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
final TabHost tabHost = getTabHost();

getLayoutInflater().inflate(R.layout.main, tabHost.getTabContentView());

tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator("tab1").setContent(R.id.TextView01));
tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator("tab2").setContent(R.id.Button01));
}
}
 
 
TabSpec.setContent 에 view 를 지정하려면 반드시 @”android:id/tabcontent” 의 하위 뷰 여야 합니다.
그래서 자신이 만든 layout 을 기존에 있던 tabHost 의 tabContentView 에 inflate 를 활용하여 붙혀주는 것 입니다.

 

위의 굵은 글씨에 의해 inflat 가 실행된 이후에는 layout 을 아래와 같이 인식합니다.

<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_weight="0" />
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1">
<TextView android:text="@+id/TextView01"
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button android:text="@+id/Button01"
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
</LinearLayout>
</TabHost>

결국 위와 같이 tabSpec 을 만들때 setContent 에다가 자신이 만든 layout 을 사용할 수 있게 되는것 입니다.

 

이렇게 TabActivity 가 돌아가는 구조를 알아내면 응용도 가능합니다.

아래 예제는 안드로이드 TabUI 에서 TabWidget 이 아래에 있도록 구성한 Activity 입니다.

먼저 layout 파일은 아래와같이 구성합니다.

<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1">
<TextView android:text="@+id/TextView01"
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button android:text="@+id/Button01"
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
<TabWidget android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_weight="0" />
</LinearLayout>
</TabHost>

 

그다음 Activity 파일은 아래와 같이 구성합니다.

package net.cranix.android.testtabactivity;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TabHost;

public class TestTabActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TabHost tabHost = (TabHost) findViewById(R.id.tabhost);
tabHost.setup();

tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator("tab1").setContent(R.id.TextView01));
tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator("tab2").setContent(R.id.Button01));
}
}

실행해 보면 아래와 같이 탭이 아래에 있는것을 볼 수 있습니다.

 

image

 

여기서 중요한 것은 TabActivity 가 아니라 그냥 Activity 를 이용하였다는 것과 레이아웃 파일을 안드로이드 TabUI 에 맞게 직접 구성했다는점 입니다.

이렇게 TabActivity 를 통하지 않고 Tab 을 구현할 경우에는 반드시 tabHost.setup() 을 호출해 주어야 합니다.

여기서 TabHost view 하위에 있는 기본 뷰를 탐색해서 셋팅해 주게 됩니다.

즉 이 함수를 거치면 tabHost.getTabWidget() 과 tabHost.getTabContentView() 같은 메소드를 사용할때 null 이 반환되지 않게 됩니다.

 

결국 안드로이드 TabUI 는 기본적인 안드로이드 UI 구조를 가지고 TabUI 를 구성하기 편하게 상속하여 재작성 한 것입니다.

by cranix 2011. 1. 5. 15:49

안드로이드 SDK 에는 프레임웍 소스가 포함되어 있지 않습니다.

그러나 안드로이드 어플을 개발하다보면 프레임웍쪽 소스코드를 확인해 보고싶을때가 있습니다.

이번 포스트에서는 이클립스에서 편하게 안드로이드 프레임웍 소스를 따라갈 수 있도록 셋팅하는법을 알아보도록 하겠습니다.

 

 

1. 프레임웍 소스코드 다운받기

 

안드로이드 소스크도는 git 로 관리되기 때문에 윈도우에서 받으려면 윈도우용 git 클라이언트를 사용해야 합니다.

그래서 Tortoise 같은 git 클라이언트인 msysgit 를받아서 설치합니다.

 

http://code.google.com/p/msysgit/downloads/list

 

리스트중 “Git-1.7.3.1-preview20101002.exe” 를 다운로드 합니다.

 

설치하고 git-gui 를 실행하면 아래와 같은 화면이 나옵니다.

 

image

 

여기서 “Clone Existing Repository” 를 선택하면 다음과 같은 화면이 나옵니다.

 

image

 

여기에 Source Location 은 “git://android.git.kernel.org/platform/frameworks/base.git” 으로 입력하고 Target Directory 는 적절히 선택해서 “Clone” 버튼을 클릭합니다.

 

image

 

이와 같은 화면이 나오는데 여기서 상당히 오래 걸립니다.

다운된거 같지만 다운된게 아니니 기다려주세요.(약 10분)

 

작업이 완료되면 아래와 같은 화면이 나옵니다.

image

 

이제 위에서 지정했던 “Target Directory” 를 확인해보면 소스코드가 다운받아져 있는것을 확인할 수 있습니다.

 

 

 

2. 이클립스 안드로이드 라이브러리에 소스코드 연결시키기

 

이클립스의 안드로이드 프로젝트의 Properties > Java Build Path 에 들어가서 Libraries 탭에 갑니다.

image

위와 같이 android.jar 파일의 Source attachment 가 none 으로 셋팅되어 있는것을 볼 수 있습니다.

이것을 더블클릭해서 “External Folder” 를 클릭합니다.

아래와 같이 소스를 다운받은 “Target Directory” 아래에 “core/java” 디렉토리를 선택합니다.

 

image

 

 

이제 아래와 같이 마음껏 프레임웍 소스를 확인할 수 있습니다.

image

by cranix 2011. 1. 4. 15:54

톰켓홈에서 tar.gz 바이너리 다운로드

wget http://apache.tt.co.kr/tomcat/tomcat-7/v7.0.5-beta/bin/apache-tomcat-7.0.5.tar.gz

 

 

압축해제

tar -zxvf apache-tomcat-7.0.5.tar.gz

 

 

tomcat 디렉토리 생성

mkdir /usr/local/tomcat

 

 

압축푼 톰켓 디렉토리 복사

mv apache-tomcat-7.0.5 /usr/local/tomcat/

 

심볼릭 링크 생성

cd /usr/local/tomcat

ln –s apache-tomcat-7.0.5/ default

 

실행확인

cd /usr/local/tomcat/default/bin

./startup.sh

[브라우저로 http://localhost:8080] 접속

 

 

시작프로그램에 등록

/etc/init.d/tomcat 스크립트 작성

#!/bin/sh
#
# Tomcat7 auto-start
#
# chkconfig: 2345 90 90
# description: Auto-starts tomcat
# processname: tomcat
# pidfile: /var/run/tomcat.pid
case $1 in
start)
    sh /usr/local/tomcat/default/bin/startup.sh
    ;;
stop)
    sh /usr/local/tomcat/default/bin/shutdown.sh
    ;;
restart)
    sh /usr/local/tomcat/default/bin/shutdown.sh
    sh /usr/local/tomcat/default/bin/startup.sh
    ;;
esac
exit 0

'알짜정보 > Linux server' 카테고리의 다른 글

snmpwalk 사용법  (12) 2012.12.16
centos 에 시작프로그램 등록하기.  (41) 2012.12.15
cent os svn server 설치  (28) 2011.01.02
cent os 런레벨  (30) 2011.01.02
cent os chkconfig 이용해서 시작프로그램 등록하기  (61) 2011.01.02
by cranix 2011. 1. 3. 10:36
svn 설치 & mod_dav_svn 설치
yum install subversion
yum install mod_dav_svn  (아파치와 svn 연동을 위한 모듈)

유저별 svn 저장소 만들기
$ mkdir svnroot
$ cd svnroot
$ svnadmin create cranix (레퍼지토리 cranix 만들기)
$ htpasswd -c htsvnusers cranix (레퍼지토리에 접근할 수 있는 user 만들기)
$ chgrp -R apache cranix (레퍼지토리 에 apache 권한 주기)
$ chmod -R g+w cranix (그룹에 쓰기권한 주기)


virtual host 파일 만들기
<VirtualHost *:80>
        ServerName svn.cranix.net
        <Location "/">
                DAV svn
                SVNParentPath /home/cranix/svnroot
                AuthType Basic
                AuthName "cranix repository"
                AuthUserFile /home/cranix/svnroot/htsvnusers
                Require valid-user
                Order Deny,Allow
                Allow from all
        </Location>
</VirtualHost>

아파치를 리스타트 하고 http://svn.cranix.net/cranix 형태로 접근 가능

htpasswd 를 이용한 사용자 추가/변경/삭제
htpasswd htsvnusers cranix (만약에 있다면 변경 없다면 추가)
htpasswd -D htsvnusers cranix (cranix 유저 삭제)


 

'알짜정보 > Linux server' 카테고리의 다른 글

centos 에 시작프로그램 등록하기.  (41) 2012.12.15
cent os tomcat7 설치  (37) 2011.01.03
cent os 런레벨  (30) 2011.01.02
cent os chkconfig 이용해서 시작프로그램 등록하기  (61) 2011.01.02
cent os vsftp 설치하기  (23) 2011.01.02
by cranix 2011. 1. 2. 21:53

런레벨 확인
runlevel


런레벨 종류
- 런레벨 0 : Shutdown 모드
- 런레벨 1 : 싱글모드 부팅
- 런레벨 2 : NFS 를 사용하지 않는 다중 사용자 모드
- 런레벨 3 : 콘솔모드로 부팅 (기본 부팅상태)
- 런레벨 4 : 사용하지 않음
- 런레벨 5 : X 윈도우로 부팅
- 런레벨 6 : 지속적인 재부팅


런레벨에 따른 시작 프로그램 디렉토리
- /etc/rc.d/init.d/rcx.d


'알짜정보 > Linux server' 카테고리의 다른 글

cent os tomcat7 설치  (37) 2011.01.03
cent os svn server 설치  (28) 2011.01.02
cent os chkconfig 이용해서 시작프로그램 등록하기  (61) 2011.01.02
cent os vsftp 설치하기  (23) 2011.01.02
cent os apache virtual host 설정  (18) 2011.01.02
by cranix 2011. 1. 2. 21:21


1. 등록된 런레벨 확인하기
chkconfig --list [이름]

2. 런레벨에 등록하기
chkconfig --levell 1 httpd on





'알짜정보 > Linux server' 카테고리의 다른 글

cent os svn server 설치  (28) 2011.01.02
cent os 런레벨  (30) 2011.01.02
cent os vsftp 설치하기  (23) 2011.01.02
cent os apache virtual host 설정  (18) 2011.01.02
cent os php 설치  (35) 2011.01.02
by cranix 2011. 1. 2. 21:17

설치
yum install vsftpd


설정파일
/etc/vsftpd/vsftpd.conf

설정하기
1. 단순하게 사용자 계정에 chroot 설정
chroot_local_user=YES
2. 특정 사용자만 chroot 설정
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd/chroot_list

3. 특정 사용자를 제외한 나머지 사용자만 chroot 설정
chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd/chroot_list

4. 계정마다 동적으로 설정할 경우
chroot_local_user=YES
passwd_chroot_enable=YES

이런식으로 하면 /etc/passwd 파일을 참고하여 chroot 를 설정할 수 있다.
아래와 같은 형태로 passwd 파일을 셋팅하면 "." 이 있는곳이 루트 디렉토리가 된다.
cranix:x:500:500::/home/./cranix:/bin/bash

'알짜정보 > Linux server' 카테고리의 다른 글

cent os 런레벨  (30) 2011.01.02
cent os chkconfig 이용해서 시작프로그램 등록하기  (61) 2011.01.02
cent os apache virtual host 설정  (18) 2011.01.02
cent os php 설치  (35) 2011.01.02
cent os mysql 설치  (30) 2011.01.02
by cranix 2011. 1. 2. 20:41

NameVirtualHost *:80

<VirtualHost *:80>
ServerName domain1
...
</VirtualHost>


<VirtualHost *:80>
ServerName domain2
...
</VirtualHost>


<VirtualHost *:80>
ServerName domain3
...
</VirtualHost>

'알짜정보 > Linux server' 카테고리의 다른 글

cent os chkconfig 이용해서 시작프로그램 등록하기  (61) 2011.01.02
cent os vsftp 설치하기  (23) 2011.01.02
cent os php 설치  (35) 2011.01.02
cent os mysql 설치  (30) 2011.01.02
cent os apache 설치  (28) 2011.01.02
by cranix 2011. 1. 2. 19:57
| 1 2 3 4 5 6 ··· 33 |