본문 바로가기

안드로이드

[안드로이드] 간단한 투표 앱 만들기. intent.putExtra(), getExtra()를 활용.

728x90

# 간단한 투표 앱 기능

안드로이드 스튜디오에서 구현할 수 있는 2개의 activity에서 데이터를 주고 받는 방법을 알아보겠습니다.

 

메인 액티비티에서 그림을 클릭하면 해당 항목에 투표를 하게 됩니다.

투표 종료를 누르면 결과 액티비티로 넘어가 각 항목의 투표수를 RatingBar로 보여주고

최다 득표 항목을 상단에 보여줍니다.

 

메인 액티비티에서 투표한 결과를 intent.putExtra()로 intent에 담아 결과 액티비티로 전달합니다.

투표 항목 이름은 문자열로 전달하여, intent.getStringArrayExtra()로 받습니다.

투표 횟수는 정수형으로 전달하여, intent.getIntArrayExtra()로 받습니다.

 

# 준비물

  • 투표에 사용할 항목 이미지 9종
    • w 200 * 250 사이즈로 사용했습니다.

 

# activity_main.xml

메인 액티비티의 화면을 구성합니다.

위치: project\app\res\layout

<?xml version="1.0" encoding="utf-8"?>

// 세로 방향 리니어레이아웃으로
// 그림3개/그림3개/그림3개/버튼1개를 배치합니다.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    
    // 1,2,3번 항목 이미지 3개가 들어갈 리니어레이아웃
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="horizontal"
        android:layout_weight="3">
        
        // 1번 항목 이미지 뷰
        <ImageView
            
            // 자바 스크립트에서 에셋을 불러오기 위한 변수명
            android:id="@+id/iv1"
            
            // ImageView에 표시할 이미지 주소와 이미지 이름
            android:src="@drawable/pic1"
            
            // 에셋의 가로 크기를 상위 레이아웃의 가로 크기에 맞춥니다.
            android:layout_width="match_parent"
            
            // 에셋의 세로 크기를 상위 레이아웃의 세로 크기에 맞춥니다.
            android:layout_height="match_parent"
            
            // 에셋 주변에 5dp만큼 여백을 둡니다.
            android:layout_margin="5dp"
            
            // 현재 레이아웃 내에서 에셋이 차지할 공간 가중치
            // 현재 레이아웃의 이미지 뷰 3개 모두 가중치를 1씩 가지고 있기 때문에
            // 모두 균등하게 공간을 차지하게 됩니다.
            android:layout_weight="1"/>
        
        // 2번 항목 이미지 뷰
        <ImageView
            android:id="@+id/iv2"
            android:src="@drawable/pic2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="5dp"
            android:layout_weight="1"/>
        
        // 3번 항목 이미지 뷰
        <ImageView
            android:id="@+id/iv3"
            android:src="@drawable/pic3"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="5dp"
            android:layout_weight="1"/>

    </LinearLayout>

    // 4,5,6번 항목 이미지 3개가 들어갈 리니어레이아웃
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="horizontal"
        android:layout_weight="3">
        <ImageView
            android:id="@+id/iv4"
            android:src="@drawable/pic4"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="5dp"
            android:layout_weight="1"/>
        <ImageView
            android:id="@+id/iv5"
            android:src="@drawable/pic5"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="5dp"
            android:layout_weight="1"/>
        <ImageView
            android:id="@+id/iv6"
            android:src="@drawable/pic6"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="5dp"
            android:layout_weight="1"/>

    </LinearLayout>

    // 7,8,9번 항목 이미지 3개가 들어갈 리니어레이아웃
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="horizontal"
        android:layout_weight="3">
        <ImageView
            android:id="@+id/iv7"
            android:src="@drawable/pic7"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="5dp"
            android:layout_weight="1"/>
        <ImageView
            android:id="@+id/iv8"
            android:src="@drawable/pic8"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="5dp"
            android:layout_weight="1"/>
        <ImageView
            android:id="@+id/iv9"
            android:src="@drawable/pic9"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="5dp"
            android:layout_weight="1"/>

    </LinearLayout>
    
    // 최하단에 투표 종료 버튼을 위치합니다.
    <Button
        android:id="@+id/btnResult"
        android:text="투표 종료"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>


