'안드로이드 개발'에 해당되는 글 1건

  1. 2019.05.10 화면 유지 등

1. 스마트폰은 기본적으로 일정 시간동안 아무런 반응이 없으면 자동으로 화면이 꺼지게 됩니다.

원할 경우 실행되는 동안 화면을 안꺼지 게 할수 있습니다.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
을 추가하게 되면 실행되는 동안 화면이 꺼지지 않습니다.

2. Dialog 타이틀바 없애기.

3. EditText에 이벤트 주기

EditText 이벤트는 addTextChangedListener() 를 사용하면 보다 쉽게 다룰수가 있었다.( setOnClickListener() 보다 좋음.)

et.addTextChangedListener(new TextWatcher(){   

   public void afterTextChanged(Editable arg0) {
    // TODO Auto-generated method stub    
   }   

   public void beforeTextChanged(CharSequence s, int start, int count,
     int after) {
    // TODO Auto-generated method stub    
   }

   public void onTextChanged(CharSequence s, int start, int before,
     int count) {
    // TODO Auto-generated method stub
    
   }
         
});

4. intent : https://yoo-hyeok.tistory.com/15?category=708422 putExtra를 단일 String, ArrayList 모두 가능.

5. 서비스 등록하기

Service는 background에서 처리를 계속할 수 있는 클래스이다.
Service는 기본적으로 activity를 가지지 않는다.

서비스를 구현하기 위한 3가지 절차
-- Service 클래스를 확장한 새로운 클래스 정의
-- Manifest file에 Service 선언 추가
-- App에서 Service 실행



1. 서비스를 실행하는 클래스 - 타이머를 이용한 반복 처리.

public class MyService extends Service implements Runnable {

    // 시작 ID
    private int mStartId;
    // 서비스에 대한 스레드에 연결된 Handler. 타이머 이용한 반복 처리시 사용.
    private Handler mHandler;
    // 서비스 동작여부 flag
    private boolean mRunning;
    // 타이머 설정 (2초)
    private static final int TIMER_PERIOD = 2 * 1000; 
    private static final int COUNT = 10;
    private int mCounter;


    // 서비스를 생성할 때 호출
    public void onCreate() {
        Log.e("MyService", "Service Created.");
        super.onCreate();
        mHandler = new Handler();
        mRunning = false;
    }


    // 서비스 시작할 때 호출. background에서의 처리가 시작됨.
    // startId : 서비스 시작요구 id. stopSelf에서 종료할 때 사용. 

     //onStart는 여러번 호출될 수 있기 때문에 식별자로 사용.

    public void onStart(Intent intent, int startId) {
        Log.e("MyService", "Service startId = " + startId);
        super.onStart(intent, startId);
        mStartId = startId;
        mCounter = COUNT;

        // 동작중이 아니면 run 메소드를 일정 시간 후에 시작
        if (!mRunning) {
              // this : 서비스 처리의 본체인 run 메소드. Runnable 인터페이스를 구현 필요.
              // postDelayed : 일정시간마다 메소드 호출
              mHandler.postDelayed(this, TIMER_PERIOD);
              mRunning = true;
        }
    }

 

    // 서비스의 종료시 호출
    public void onDestroy() {
        // onDestroy가 호출되어 서비스가 종료되어도 
        // postDelayed는 바로 정지되지 않고 다음 번 run 메소드를 호출.
        mRunning = false;
        super.onDestroy();
    }



    // 서비스 처리
    public void run() {
        if (!mRunning) {
            // 서비스 종료 요청이 들어온 경우 그냥 종료
            Log.e("MyService", "run after destory");
            return;
        } else if (--mCounter <= 0) {
            // 지정한 횟수 실행하면 스스로 종료
            Log.e("MyService", "stop Service id = "+mStartId);
            stopSelf(mStartId);
        } else {
            // 다음 작업을 다시 요구
            Log.e("MyService", "mCounter : " + mCounter);
            mHandler.postDelayed(this, TIMER_PERIOD);
        }
    }

    // 원격 메소드 호출을 위해 사용
    // 메서드 호출을 제공하지 않으면 null을 반환
    public IBinder onBind(Intent intent) {
        return null;
    }
}




2. 서비스 실행, 종료를 사용자가 요청하는 클래스

// 서비스 시작과 종료를 요구하는 Activity
public class MyServiceActivity extends Activity {

    ComponentName mService;    // 시작 서비스의 이름
    TextView mTextView;              // 서비스 상태 표시



    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        mTextView = (TextView)findViewById(R.id.text_view);
        
        Button start = (Button)findViewById(R.id.start_button);
        start.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v) {
                startHelloService();
            }});
        
        Button stop = (Button)findViewById(R.id.stop_button);
        stop.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v) {
                stopHelloService();
            }});
    }



    // 서비스 시작 요청
    private void startHelloService() {
        mService = startService(new Intent(this, MyService.class));
        mTextView.append(mService.toShortString()+" started.\n");
    }

 

    // 실행한 서비스 중지 요청

    private void stopHelloService() {
        if (mService == null) {
            mTextView.append("No requested service.\n");
            return;
        }
        
        Intent i = new Intent();
        i.setComponent(mService);
        if (stopService(i))
            mTextView.append(mService.toShortString()+" is stopped.\n");
        else
            mTextView.append(mService.toShortString()+" is alrady stopped.\n");
    }
}


