Android Developer

[Android] Foreground, Background, Timer

졸려질려 2019. 4. 2. 17:04
반응형

Foreground, Background

Foreground

  • 사용자와 상호작용이 가능한 상태의 프로세스 ( 화면에 직접적으로 보이는 프로세스)

    Background

  • 겉으로는 보이지 않는 프로세스 공간

  • 주로 'Service' 기능이 많이 실행된다.

    Android 8.0 (Oreo) Background Execution limits

  • 백그라운드에서 실행되는 어플리케이션들이 기기의 리소스를 많이 소모하는 것을 개선하기 위해 제한하는 것이다.

  • 백그라운드 서비스 제한 : 앱이 유휴 상태인 경우 백그라운드 서비스의 사용이 제한된다. 유휴상태 : 주변장치들의 입력과 출력이 없는 상태

  • 브로드캐스트 제한 : 매니페스트에 등록한 암시적 broadcast 를 받을 수 없다. (약간의 예외는 있다)

  • Android 8.0 이하라도 Settings를 통해 enable 가능하다.

Timer 만들기

Timer 생성 방법

Timer를 생성하는 방법에는 2가지가 있다.

  1. Android SDK 에서 제공하는 스케줄용 Timer와 TimerTask를 이용한다.
  2. Thread 클래스나 인터페이스를 이용한다. ( Sleep 을 이용해서 간격을 유지 )

Timer Class 를 사용하여 Timer 만들기

  1. 현재 시각 나타내기 ( Timer Class )
package com.example.calculatorapplication;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class StopWatch extends Fragment {  
private View mView;  
private Timer mTimer;  
private TextView mTvTimer;

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

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstatnceState){
    mView = inflater.inflate(R.layout.timer_fragment, null);
    mTvTimer = (TextView)mView.findViewById(R.id.tv_timer);
    mTimer = new Timer();
    mTimer.schedule(new CustomTimer(), 2000, 1000);
    return mView;
}

class CustomTimer extends TimerTask {  
@Override  
public void run(){  
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd mm:ss");  
    String currentTime = sdf.format(new Date());

    mTvTimer.setText("Timer Class 현재 시간 : " + currentTime);
}
}
}
  • 프래그먼트 내에 타이머를 생성하였다.
  • 실행 결과 현재 날짜와 분,초가 나오는 것을 볼 수 있다.
  1. Stopwatch 만들기
package com.example.calculatorapplication;
import android.os.Bundle;  
import android.support.v4.app.Fragment;  
import android.support.v7.widget.LinearLayoutManager;  
import android.support.v7.widget.RecyclerView;  
import android.view.LayoutInflater;  
import android.view.View;  
import android.view.ViewGroup;  
import android.widget.Button;  
import android.widget.TextView;

import java.text.SimpleDateFormat;  
import java.util.ArrayList;  
import java.util.Date;  
import java.util.Timer;  
import java.util.TimerTask;

public class TimerFragment extends Fragment implements View.OnClickListener{  
private View mView;  
private Button mStart;  
private Button mPause;  
private Button mStop;  
private TextView mTimerText;  
private Timer mTimer;  
private TimerTask mTimerTask;  
private int mMin = 0;  
private int mSec = 0;  
private int mMsec = 0;

private RecyclerView mTimerRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private ArrayList<String> mNow = new ArrayList<>();

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

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstatnceState){
    mView = inflater.inflate(R.layout.timer_fragment, null);
    init(mView);
    return mView;
}

private void init(View v) {
    mStart = (Button)v.findViewById(R.id.timer_button_Start);
    mPause = (Button)v.findViewById(R.id.timer_button_Pause);
    mStop = (Button)v.findViewById(R.id.timer_button_Stop);
    mTimerText = (TextView)v.findViewById(R.id.timer_Textview);

    mTimerRecyclerView = (RecyclerView)v.findViewById(R.id.timer_Recyclerview);
    mLayoutManager = new LinearLayoutManager(getActivity());
    mTimerRecyclerView.setLayoutManager(mLayoutManager);

    mStart.setOnClickListener(this);
    mPause.setOnClickListener(this);
    mStop.setOnClickListener(this);
    mTimerText.setText(Integer.toString(mMin) + " : " + Integer.toString(mSec) + " : " + Integer.toString(mMsec));
}

@Override
public void onClick(View v) {
    switch(v.getId()){
        case R.id.timer_button_Start :
            timerStart();
            break;
        case R.id.timer_button_Pause :
            timerPause();
            break;
        case R.id.timer_button_Stop :
            timerStop();
            break;
    }
}

private void timerStop() {
    mTimer.cancel();
    mMin=0;
    mSec=0;
    mMsec=0;
    mTimerText.setText("00 : 00 : 00");
}

private void timerPause() {
    mTimer.cancel();
}

private void timerStart(){
    mTimer = new Timer();
    mTimerTask = new TimerTask() {
        @Override
        public void run() {
            mMsec++;
            if(mMsec>=100) {
                mMsec=0;
                mSec++;
                if(mSec%10==0){
                    printDate();
                }
            }
            if(mSec == 60){
                mSec=0;
                mMin++;
            }
            mTimerText.setText(Integer.toString(mMin) + " : " + Integer.toString(mSec) + " : " + Integer.toString(mMsec));
        }
    };

    mTimer.schedule(mTimerTask, 0, 10);
}

private void printDate(){
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    mNow.add(sdf.format(new Date()));
    mAdapter = new MainRecyclerViewAdapter(mNow);
    mTimerRecyclerView.setAdapter(mAdapter);
}
}
  • 위와 같이 코드를 짜면

    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

해당 에러가 나타나게 된다. 무슨 에러인지 알아보자.
일단 직역을 하자면 : Original Thread로만 UI를 변경 시킬 수 있다.
는 뜻이다.
즉, 에러의 원인은 Main Thread 외의 새로 생성한 Thread를 이용하여 임의로 UI를 변경시키려고 했던 것이다.
이럴 때는 'Handler'를 이용하여 Main Thread를 간접적으로 사용하면 해결 할 수 있다.

  • 수정된 코드는 다음과 같다.
private void timerStart(){
        final Handler handler = new Handler() {
            public void handleMessage(Message msg){
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                mNow.add(sdf.format(new Date()));
                mAdapter = new MainRecyclerViewAdapter(mNow);
                mTimerRecyclerView.setAdapter(mAdapter);
            }
        };
        mTimer = new Timer();
        mTimerTask = new TimerTask() {
            @Override
            public void run() {
                mMsec++;
                if(mMsec>=100) {
                    mMsec=0;
                    mSec++;
                    if(mSec%10==0){
                        Message msg = handler.obtainMessage();
                        handler.sendMessage(msg);
                    }
                }
                if(mSec == 60){
                    mSec=0;
                    mMin++;
                }
                mTimerText.setText(Integer.toString(mMin) + " : " + Integer.toString(mSec) + " : " + Integer.toString(mMsec));
            }
        };
        mTimer.schedule(mTimerTask, 0, 10);
    }
  • 무사히 완성되었다.
반응형

'Android Developer' 카테고리의 다른 글

[Andoird] GIF를 이용한 Splash Activity 만들기  (0) 2019.04.12
[Android] Android Design Pattern  (0) 2019.04.09
[Android] ListView, Navigation Drawer  (0) 2019.03.24
[Android] Fragment  (0) 2019.03.13
[Android] Naming  (0) 2019.03.01