본문 바로가기
College Computer Science/Software Engineering

[Android] Java 안 써본 컴공 4학년의 안드로이드 하루컷하기

by 2den 2021. 5. 29.
728x90

안드로이드는 MainActivity.java가 진입점이다. 앱을 실행하면 이 Activity의 인스턴스를 실행하고 레이아웃을 로드한다.

 

activity_main.xml 이런 식으로 xml 파일로 UI 레이아웃을 정의한다.

 

build.gradle은 프로젝트에 하나, 모듈에 하나 같은 이름의 파일이 두 개 있다.

 

실행이 안될 때는 여기를 참고하자.

https://developer.android.com/training/basics/firstapp/running-app

 

앱 실행  |  Android 개발자  |  Android Developers

이전 과정에서는 'Hello, World!'를 표시하는 Android 앱을 만들었습니다. 이제 실제 기기 또는 에뮬레이터에서 앱을 실행할 수 있습니다. 실제 기기에서 실행 다음 단계에 따라 기기를 설정합니다. USB

developer.android.com

 

참고로 나는 팀플 과제 중인데, client 실행을 도저히 못하겠어서 알아보니 client 폴더를 안드로이드 스튜디오에서 열어줘야 했다. 서버는 flask를 사용하고, https://flask.palletsprojects.com/en/1.1.x/installation/ 를 보면 설치와 환경설정, 실행을 쉽게 할 수 있다. 데이터베이스는 firebase를 사용한다.

 

레이아웃과 위젯 : 레이아웃은 ViewGroup 객체, 하위 View의 위치를 지정해주는 컨테에너이다. 위젯은 View 객체, 버튼 등의 UI 구성요소를 말한다.

 

XML 용어를 제공하여 UI를 설정할 수 있지만, 안드로이드 스튜디오에 레이아웃 에디터를 사용하면 코드를 작성해준다.

https://developer.android.com/training/basics/firstapp/building-ui#open

 

간단한 사용자 인터페이스 빌드  |  Android 개발자  |  Android Developers

이 과정에서는 Android 스튜디오 Layout Editor를 사용하여 텍스트 상자와 버튼이 포함된 레이아웃을 만드는 방법을 알아봅니다. 이는 다음 과정을 위한 준비 단계로, 다음 과정에서는 버튼을 탭했을

developer.android.com

 

https://developer.android.com/training/basics/firstapp/starting-activity#RespondToButton

 

다른 활동 시작  |  Android 개발자  |  Android Developers

이전 과정을 완료했다면 텍스트 필드와 Send 버튼이 있는 단일 화면으로 구성된 활동을 보여주는 앱이 있을 것입니다. 이 과정에서는 사용자가 Send 버튼을 탭할 때 메시지를 표시하도록 새 활동

developer.android.com

 

버튼을 누른 후의 동작 등 새로운 activity 발생은 Activity.java 파일에서 처리한다.

 

MainActivity 클래스 안에 sendMessage() 매서드를 추가한다.

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    /** Called when the user taps the Send button */
    public void sendMessage(View view) {
        // Do something in response to button
    }
}

매서드의 파라미터 View 클래스는 import를 해주어야 한다. (alt + enter 누르면 알아서 import)

 

activity_main.xml 파일에, 버튼에서 메서드를 호출한다.

  1. Layout Editor에서 버튼을 선택
  2. Attributes 창에서 onClick 속성을 찾아 이 속성의 드롭다운 목록에서 sendMessage [MainActivity]를 선택

버튼을 누르면 sendMessage() 매서드를 호출한다. 

public : 퍼블릭 액세스

void : 무효단위 리턴

View : 유일한 파라미터, 아까 import해준 View

 

public class MainActivity extends AppCompatActivity {
    public static final String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    /** Called when the user taps the Send button */
    public void sendMessage(View view) {
        Intent intent = new Intent(this, DisplayMessageActivity.class);
        EditText editText = (EditText) findViewById(R.id.editText);
        String message = editText.getText().toString();
        intent.putExtra(EXTRA_MESSAGE, message);
        startActivity(intent);
    }
}