</LinearLayout>

 

# result.xml

결과 액티비티의 화면을 구성합니다.

위치: project\app\res\layout 에 TableLayout으로 새로 생성합니다.

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_vertical"
    android:stretchColumns="0"
    >
    
    // 최다 득표 항목의 이름
    <TableRow>
        <TextView
            android:id="@+id/tvTop"
            android:layout_gravity="center"
            android:layout_span="2"
            android:text="최다 득표 음식 이름"
            android:textSize="20dp"/>
    </TableRow>
    
    // 최다 득표 항목의 이미지
    <TableRow>
        <ImageView
            android:id="@+id/ivTop"
            android:layout_width="150dp"
            android:layout_height="150dp"
            android:layout_margin="15dp"
            android:layout_span="2"
            android:src="@drawable/pic1"/>
    </TableRow>
    
    // 1번 항목 이름과 RaingBar
    <TableRow>
        <TextView
            android:id="@+id/tv1"
            android:layout_gravity="center_vertical"
            android:text="그림1"
            android:textSize="20dp"
            />
        <RatingBar
            android:id="@+id/rbar1"
            style="?android:attr/ratingBarStyleIndicator"
            android:layout_gravity="right"
            />
    </TableRow>

    // 2번 항목 이름과 RaingBar
    <TableRow>
        <TextView
            android:id="@+id/tv2"
            android:layout_gravity="center_vertical"
            android:text="그림2"
            android:textSize="20dp"
            />
        <RatingBar
            android:id="@+id/rbar2"
            style="?android:attr/ratingBarStyleIndicator"
            android:layout_gravity="right"
            />
    </TableRow>

    // 3번 항목 이름과 RaingBar
    <TableRow>
        <TextView
            android:id="@+id/tv3"
            android:layout_gravity="center_vertical"
            android:text="그림3"
            android:textSize="20dp"
            />
        <RatingBar
            android:id="@+id/rbar3"
            style="?android:attr/ratingBarStyleIndicator"
            android:layout_gravity="right"
            />
    </TableRow>

    // 4번 항목 이름과 RaingBar
    <TableRow>
        <TextView
            android:id="@+id/tv4"
            android:layout_gravity="center_vertical"
            android:text="그림4"
            android:textSize="20dp"
            />
        <RatingBar
            android:id="@+id/rbar4"
            style="?android:attr/ratingBarStyleIndicator"
            android:layout_gravity="right"
            />
    </TableRow>

    // 5번 항목 이름과 RaingBar
    <TableRow>
        <TextView
            android:id="@+id/tv5"
            android:layout_gravity="center_vertical"
            android:text="그림5"
            android:textSize="20dp"
            />
        <RatingBar
            android:id="@+id/rbar5"
            style="?android:attr/ratingBarStyleIndicator"
            android:layout_gravity="right"
            />
    </TableRow>

    // 6번 항목 이름과 RaingBar
    <TableRow>
        <TextView
            android:id="@+id/tv6"
            android:layout_gravity="center_vertical"
            android:text="그림6"
            android:textSize="20dp"
            />
        <RatingBar
            android:id="@+id/rbar6"
            style="?android:attr/ratingBarStyleIndicator"
            android:layout_gravity="right"
            />
    </TableRow>

    // 7번 항목 이름과 RaingBar
    <TableRow>
        <TextView
            android:id="@+id/tv7"
            android:layout_gravity="center_vertical"
            android:text="그림7"
            android:textSize="20dp"
            />
        <RatingBar
            android:id="@+id/rbar7"
            style="?android:attr/ratingBarStyleIndicator"
            android:layout_gravity="right"
            />
    </TableRow>

    // 8번 항목 이름과 RaingBar
    <TableRow>
        <TextView
            android:id="@+id/tv8"
            android:layout_gravity="center_vertical"
            android:text="그림8"
            android:textSize="20dp"
            />
        <RatingBar
            android:id="@+id/rbar8"
            style="?android:attr/ratingBarStyleIndicator"
            android:layout_gravity="right"
            />
    </TableRow>

    // 9번 항목 이름과 RaingBar
    <TableRow>
        <TextView
            android:id="@+id/tv9"
            android:layout_gravity="center_vertical"
            android:text="그림9"
            android:textSize="20dp"
            />
        <RatingBar
            android:id="@+id/rbar9"
            style="?android:attr/ratingBarStyleIndicator"
            android:layout_gravity="right"
            />
    </TableRow>

    // 메인액티비티로 돌아가기 위한 버튼
    <TableRow>
        <Button
            android:id="@+id/btnReturn"
            android:text="돌아가기"
            android:textSize="20dp"
            android:layout_span="2"
            />
    </TableRow>