3. 사용자가 서비스 실행, 종료하는 화면 구성

<!-- 시작 -->
<Button android:id="@+id/start_button" android:text="Start"
android:layout_width="fill_parent" android:layout_height="wrap_content" />

<!-- 종료 -->
<Button android:id="@+id/stop_button" android:text="Stop"
android:layout_width="fill_parent" android:layout_height="wrap_content" />

<!-- 상태표시 -->
<TextView android:id="@+id/text_view_id"

android:editable="true"
android:layout_width="fill_parent" android:layout_height="fill_parent" />

6. 컴포넌트의 생명주기
컴포넌트의 생명주기는 컴포넌트를 인스턴스화 할 때 시작해서, 인스턴스가 사라질 때 종료됩니다.
액티비티의 경우 그 사이에 활성화, 비활성화가 될 수 있기 때문에 사용자에게 보이거나 , 또는 보이지 않을 수도 있습니다.

1. 액티비티 생명주기


액티비티는 필수적으로 세 가지의 상태를 가지고 있습니다.

▣ 활성화(activity) 또는 실행 (running) 상태

액티비티가 포그라운드 화면으로 사용자에게 보이는 상태입니다 ( 즉, 현재 태스크에서 스택의 최상위에 위치하는 것).
이 상태는 사용자 액션을 받을 수 있게 됩니다.


▣ 멈춤(paused) 상태

사용자 액션을 받진 못하지만 여전히 보여지고 있는 상태입니다. 즉 다른 액티비티가 그 위에 위치하지만 해당 액티비티가 화면을 전부 채우지 않거나 투명해서 멈춤 상태의 액티비티를 볼 수 있는 상태입니다.
이 상태의 액티비티는 살아있습니다 ( 모든 상태정보와 멤버를 유지 중 )
하지만 , 메모리 부족시엔 시스템에 의해 강제종료 될 수 있습니다.


▣ 정지 (stopped) 상태

완전히 다른 액티비티에 의해 가려진 상태입니다.더 이상 사용자에게 보이진 않지만 여전히 살아서(정보와 멤버유지) 있는 상태이죠.
여전히 보여지진 않기 때문에 메모리 부족시엔 강제종료 될 수 있습니다.



액티비티가 멈춤 또는 정지 상태라면, 시스템은 finish() 메소드를 호출하거나 프로세스를 강제종료 시킴으로서 메모리에서 제거할 수 있습니다.
종료된 액티비티가 다시 실행된다면, 다시 시작되어야 하고 이전 상태로 복구되어야 할 것입니다.



액티비티 상태변화


액티비티의 상태가 변하면 아래의 메소드가 호출됨으로써 변화가 통보되는데요.
이 메소들은 모두 프로텍티드(protected) 메소드 입니다.


여기의 7가지 메소드들은 오버라이드 할 수 있습니다.
단, 모든 액티비티는 최초 인스턴스 초기화를 위해 onCreate() 메소드는 무조건 구현해야 합니다.

또한, 액티비티 종료직전.... 마지막 기회가 될 수도 있는 시점에선 적절한 데이터 저장을 위해 onPause() 메소드도 구현해주면 좋겠네요.

액티비티 생명주기 메소드를 구현할 땐 항상 슈퍼클래스 버전을 호출하여야 합니다.
protected void onPause() {

super.onPause() ;

}


네스티드 루프(nested loop)


액티비티 생명주기 메소드를 구현하여 볼 수 있는 것은 아래와 같습니다.

▣ 액티비티 인타이어 라이프타임 ( entire lifetime )

onCreate() 와 onDestroy() 메소드 사이에서 발생합니다.
액티비티는 onCreate() 메소드에서 모든 초기 설정을 하고 onDestroy()에서 모든 리소스를 해제하죠.


▣ 액티비티 비지블 라이프타임 ( visible lifetime )

onStart() 메소드에서 onStop() 메소드 사이에서 발생합니다.
onStart() 메소드에서는 사용자 인터페이스의 변화 모니터를 위해 브로드캐스트 리시버를 등록할 수 있고 사용자가 보고있는 화면이 없을때엔 onStop() 메소드에서 제거할 수 있습니다. onStart() 와 onStop()은 액티비티가 사용자에게 보여지고 숨겨지는 상태이므로 여러번 호출 될 수 있습니다.


▣ 액티비티 포그라운드 라이프타임 ( foreground lifetime )

onResume() 메소드와 onPause() 메소드 사이에서 발생합니다.
이 기간동안 액티비티는 화면에서 다른 모든 액티비티보다 앞에 놓이며 사용자에게 보여집니다. onPause()는 기계가 꺼지거나 새로운 액티비티가 시작될 때 호출되고, onResume() 은 액티비티가 다시 복귀되거나 새로운 인텐트가 도착했을때 호출됩니다.
따라서 이 두개의 메소드 내용은 빠르고 가벼울 수록 좋겠네요.