(alt + enter)

 

public static final String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";

EXTRA_MESSAGE 상수를 추가했다. 패키지 이름을 접두사로 활용해 키를 정의하는 것이 좋다.

 

Intent intent = new Intent(this, DisplayMessageActivity.class);

Intent는 구성요소 간에 런타임 바인딩을 제공하는 객체이다. 예를 들면 두 개의 활동을 바인딩한다. 어떤 작업을 하려는 앱의 의도를 나타낸다.(?) 파라미터는 Context와 Class를 사용한다. (Activity 클래스는 Context의 서브클래스이다.) DisplayMessage.class 는 시작할 활동을 가리킨다.

 

String message = editText.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);

putExtra() 매서드는 message(EditText 값)를 인텐트에 추가한다. Intent는 extras라는 키-값 쌍을 통해 데이터의 유형을 전달할 수 있다. 

 

startActivity(intent);

지정한 intent 인스턴스를 시작한다.

 

 

 

두번째 뷰를 위해 xml 파일과 Activity.java를 추가한다.

 

안드로이드스튜디오는 xml 파일 레이아웃을 쉽게 지정하도록 design 툴을 제공한다. 그것으로 편집을 하면 알아서 코드를 써준다. 버튼, 텍스트뷰 등의 아이디를 잘 정해준다. (Activity.java에서 사용해야 하기 때문에 직관적인 네이밍은 필수)

 

아래는 시간이 급하여... 아무것도 모른채로 작성하기 시작한 코드이다. 파일만 만들어도 IDE에서 알아서 제안을 해준다. 바로 밑부분부터 적었다.

public class RegisterActivity extends AppCompatActivity {

    EditText EditText_newid, EditText_newpw, EditText_pwcheck;
    Button Button_back2main, Button_idcheck, Button_register;
    AlertDialog dialog;
    boolean validate = false;
    boolean isIdAlreadyTaken, isSuccess;

EditText, Button, AlertDialog 등은 xml 뷰에서 만든대로 추가해주었다. validate와 isIdAlreadyTaken, isSuccess는 내가 사용하는 boolean 변수이다.

 

Button_back2main.setClickable(true);
Button_back2main.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent(RegisterActivity.this, MainActivity.class);
        startActivity(intent);
    }
});

버튼은 누를 때 동작이 발생해야 해서 위에처럼 코드를 작성한다. setClickable()로 클릭이 가능하게 설정한 다음, setOnClickListener로 이벤트를 탐지해준다. onClick 함수는 버튼이 누르면 호출되는 콜백함수이다. 위에서 살펴본 것처럼 Intent를 통해 다른 페이지(다른 Activity 클래스)를 열어야 할 때 context와 class를 입력하여 설정한다. startActivity(intent); 명령어를 통해 인스턴스가 실행되게 한다.

 

String newid = EditText_newid.getText().toString();

if (validate) {
	return;
}

if (newid.equals("")) {
	AlertDialog.Builder builder = new AlertDialog.Builder(RegisterActivity.this);
	dialog = builder.setMessage("please enter the ID.").setPositiveButton("ok", null).create();
	dialog.show();
	return;
}

버튼이 눌리면 EditText의 문자열을 가져올 수도 있다. 위처럼 getText()를 사용하면 된다. 나 같은 경우에는, 문자열이 비었을 경우 Alert를 띄울 수 있도록 설정했다. AlertDialog는 위 코드처럼 설정해 주면 된다.

 

String url = "http://XXXXXXXX:5000/registercheck?id=" + newid;
new SearchForNewID().execute(url);

이제 서버를 통해 데이터베이스에 입력된 id 값을 넘겨주려고 한다. 이 id가 현재 DB에 저장된 id와 겹치는지를 판별할 것이다. SearchForNewID()는 내가 코드 하단에서 정의한 클래스 이름이다. OkHttp(rest API형식)를 사용하여, url 형태의 파라미터를 서버에 넘겨주었다.

 

private class SearchForNewID extends AsyncTask<String, Void, Boolean> {

	OkHttpClient client = new OkHttpClient();