</TableLayout>

 

# AndroidManifest.xml

위치: project\app\manifests\ 에 있습니다.

 

액티비티의 존재를 AndroidManifest.xml 이 알고 있어야 합니다.

AndroidManifest.xml을 열어보면 <application> 안에

메인 액티비티가 이미 있습니다.

아래 코드를 <application> 안에 메인 액티비티가 들어있는 <activity></activity> 바로 아래 추가합니다.

 

<activity android:name=".ResultActivity"/>

 

# MainActivity.java

위치: project\app\java\"프로젝트명"\ 에 있습니다.

메인 액티비티 화면의 기능을 구현합니다.

package com.sikuroku.p10_2_ratingdrawing;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 앱 화면 상단의 메뉴바에 표시될 이름
        setTitle("음식 선호도 투표");

        // 투표 횟수를 저장할 정수형 배열을 선언하고 0으로 초기화합니다.
        final int voteCount[]  = new int[9];
        for(int i=0; i<9; i++)
            voteCount[i] = 0;

        // 투표 항목 이미지뷰 9개의 변수를 배열로 선언합니다.
        ImageView image[] = new ImageView[9];
        
        // 9개 이미지 뷰의 변수명을 정수형 배열로 저장합니다.
        Integer imageId[] = {R.id.iv1, R.id.iv2, R.id.iv3, R.id.iv4, R.id.iv5,
                             R.id.iv6, R.id.iv7, R.id.iv8, R.id.iv9};
        
        // 각 항목의 이름을 저장합니다.
        final String imgName[] = {"햄버거", "피자", "백반",
        "초밥", "국수", "도넛", "샐러드", "치킨",
        "빵" };

        for(int i=0; i<9; i++){
            
            // 그대로 i를 사용하면 컴파일 에러가 발생합니다.
            // 이유는 onClick() 함수가 리스너이기 때문인데,
            // i변수는 onCreate() 함수가 리턴되고 나면 사라져서
            // 리스너가 나중에 참조할 수 없기 때문입니다.
            // 그래서 final로 i 변수를 상수화하여 상수를 리스너에게 전달하여
            // 리스너가 상수를 간직할 수 있게 하기 위함입니다.
            final int index;
            index = i;
            
            // 이미지뷰 에셋에 xml에서 설정한 에셋을 찾아 대입합니다.
            image[index] = findViewById(imageId[index]);
            image[index].setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    
                    // 이미지를 클릭하면 투표 횟수가 1 증가하고
                    voteCount[index]++;
                    
                    // 토스트메시지가 출력됩니다.
                    Toast.makeText(getApplicationContext(), imgName[index] + ": 총 " +
                            voteCount[index] + " 표", Toast.LENGTH_SHORT).show();
                }
            });
        }

        // 투표 종료 버튼 구현
        Button btnFinish = findViewById(R.id.btnResult);
        btnFinish.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                
                // resultActivity.class로 전달할 intent를 생성합니다.
                Intent intent = new Intent(getApplicationContext(), ResultActivity.class);
                
                // intent에 voteCount변수를 "VoteCount"라는 이름으로 추가합니다.
                intent.putExtra("VoteCount", voteCount);
                
                // intect에 imgName변수를 "ImageName"이라는 이름으로 추가합니다.
                intent.putExtra("ImageName", imgName);
                
                // ResultActivity.class를 인수로 생성한 intent를 실행합니다.
                startActivity(intent);
            }
        });
    }
}

 

