환경설정탭과 Web탭 만들기
BottomNavigationView 만들기
MENU 바 만들기
menu 커스텀은 menu.xml에서 해야함
다시 Main으로와서 menu 선택하고
labelVisibilityMode를 labeled로 바꾸면 menu에 설정한 item들이 다 나온다
4개의 메뉴에 들어갈 fragment 4개 만들기
그리고fragment의 레이아웃을 constraintLayout으로 바꿔준다
●MainActivity.java
public class MainActivity extends AppCompatActivity {
// 1. 어떤 메뉴를 선택했는지 판별하기
BottomNavigationView nv;
// 2. 선택한 메뉴에 따라서 FrameLayout에 들어갈 Fragment를 갈아끼우기
// 2-1 각각 fragment들 객체 생성
Fragment_1 fg1;
Fragment_2 fg2;
Fragment_3 fg3;
Fragment_4 fg4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fg1 = new Fragment_1();
fg2 = new Fragment_2();
fg3 = new Fragment_3();
fg4 = new Fragment_4();
// 2-2 최초 실행될 fragment 고르기
// 1) fragment가 들어갈 공간(frameLayout)의 id
// 2) 같이 끼울 Fragment 객체
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, fg1).commit();
nv = findViewById(R.id.bottomNavigationView);
// 3. navigation 에서 선택한 메뉴에 따라 fragment 바꿔끼우기
nv.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.tab1:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, fg1).commit();
Toast.makeText(getApplicationContext(),"Web 선택!",Toast.LENGTH_SHORT).show();
break;
case R.id.tab2:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, fg2).commit();
Toast.makeText(getApplicationContext(),"Stopwatch 선택!",Toast.LENGTH_SHORT).show();
break;
case R.id.tab3:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, fg3).commit();
Toast.makeText(getApplicationContext(),"Kill 선택!",Toast.LENGTH_SHORT).show();
break;
case R.id.tab4:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, fg4).commit();
Toast.makeText(getApplicationContext(),"Setting 선택!",Toast.LENGTH_SHORT).show();
break;
}
// return false => 아직 현재 이벤트가 끝나지 않았다 라는 뜻
return true;
}
});
}
}
각각 만들기
▼ findViewById 하는법
●fragment_4.java
public class Fragment_4 extends Fragment {
// Fragmant 4
// 1. Fragment 상황에서 findViewById하기 Toast띄우기
// 2. Fragment 1로 데이터 넘기기
// 2-1 App 데이터(캐시)로 저장하기 -> SharedPreference => 간단한데이터저장 (로그인정보,환경설정,첫 실행인지 감지)
Button btn_setting;
EditText edt_address;
SharedPreferences spf;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_4, container, false);
// MODE_PRIVATE -> mySFP라는 이름의 프리퍼런스가 없으면 새로 생성, 있으면 있는거 가져와라
spf = getActivity().getSharedPreferences("mySPF", Context.MODE_PRIVATE);
// 값 반영할 수 있는 객체
SharedPreferences.Editor editor = spf.edit();
btn_setting = view.findViewById(R.id.btn_setting);
edt_address = view.findViewById(R.id.edt_address);
btn_setting.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Toast 띄울 때 getApplicationContext() -> Fragment에서는 x
// 앞에 getActivity(). 를 붙여주면 현재 Fragment가 포함된 Activity정보를 가지고 올 수 있음
// 현재 url에 https:// 로 시작하지 않는다면 https:// 붙여주기
String url = edt_address.getText().toString();
if (!url.startsWith("https://")){
url = "https://"+url;
}
Toast.makeText(getActivity().getApplicationContext(), url, Toast.LENGTH_SHORT).show();
//spf에 값 저장하기, 해당값을 App을 껐다 켜도 유지됨
editor.putString("address",url);
editor.commit();
}
});
return view;
}
}
url 주소 작성하고 버튼 누르면 ▼fragment_1.xml 에 브라우저 띄우기
●fragment_1.java
// onCreateView 빼고 나머지 지우기
public class Fragment_1 extends Fragment {
// Fragmet 1
// 1. WebView 쓰는 법
// 2. 저장된 url 정보 가져오는 법 -> SPF
WebView wv;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// fragment.xml 파일을 view로 inflate(id -> view)하여 반환
View view = inflater.inflate(R.layout.fragment_1, container, false);
wv = view.findViewById(R.id.webview);
//spf에서 값 꺼내기, 한줄로 간단하게
//String url = "https://www.smhrd.or.kr";
String url = getActivity().getSharedPreferences("mySPF", Context.MODE_PRIVATE)
.getString("address",null);
//1-1 webView 환경설정해주기
WebSettings settings = wv.getSettings();
settings.setJavaScriptEnabled(true); // javascript 사용가능
//1-2 webClient 지정
wv.setWebViewClient(new WebViewClient());
//1-3 띄워줄 url 지정
wv.loadUrl(url);
//1-4 인터넷 권한 부여 -> manifest.xml
return view;
}
}
<- manifest.xml 에서
인터넷 권한부여 하기
결과
youtube.com 작성후 설정버튼 -> Web탭▼
Stopwatch 탭에 스톱워치 만들기
Process - 컴퓨터에서 연속적으로 실행되고 있는 컴퓨터 프로그램 (작업)
Thread - 프로세스 병렬처리 - 하나의 프로그램 내에서 둘 이상의 작업을 동시에 진행하는 프로세스보다 작은단위
Handler -
시분할 시스템 ( 시간 분할 )
START!! 버튼 누르면 1초에 1씩 카운트되게 ( 각각 다른 스톱워치 - 스레드로 동작하게 )
SubThread가 MainThread의 작업Queue에 setText를 Message로 보냄
꺼낼때는 msg에서 arg1에 저장된 값을 setText
●fragment_2.java
public class Fragment_2 extends Fragment {
// Thread 만들기
// 1. Thread 클래스(설계도) 정의하기 (Thread 상속)
// 2. run 메소드(Thread 시작시켰을 때 호출되는 메소드)를 오버라이딩 하기
// 3. setText(UI업데이트)하기 위해 Handler 생성
// 4. Message 전송 (sendMassage)하고 Handler에서 값 전달받음 (HandlerMessage)
// 5. Handler에서 setText처리
TextView tv1, tv2;
Button btn1, btn2;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// tv1,tv2,btn1,btn2 찾아오기
View view = inflater.inflate(R.layout.fragment_2, container, false);
tv1 = view.findViewById(R.id.tv1);
tv2 = view.findViewById(R.id.tv2);
btn1 = view.findViewById(R.id.btn1);
btn2 = view.findViewById(R.id.btn2);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Thread 실행시키기
// 1) Thread를 상속받아 만들어진 클래스의 객체를 생성
cntThread thread = new cntThread();
// 2) start메소드를 호출한다.
thread.start();
}
});
return view;
}
// Handler 만들기
Handler handler = new Handler() {
// 메세지 수신 시 호출되는 메소드 생성 - 원래는 상속받는게 정석
@Override
public void handleMessage(@NonNull Message msg) {
// msg에서 arg1에 저장된 값을 setText
tv1.setText(msg.arg1 + ""); // setText 할 때 정수형을 넣으면 에러!! (정수형을 참조할 주소값으로 인식함)
}
};
class cntThread extends Thread {
@Override
public void run() { //Thread 시작시켰을 때
// Thread가 할 일을 적어주면 됨 - 1~10까지 1초씩 세는 코드
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
// Thread가 CPU 사용하다가 양보 -> yield
// CPU 뺏어옴 -> interrupt
// 쉬는동안 (sleep) 다른 Thread가 interrupt를 걸었을 때를 대비
}
// i -> TextView에 setText만 하면 됨
// 여기 (SubThread -> 내가 만든 Thread)에서는 setText등 UI업데이트 못함
// Handler에 메세지를 전송해서 setText작업을 처리해야함
Message msg = new Message();
// Message 객체에는 변수가 3개있음 ▼
// Object obj , int arg1 , int arg2 - 변수에 각각 값을 저장할 수 있음
// i값을 handler에 보내서 textView에 setText 하기
msg.arg1 = i;
handler.sendMessage(msg);
}
}
}
}
다음과 같이 하면
클릭 할때마다 Thread가 시작돼서 여러번누르면 스톱워치가 한번에 여러번 시작되므로
▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼
cntThread thread = null; 이라고 전역 변수로 지정하고
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 버튼에 적혀있는 글자가 START 일때만 Thread 생성, 아니면 멈추게
if (btn1.getText().toString().equals("START!!")){
thread = new cntThread();
thread.start();
// start 버튼을 누르면 버튼에 적힌 글자가 stop으로 바뀌게
btn1.setText("STOP!");
}else{
thread.interrupt(); // 멈추는 법 (지금 실행하고 있는 쓰레드 멈춤)
// cpu 뺏기
// thread.interrupt 하면 thread 내부에서는 interrupt Exception 이 발생
// 멈추게 하려면 interruptException을 처리할 수 있는 catch 문에서 run 메소드를 끝내면 됨
btn1.setText("START!");
}
}
});
START버튼 누를때에만 쓰레드 생성되게한다 ( 한번누르면 버튼이 STOP으로 바뀜 )
class cntThread extends Thread {
@Override
public void run() { //Thread 시작시켰을 때
// Thread가 할 일을 적어주면 됨 - 1~10까지 1초씩 세는 코드
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
// 메소드는 return문을 만나면 종료되기 때문에
// 누군가가 이 Thread를 종료시키고 싶다면 interrupt를 걸어주면 됨
run 메소드에는 catch에 return; 해준다
tv2와 2번째 버튼도 활성화 하기 위해
만들어 준다
MainThread -> cntThread
지금 생성되는 Thread가 필요한 TextView를 매개변수로 보내줘야함 ( tv1 )
cntThread에서 매개변수로 TextView를 전달받는 생성자 생성하기
Message msg = new Message();
// Message 객체에는 변수가 3개있음 ▼
// Object obj , int arg1 , int arg2 - 변수에 각각 값을 저장할 수 있음
// i값을 handler에 보내서 textView에 setText 하기
msg.arg1 = i;
msg.obj = textView;
handler.sendMessage(msg);
Message에 textView를 담을 msg.obj를 만들고
cntThread -> handler
msg.obj 를 TextView로 다운캐스팅하고 그걸 setText함
●fragment_2.java
public class Fragment_2 extends Fragment {
// Thread 만들기
// 1. Thread 클래스(설계도) 정의하기 (Thread 상속)
// 2. run 메소드(Thread 시작시켰을 때 호출되는 메소드)를 오버라이딩 하기
// 3. setText(UI업데이트)하기 위해 Handler 생성
// 4. Message 전송 (sendMassage)하고 Handler에서 값 전달받음 (HandlerMessage)
// 5. Handler에서 setText처리
TextView tv1, tv2;
Button btn1, btn2;
cntThread thread = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// tv1,tv2,btn1,btn2 찾아오기
View view = inflater.inflate(R.layout.fragment_2, container, false);
tv1 = view.findViewById(R.id.tv1);
tv2 = view.findViewById(R.id.tv2);
btn1 = view.findViewById(R.id.btn1);
btn2 = view.findViewById(R.id.btn2);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 버튼에 적혀있는 글자가 START 일때만 Thread 생성, 아니면 멈추게
if (btn1.getText().toString().equals("START!!")){
thread = new cntThread(tv1); // 지금 생성되는 Thread가 필요한 TextView를 보내줘야함(매개변수)
thread.start();
// start 버튼을 누르면 버튼에 적힌 글자가 stop으로 바뀌게
btn1.setText("STOP!");
}else{
thread.interrupt(); // 멈추는 법 (지금 실행하고 있는 쓰레드 멈춤)
// cpu 뺏기
// thread.interrupt 하면 thread 내부에서는 interrupt Exception 이 발생
// 멈추게 하려면 interruptException을 처리할 수 있는 catch 문에서 run 메소드를 끝내면 됨
btn1.setText("START!");
}
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 버튼에 적혀있는 글자가 START 일때만 Thread 생성, 아니면 멈추게
if (btn2.getText().toString().equals("START!!")){
thread = new cntThread(tv2); // 지금 생성되는 Thread가 필요한 TextView를 보내줘야함(매개변수)
thread.start();
// start 버튼을 누르면 버튼에 적힌 글자가 stop으로 바뀌게
btn2.setText("STOP!");
}else{
thread.interrupt(); // 멈추는 법 (지금 실행하고 있는 쓰레드 멈춤)
// cpu 뺏기
// thread.interrupt 하면 thread 내부에서는 interrupt Exception 이 발생
// 멈추게 하려면 interruptException을 처리할 수 있는 catch 문에서 run 메소드를 끝내면 됨
btn2.setText("START!");
}
}
});
return view;
}
// Handler 만들기
Handler handler = new Handler() {
// 메세지 수신 시 호출되는 메소드 생성 - 원래는 상속받는게 정석
@Override
public void handleMessage(@NonNull Message msg) {
// msg에서 arg1에 저장된 값을 setText
((TextView)msg.obj).setText(msg.arg1 + ""); // setText 할 때 정수형을 넣으면 에러!! (정수형을 참조할 주소값으로 인식함)
// obj로만든 TextView로 다운캐스팅하고 setText함
}
};
class cntThread extends Thread {
private TextView textView;
public cntThread(TextView textView){ // 매개변수로 TextView를 전달받는 생성자
this.textView=textView;
}
@Override
public void run() { //Thread 시작시켰을 때
// Thread가 할 일을 적어주면 됨 - 1~10까지 1초씩 세는 코드
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
// 메소드는 return문을 만나면 종료되기 때문에
// 누군가가 이 Thread를 종료시키고 싶다면 interrupt를 걸어주면 됨
// Thread가 CPU 사용하다가 양보 -> yield
// CPU 뺏어옴 -> interrupt
// 쉬는동안 (sleep) 다른 Thread가 interrupt를 걸었을 때를 대비
}
// i -> TextView에 setText만 하면 됨
// 여기 (SubThread -> 내가 만든 Thread)에서는 setText등 UI업데이트 못함
// Handler에 메세지를 전송해서 setText작업을 처리해야함
Message msg = new Message();
// Message 객체에는 변수가 3개있음 ▼
// Object obj , int arg1 , int arg2 - 변수에 각각 값을 저장할 수 있음
// i값을 handler에 보내서 textView에 setText 하기
msg.arg1 = i;
msg.obj = textView;
handler.sendMessage(msg);
}
}
}
}
버튼2를 똑같이 만들어 눌렀을때 tv2가 변하게 만든다
연결할 이미지 동시선택 -> 우클릭해서 chain 생성하기
●fragment_3.java
package com.kmg.ex0413_dudu;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.media.Image;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
TextView tv_count;
ImageView[] imgArray = new ImageView[9];
int score;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_count = findViewById(R.id.tv_count);
for(int i = 0; i<imgArray.length; i++){
// 상수 정의
final int pos = i;
// 이미지뷰초기화
int img_id = getResources().getIdentifier("img"+(i+1),"id",getPackageName());
//매개변수 name -> View의 id
//매개변수 defType -> id ( R.id )
//매개변수 defPackage -> Project의 pakage
imgArray[i] = findViewById(img_id);
// 두더지의 상태(on/off)를 이미지에 저장
imgArray[i].setTag("off");
// 두더지 쓰레드 실행
Thread doThread = new doThread(i);
doThread.start();
// 클릭이벤트 적용
imgArray[i].setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 두더지 상태에 따른 점수 카운트 (Tag사용)
if (imgArray[pos].getTag().toString().equals("on")){ // 변수x , 상수o ( 변수 i대신 pos라는 상수로 )
score++;
}else{
score--;
}
tv_count.setText(String.valueOf(score)); // score 문자열로 반환
}
});
}
}//end onCreate()
Handler dohandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
// 두더지에 대한 상태, 이미지 등을 변경
imgArray[msg.arg1].setImageResource(msg.arg2);
imgArray[msg.arg1].setTag(msg.obj);
}
};
class doThread extends Thread{
int pos = 0; // 두더지 번호
public doThread(int pos) { // 두더지 번호 초기화
this.pos = pos;
}
@Override
public void run() {
while (true) {
// 박혀있는 시간
int offtime = new Random().nextInt(5000) + 500; // 0 ~ 4.5초
// 올라온 시간
int ontime = new Random().nextInt(3000) + 500; // 0 ~ 4.5초
try {
Thread.sleep(offtime);
Message msg = new Message();
// 핸들러에게 전달할 값 - pos 몇번째 두더지인지, on.png파일명, 상태값(on)
msg.arg1 = pos;
msg.arg2 = R.drawable.on;
msg.obj = "on";
dohandler.sendMessage(msg);
// 두더지 숨기는 기능 구현
// 두더지가 서있는 시간
// 두더지 번호, 사진, 상태값을 새로운 Message객체를 생성해 핸들러에게 전달
Thread.sleep(ontime);
msg = new Message();
msg.arg1 = pos;
msg.arg2 = R.drawable.off;
msg.obj = "off";
dohandler.sendMessage(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
} // while문
}
}
}
'Android' 카테고리의 다른 글
[Android/Java] Intent 사용 (0) | 2022.01.04 |
---|---|
[Android/Java] Git연동과 findViewById 에러 (0) | 2022.01.04 |
로그인 후 채팅 방 만들기?? (0) | 2021.04.06 |
서버 통신 로그인 DB연동( Volley 라이브러리 ) (0) | 2021.04.03 |
Custom ListView + DB연동하기 ( SQLite ) (0) | 2021.04.03 |