생명주기 메소드가 하는 일

▣ onCreate()

액티비티가 최초 생성시에 호출됩니다. 초기화 설정을 하는 곳이지요. 보관된 상태의 액티비티가 있다면, 그 상태를 저장중인 Bundle 객체를 받습니다.
onStart() 메소드가 이어집니다. 강제종료가 불가능 합니다.


▣ onRestart()

액티비티가 정지 후 다시 시작되기 바로 직전에 호출됩니다.
onStart() 메소드가 이어집니다. 강제종료가 불가능 합니다.


▣ onStart()

액티비티가 사용자에게 보여지기 직전에 호출됩니다.
액티비티가 보여지게되면 onResume() 메소드가, 안보이게 되면 onStop() 메소드가 이어집니다.
강제종료가 불가능 합니다.


▣ onResume()

액티비티가 사용자와 상호작용하기 직전에 호출됩니다 (스택의 최상위에 위치)
onPause() 메소드가 이어집니다. 강제종료가 불가능 합니다.


▣ onPause()

시스템이 다른 액티비티를 시작하려 할 때 호출됩니다.
일반적으로 데이터 저장을 하기에 좋은 곳입니다.
하지만 소스코드의 속도가 빨라야합니다.
왜냐하면 이 메소드가 끝나기 전까진 다음 액티비티가 실행되지 않기 때문인데요,
액티비티가 되돌아오면 onResume(), 보이지않게되면 onStop() 이 이어집니다.
강제종료가 가능 합니다.


▣ onStop()

액티비티가 사용자에게 보이지 않을때 호출 됩니다.
액티비티가 제거되거나 다른 액티비티가 실행되어 해당 액티비티를 덮어버렸을 때, 호출되죠. 액티비티가 되돌아오면 onRestart(), 액티비티가 사라지면 onDestroy() 가 이어집니다.
강제종료가 가능 합니다.


▣ onDestroy()

액티비티 삭제 직전에 호출됩니다. 액티비티가 받는 마지막 호출 메소드가 되죠. 시스템이 메모리 확보를 위해 액티비티 인스턴스를 없애버려고 하거나 , finish() 메소드가 호출되면 호출되는 메소드입니다.

isFinishing() 메소드로 두 가지를 분기할 수 있습니다.



onStart() 메소드가 이어집니다. 강제종료가 불가능 합니다.



☞ 여기에서 onPause() 는 프로세스가 강제종료 되기 전에 호출되는 것입니다. 즉, 프로세스가 강제종료 될 때 onPause() 는 무조건 호출되는 유일한 곳이 됩니다. ( onStop(), onDestroy() 는 호출되지 않을 수 있어요 ), 따라서 이터 저장 등의 작업은 종료되기 직전에 호출되는 onPause() 에 구현해야 되겠네요.


액티비티 상태 저장하기


시스템이 액티비티를 강제종료 했을때, 사용자는 이전의 액티비티로 돌아가고 싶을 수 있습니다. 이럴 경우 액티비티가 강제종료 되기 전에 상태를 저장할 수 있는 onSaveInstanceState() 메소드를 구현하면 저장이 가능해 집니다.



즉, 액티비티가 파괴되기전에 호출되는 메소드 인데요. ( onPause() 호출 이전에 호출됩니다. )
이 메소드는 이름/값 쌍으로 이루어진 번들 객체(Bundle) 를 인수로 가집니다. 액티비티가 다시 시작되면 번들은 onSaveInstanceState() 와 onStart() 이후에 호출되는 onRestoreInstanceState() 에게 전달됩니다.



☞ onSaveInstanceState() , onRestoreInstanceState() 메소드는 생명주기 메소드는 아닙니다.
따라서 항상 호출되지는 않으며 특정 상황 ( 액티비티 강제종료전에 onSaveInstance() 호출처럼 ) 에서만 호출됩니다. 단, 사용자 액션에 의해 종료될 때는 ( 사용자가 직접종료 ) 호출되지 않습니다.
- 사용자가 되돌아가지 않을 생각으로 종료한 것으로 판단한 것이겠죠...

onSaveInstanceState() 는 액티비티의 일시적인 상태 저장을 위한 것이므로 , 데이터 등을 안전하게 저장하려면 onPause() 메소드에서 처리해야 합니다.


액티비티 생명주기 메소드의 순서


하나의 액티비티가 다른 액티비티를 시작할 때 하나는 멈추고 정지되며, 다른 하나는 시작되는 구조를 가집니다. 생명주기 메소드의 순서는 두 개의 액티비티가 동일 프로세스 안에 있을 때에 정의됩니다.

1. 현재 액티비티("A") 의 onPause() 가 호출됩니다.
2. 다음 시작되는 액티비티("B") 의 onCreate() -> onStart() -> onResume() 이 차례대로 호출됩니다
3. "B" 액티비티가 더 이상 사용되지 않으면 그것의 onStop() 이 호출됩니다.

7. PHP MySql 설치 등.. https://yoo-hyeok.tistory.com/16?category=708422

Posted by 목표를 가지고 달린다
,