	@Override
	protected Boolean doInBackground(String... params) {
		String strUrl = params[0];
		try {
			Request request = new Request.Builder()
				.url(strUrl)
				.build();
			Response response = client.newCall(request).execute();

			if (response.body().status == 400) { // registercheck? response.body().status 400 : is already taken, 200 : no id in DB
				isIdAlreadyTaken = true;
			} else { // response.body().status == 200
				isIdAlreadyTaken = false;
			}

		} catch (IOException e) {
			e.printStackTrace();
		} catch (JSONException e) {
			e.printStackTrace();
		}

		return isIdAlreadyTaken;
}

이 클래스는 버튼에 대한 처리를 모두 마친 후에 Activity 클래스 안에 마지막에 넣어주면 된다. client를 생성해주고 나서, IDE가 시키는대로 doInBackground를 만들었다. 파라미터는 넘어온 url이 된다. 리퀘스트를 빌드해주고, response를 받아온다. 내가 원하는 상태는 status라는 변수로 response의 바디에 넣어주기로 했다. (아직 코딩 안 한 부분) 내 맘대로, 상태가 200이면 아이디 사용 가능, 400이면 불가능이다. 전역변수 (지역변수로 바꿀 예정) isIdAlreadyTaken을 true 혹은 false로 설정해 주었다. catch 부분은 try를 쓰면 안드로이드 스튜디오가 알아서 써준다. 그리고 return 값은 사실 void로 해도 무방하다. 지금은 전역변수를 쓰고 있기 때문이다.

 

계속 같은 방식으로 코딩하면 된다. 다만, 같은 status를 사용하려면 url 파라미터를 다르게 열어 라우팅 경로가 달라지도록 설정해야 한다.

String url = "http://XXXXXXXX:5000/register?id=" + newid + "&pw=" + newpw;
new RegisterNewIdAndPw().execute(url);

위와 같이, ID 중복 체크와 회원가입을 다른 경로로 설정하면,

if (response.body().status == 200) { // register? response.body().status 400 : fail, 200 : success
	isSuccess = true;
} else {
	isSuccess = false;
}

같은 status를 사용할 수 있다.

 

 

그럼 20000.

 


이틀째. 새로 알게된 내용이 있어 덧붙인다.

 

1. 버튼도 초기화를 해줘야 한다.

Button_back2main = findViewById(R.id.Button_back2main);
Button_idcheck = findViewById(R.id.Button_idcheck);
Button_register = findViewById(R.id.Button_register);

 

2. boolean 변수는 Boolean이 아닌 boolean으로 쳐줘야 한다. ...;;

boolean validate = false;
boolean isIdAlreadyTaken, isSuccess; // boolean (o) Boolean (x)

 

3. 서버 통신 중에 프로그램이 돌아가지 않도록 살짝의 delay를 시켜주어야 한다.

String url = "http://XXXXXXXX:5000/registercheck?id=" + newid;
new SearchForNewID().execute(url);
try {
	TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
	e.printStackTrace();
}

 

4. java는 == != 연산자가 주소값을 비교한다. 문자열의 내용이 같은지 확인하려면 .equals() 메소드를 사용해야 한다.

if (!(newpw.equals(pwcheck))) {
	AlertDialog.Builder builder = new AlertDialog.Builder(RegisterActivity.this);
	dialog = builder.setMessage("Passwords are not same.").setNegativeButton("ok", null).create();
	dialog.show();
	return;
}

 

5. flask는 서버 통신을 json 문자열로 하는 게 기본인가? 이건 아직도 모르겠다.

// server
@app.route("/registercheck", methods=["GET"])
def register_check():
    u_id = request.args.get("id")
    
    if db.register_verification(u_id):
        return jsonify({"status": 200}) # id pw not needed
    else:
        return jsonify({"status": 400})

// client
JSONObject jsonObject = new JSONObject(response.body().string());
Integer status = jsonObject.getInt("status");

 

6. 서버 통신을 간이로 확인하려면 localhost url에 라우팅 경로를 붙여서 확인할 수 있다.

728x90

댓글