# ResultActivity.java

위치: project\app\java\"프로젝트명"\ 에 새로 생성합니다.

결과 액티비티 화면의 기능을 구현합니다.

 

package com.sikuroku.p10_2_ratingdrawing;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.TextView;

import androidx.annotation.Nullable;

public class ResultActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.result);

        // 메인액티비티에서 투표 종료 버튼을 눌렀을 때 실행된
        // startActivity(intent)의 intent를 가져와서 생성합니다.
        Intent intent = getIntent();
        
        // intent에서 정수배열 "VoteCount"를 가져옵니다.
        int[] voteResult = intent.getIntArrayExtra("VoteCount");
        
        // intent에서 문자열배열 "ImageName"를 가져옵니다.
        String[] imageName = intent.getStringArrayExtra("ImageName");

        // 항목의 이미지를 가져오진 않았기 때문에 이미지 리소스 주소를 저장합니다.
        Integer imageField[] = {R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4,
                R.drawable.pic5, R.drawable.pic6, R.drawable.pic7, R.drawable.pic8, R.drawable.pic9};

        TextView tvTop = findViewById(R.id.tvTop);
        ImageView ivTop = findViewById(R.id.ivTop);
        
        // 최다 득표 항목의 순번입니다.
        int maxEntry = 0;
        
        // 전체 항목의 투표 횟수와 비교하여 가장 많은 항목의 순번을 찾습니다.
        for(int i=1; i<voteResult.length; i++){
            if(voteResult[maxEntry] < voteResult[i])
                maxEntry = i;
        }

        // 최다 득표 항목의 이름을 설정합니다.
        tvTop.setText(imageName[maxEntry]);
        
        // 최다 득표 항목의 이미지을 설정합니다.
        ivTop.setImageResource(imageField[maxEntry]);

        // 텍스트뷰 변수를 넘어온 imageName의 길이만큼 선언합니다.
        TextView tv[] = new TextView[imageName.length];
        
        // 레이팅바 변수를 넘어온 imageName의 길이만큼 선언합니다.
        RatingBar rbar[] = new RatingBar[imageName.length];

        // resutl.xml에서 설정한 텍스트뷰 에셋의 아이디입니다.
        Integer tvID[] = {R.id.tv1, R.id.tv2, R.id.tv3, R.id.tv4, R.id.tv5, R.id.tv6,
                R.id.tv7, R.id.tv8, R.id.tv9};
                
        // // resutl.xml에서 설정한 레이팅바 에셋의 아이디입니다.
        Integer rbarID[] = {R.id.rbar1, R.id.rbar2, R.id.rbar3, R.id.rbar4, R.id.rbar5,
                R.id.rbar6, R.id.rbar7, R.id.rbar8, R.id.rbar9};

        // 텍스트뷰와 레이팅바 변수에 에셋을 대입해줍니다.
        for(int i=0; i<voteResult.length; i++){
            tv[i] = findViewById(tvID[i]);
            rbar[i] = findViewById(rbarID[i]);
        }
	
        // 텍스트뷰와 레이팅바에 항목이름과 투표횟수를 설정합니다.
        for(int i=0; i<voteResult.length; i++){
            tv[i].setText(imageName[i]);
            rbar[i].setRating((float) voteResult[i]);
        }
	
        // 현재 액티비티를 종료합니다.
        Button btnReturn = findViewById(R.id.btnReturn);
        btnReturn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
    }
}

 

728x90