반응형

 안드로이드에서는 Back 버튼을 누르면 현재 화면에서 이전 화면으로 돌아가거나, 앱이 종료가 된다. 

하지만 이럴 때에 부가적으로 처리를 해야하는 경우가 종종 있는데, 그 방법에 대해서 알아보자.

 

방법은 굉장히 단순하다. onBackPressed()라는 콜백 메소드를 오버라이드하기만 하면 된다. 

 

1
2
3
4
 @Override
    public void onBackPressed() {

// 여기다가 원하는 처리를 작성하면 된다.
        super.onBackPressed();
    }
cs

 

피드백은 언제나 환영입니다. 

반응형
반응형

 이전 시간에는 리사이클러뷰(RecyclerView)의 새 아이템을 추가하는 방법을 알아보았다. 

추가를 할 수 있다면 당연히 삭제도 할 수 있는 것이 맞다고 생각하기 때문에, 이번 시간에는 추가했던 아이템을

삭제하는 방법을 알아보도록 하겠다. 추가하는 방법보다 좀 더 쉽게 할 수 있을 것이다. 

 

삭제하는 메소드는 다음과 같다. 

1
2
3
4
5
6
7
8
9
10
public void deleteItem(int position) {
        items.remove(position);
       notifyItemRemoved(position);
       notifyItemRangeChanged(position, items.size());
    }
cs

 

items.remove(position)은 ArrayList인 items에서 데이터를 삭제할 수 있다.

notifyItemRemoved(position)은 특정 위치, 즉 RecyclerView에서 선택한 위치의 아이템을 삭제할 수 있다.

notifyItemRangeChange(position, items.size())는 변경된 아이템이 1개가 아니라 연속된 아이템일 때 사용한다.

(변경된 첫 번째 아이템의 위치 : position, 변경된 아이템의 개수 : items.size())

 

피드백은 언제나 환영입니다. 

 

반응형
반응형

 다들 알다시피 많은 앱을 사용하다보면 리스트 형태의 구조를 아주 많이 볼 수 있다.  

'리스트뷰(ListView)'를 사용할 수도 있지만, 보다 효율적이어서 더 많이 사용하는게 '리사이클러뷰(RecyclerView)' 이다. 

(리사이클러뷰가 어떤 것인지는 https://habilism.tistory.com/7 이 글을 참고하면 좋을 듯 하다. )

 

 그런데 리사이클러뷰를 사용할 때에는 코드에 미리 아이템의 데이터를 입력해둘 때도 있지만,

사용자가 원할 때 원하는 아이템을 추가해줘야 할 때도 많다.  

 

 

 

 이번 시간에는 메인 액티비티에 있는 버튼을 누르면 다른 액티비티인 작성 액티비티로 화면을 전환하여

데이터 입력을 하고, 작성 액티비티에 있는 버튼을 누르면 다시 메인 액티비티로 화면이 전환되면서

입력했던 데이터들이 어댑터를 통해 메인 액티비티의 리사이클러뷰에 추가되는 방법에 대해서 알아볼 것이다.  

 

 먼저, 메인 액티비티에서 버튼을 누르면 화면 전환이 되는데, 전환이 되고 끝나는 게 아니라, 데이터들을 받아서

다시 메인 액티비티 화면으로 돌아올 것이므로 인텐트를 보낼 때 startActivity(intent)가 아닌 startActivityForResult(intent, requestCode)를 호출할 것이다. 

 

1
2
  Intent intent = new Intent(getApplicationContext(), WriteActivity.class);
        startActivityForResult(intent, 101);
cs

 여기서 requestCode. 즉, 요청 코드가 무엇이냐면 지금 우리가 구현할 기능은 두 개의 액티비티끼리만 화면 전환을 하여 데이터를 주고 받지만, 더 큰 규모의 앱을 만들게 되면 많은 양의 화면이 왔다갔다하면서 데이터를 주고 받게 되는데, 이럴 때에는 requestCode를 사용해서 어디서 온 액티비티인지 구분을 할 수 있다. 

 

 다시 데이터를 돌려 받을 때는 콜백 메소드인 onActivityResult()를 통해서 받는데, 이 메소드는 조금 뒤에 알아보도록

하자. 

 

 이렇게 화면을 전환하면 데이터를 입력할 수 있는 액티비티인 WriteActivity 화면으로 오게 된다. 

여기서 사용자가 원하는 데이터를 입력하면 된다.

데이터 입력 후, 버튼을 눌러서 입력한 데이터들을 다시 메인 액티비티로 보내야하는데 아래의 코드처럼

작성하면 보낼 수 있다. 

 

1
2
3
4
5
6
7
8
public void sendMemo() {
        String memo = memoEdt.getText().toString(); 
 
        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtra("memo", memo);
        setResult(RESULT_OK, intent);
        finish();
    }
cs

 memoEdt라는 EditText에 원하는 문자열을 입력하고 입력한 문자열을 문자열 변수 memo에 할당한다.

그리고 메인 액티비티로 보내는 인텐트를 생성하고 그 인텐트에 memo를 넣어서

인텐트를 finish() 통해 이전 액티비티인 메인 액티비티로 보낸다. 

 

 이렇게 보낸 인텐트를 받아야 하는데, 메인 액티비티의 onActivityResult() 콜백 메소드로 받아서 처리할 수 있다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
 
        if (requestCode == 101) { 
            if (intent != null) {
                String memo = intent.getStringExtra("memo");
 
                adapter.addItem(new Memo(memo)); 
                adapter.notifyDataSetChanged();
            }
        }
    }
cs

 우리가 아까 메인 액티비티에서 작성 액티비티로 인텐트를 보낼 때 requestCode에 101를 지정했었다.

그래서 다시 돌려 받을 때 requestCode가 101인 것만 받아서 처리할 수 있다. 

 

 위처럼 받은 인텐트에서 "memo"라는 것을 뽑아내어 문자열 변수 memo에 할당한다.

그리고 memo를 어댑터의 addItem() 메소드로 새 아이템을 추가하면된다. 

(notifyDataSetChanged()를 해야 갱신이 되기 때문에 잊지말고 해주자.)

 

이렇게 리사이클러뷰에 새 아이템을 추가하는 방법에 대해서 알아보았다.

 

피드백은 언제나 환영입니다. 

 

 

반응형
반응형

 액티비티에서 다른 액티비티로 데이터를 전달해야하는 경우가 상당히 자주 있다. 

이렇게 데이터를 다른 액티비티로 전달할 때에는 '인텐트(Intent)'에 '부가 데이터(Extra Data)'를 넣어서 전달할 수 있는데

 

어떻게 데이터를 주고 받을까? 

 인텐트 안에는 '번들(Bundle)' 객체가 들어 있는데, 이것은 해시테이블과 비슷해서 putExtra()로 데이터를 넣고

getOOOExtra()로 데이터를 가져오는 방식으로 데이터를 주고 받을 수 있다. 

 

 데이터를 전달하는 방식 중에 아예 객체 자체를 전달하는 방법도 있는데, 그것은 바로 'Parcelable' 인터페이스를 이용하는 것이다. Parcelable 인터페이스는 Serializable 인터페이스와 비슷하지만 Serialization 했을 때 크기가 작아서

안드로이드 내부의 데이터 전달에 자주 사용된다. 이렇게 Parcelable 인터페이스를 사용하면 객체 자체를 번들에

넣어서 데이터를 전달할 수 있게된다.

 

Parcelable를 사용하려면 두 개의 메소드를 상속해야하는데,

첫 번째는 describeContents() 메소드이다. 이것은 Serialization 하려는 객체의 유형을 구분할 때 사용된다. 

두 번째는 writeToParcel() 메소드이다. 이것은 객체가 가지고 있는 데이터를 Parcel 객체로 만들어준다. 

 그리고 Parcel 객체는 번들 객체의 putExtra()나 getOOOExtra() 메소드처럼 readOOO(), writeOOO() 메소드로 데이터를 읽고 쓸 수 있다. 

 

 Parcelable를 이해하기 위한 예제를 해보겠다. 제목과 내용을 입력한 다음에 버튼을 누르면 액티비티 화면이 전환이

되면서 입력했던 데이터들이 전달되어 TextView에 출력하는 간단한 앱이다. 

 

 먼저, Parcelable 인터페이스부터 만들어보자. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class ExampleData implements Parcelable { // Parcelable 인터페이스를 상속
 
    String title;
    String contents;
 
    public ExampleData(String tit, String content) {
        title = tit;
        contents = content;
    }
 
    public ExampleData(Parcel src) { // Parcel 객체에서 읽기
        // 데이터를 읽어서 변수에 할당
        title = src.readString();
        contents = src.readString();
    }
 
    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { // Parcel 객체로부터 데이터를 읽어서 객체 생성
 
        @Override
        public ExampleData createFromParcel(Parcel src) { 
            return new ExampleData(src); // ExampleData 생성자 호출 후 Parcel 객체에서 읽기
        }
 
        // 여기에서 Parcel은 객체 안에 있는 데이터를 다른 곳에 전달할 때 사용된다.
 
        @Override
        public ExampleData[] newArray(int size) {
            return new ExampleData[size];
        }
    };
 
    @Override
    public int describeContents() {
        return 0;
    }
 
    @Override
    public void writeToParcel(Parcel dest, int flags) { // Parcel 객체로 쓰기(객체가 가지고 있는 데이터를 Parcel 객체로 만듬)
        dest.writeString(title);
        dest.writeString(contents);
    }
// 즉, Parcel 객체의 데이터를 읽는 부분과 쓰는 부분을 정의하는 것임
 
cs

Parcelable 인터페이스를 만들었으면 데이터를 서로 주고 받을 MainActivity와 ReceiveActivity를 만들어보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class MainActivity extends AppCompatActivity {
 
    public static final int REQUEST_CODE = 101;
    public static final String EXAMPLE_DAT_KEY = "data"// 번들 객체에 데이터를 저장하기 위한 Key
 
    EditText titleEdt, contentEdt;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        titleEdt = (EditText)findViewById(R.id.titleEdt);
        contentEdt = (EditText)findViewById(R.id.contentEdt);
 
        Button sendBtn = (Button)findViewById(R.id.sendBtn);
        sendBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 입력한 제목과 내용의 문자열을 변수에 할당
                String title = titleEdt.getText().toString();
                String contents = contentEdt.getText().toString();
 
                // 인텐트에 데이터를 넣어서 다른 액티비티로 전달함
                Intent intent = new Intent(getApplicationContext(), ReceiveActivity.class);
                ExampleData exampleData = new ExampleData(title, contents);
                intent.putExtra(EXAMPLE_DAT_KEY, exampleData);
                startActivityForResult(intent, REQUEST_CODE);
            }
        });
    }
}
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class ReceiveActivity extends AppCompatActivity {
 
    public static final String EXAMPLE_DATA_KEY = "data"// 번들 객체에 데이터를 저장하기 위한 Key
 
    TextView tv;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_receive);
 
        tv = (TextView)findViewById(R.id.tv);
 
        Button backBtn = (Button)findViewById(R.id.backBtn);
        backBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
 
        Intent intent = getIntent(); // 인텐트 객체 반환, 객체 안의 번들 객체 참조
        processIntent(intent); // 인텐트를 전달해서 processIntent() 메소드에서 처리
    }
 
    private void processIntent(Intent intent) { // 번들 객체에서 꺼낸 후 TextView로 보여줌
        if(intent != null) {
            Bundle bundle = intent.getExtras();
            ExampleData exampleData = bundle.getParcelable(EXAMPLE_DATA_KEY);
 
            if(intent != null) {
                tv.setText("제목 : " + exampleData.title + "\n" +"내용 : " + exampleData.contents);
            }
        }
    }
}
cs

초기 실행 화면
데이터 입력 후 전송 버튼 누르기

 

최종 화면

 

피드백은 언제나 환영입니다. 

반응형
반응형

 많은 앱들을 보면 앱을 실행한 뒤 앱의 메인 화면이 화면에 보이기 전에 앱의 로고나 이름 등이 들어간

화면이 1초 정도 보이고 사라진다. 이러한 화면을 '스플래시 화면(Splash Screen') 이라고 한다. 

우리가 자주 사용하는 앱인 카카오톡이나 유튜브만 봐도 별거 아닌 기능이지만 앱의 완성도를 조금이나마 높혀준다.

 

 스플래시 화면은 이름 그대로 '화면'이기 때문에 액티비티로 만들 수 있다. 

우선 스플래시 화면을 위한 액티비티를 만들어보자. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class SplashActivity extends AppCompatActivity {
 
    Handler handler = new Handler();
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 우리가 보통 사용하는 액티비티와는 다르게 이 부분에 xml 파일의 인플레이션을 하는 setContentView 메소드가  없음
 
        handler.postDelayed(new Runnable() { // 핸들러로 지연시키는 메소드
            @Override
            public void run() {
                Intent intent = new Intent(getApplicationContext(), MainActivity.class);
                startActivity(intent);
 
                finish(); // 메인 화면에서 뒤로 가기를 눌렀을 때 앱이 꺼지게함, finish()가 없는 상태에서
                // 뒤로 가기를 누르면 다시 스플래시 화면으로 돌아가서 고정됨
            }
        }, 1000); // 핸들러로 1초 지연시킴
    }
}
cs

 

스플래시 화면을 xml파일이 아닌 '테마(Theme)' 를 이용해서 만들 것이니 xml은 그냥 만들어 놓기만 하면 된다. 

그리고 매니페스트 파일로 가서 첫 시작 화면을 다음과 같이 스플래시 화면으로 수정해야된다.

 

1
2
3
4
5
6
7
8
9
10
  <activity android:name=".MainActivity" />
        <activity
            android:name=".SplashActivity"
            android:theme="@style/SplashTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
cs

그런데 위의 매니페스트 코드에서 좀 낯선 부분이 있을 것이다. 

이제 부터 우리가 다룰 '테마(Theme)' 라는 것인데 테마를 이용하면 앱 디자인의 세부사항을 UI 구조 및 동작과 

분리할 수 있다는 장점이 있다. 그 '테마'에 대한 정의를 스플래시 액티비티에 해놓았고 이제부터 테마를

직접 만들어보자.

 

매니페스트에 미리 정의해놓은 테마 이름을 res/values/theme.xml 파일에 들어가서 

1
2
3
 <style name="SplashTheme" parent="Theme.AppCompat.NoActionBar" >
        <item name="android:windowBackground" >@drawable/splash_background</item>
    </style>
cs

위와 같이 스타일로 설정해놓는다. 그리고 NoActionBar를 상속해서 액션바 부분이 안 보이도록 설정하고,

windowBackground 속성에 우리가 만들어야 할 드로어블을 지정해서 배경으로 보이게 할 것이다. 

 

그럼 드로어블 파일도 만들어보자.

 

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 
    <item android:drawable="@drawable/splash_base" />
 
    <item android:top="210dp" >
        <bitmap android:src="@drawable/colorlogo" android:gravity="top" />
    </item>
</layer-list>
cs

위의 코드에서 보면 item 태그가 두 개가 들어 있는 것을 알 수 있는데,

첫 번째 item 태그는 화면의 전체를 채울 것이고, 두 번째 item 태그는 이미지를 가져와서 특정한 위치에

놓을 것이다. 여기서 또, 화면의 전체를 채울 드로어블 파일을 만들어야한다. 

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
 
    <gradient
        android:startColor="#acffef"
        android:centerColor="#cbff75"
        android:endColor="#66f8f0"
        android:angle="180"
        android:centerY="1.5" />
 
    <corners android:radius="0dp" />
</shape>
cs

배경색을 위와 같이 설정할 수 있다. 본인이 원하는 대로 수정해보면 된다. 

 

 

 

피드백은 환영입니다. 

반응형
반응형

 앱을 사용하다보면 앱이 갑자기 중지되거나 다시 화면에 나타날 때가 있는데, 이럴 때에 앱의 현재 상태 정보가 저장

되고 복원되는 것은 상당히 중요하다. 예를 들어, 게임을 할 때 개인 점수 기록을 세웠다든지, 그 외 다른 앱을 사용할 때중요한 정보를 입력해 놓았을 때라든지 데이터를 저장해 놓지 않으면 앱을 다시 실행할 때 처음부터 다시해야하는 번거로움이 있게 된다. 

 

 보통 대량의 데이터를 저장할 때에는 데이터베이스를 사용하지만, 앱 안에서 간단한 데이터를 저장하거나 복원할 

때에는 'SharedPreferences' 를 사용할 수 있는데, 이 'SharedPreferences'는 앱 내부에 파일을 하나 만들고 이 파일

안에서 데이터를 저장하고 읽어올 수 있다. 

 

 그렇다면 이 'SharedPreferences'는 어떻게 사용을 할까? 

이번 시간에는 예제로 앱이 종료될 때(onDestroy()) 데이터를 저장하고, 앱을 다시 실행시킬 때(onCreate()) 

저장된 데이터를 불러오는 간단한 코드를 작성해볼 것이다. 

 

 먼저 화면에 TextView를 하나만 놓고 액티비티 코드를 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class MainActivity extends AppCompatActivity {
 
    TextView textView;
 
    String recordFile = "file";
 
    @Override
    protected void onCreate(Bundle savedInstanceState) { // 앱이 실행되면서 저장된 데이터를 불러옴
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        textView = (TextView) findViewById(R.id.textView);
 
        SharedPreferences sharedPreferences = getSharedPreferences(recordFile, Activity.MODE_PRIVATE);
        String record = sharedPreferences.getString("record""");
        textView.setText(record);
 
    }
 
    @Override
    protected void onDestroy() { // 앱이 중지가 되면서 데이터가 저장이됨
        super.onDestroy();
 
        SharedPreferences sharedPreferences = getSharedPreferences(recordFile, Activity.MODE_PRIVATE); // 데이터 저장소에 데이터를 저장하는 객체
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putString("record", textView.getText().toString()); // 저장하려는 데이터 설정
        editor.commit(); // 실제로 저장
    }
}
cs

 

위와 같이 약간의 SharedPreferences 코드 추가로 앱을 껐다가 다시 실행시켜도 데이터들이 사라지지 않고 그대로 사용할 수 있게 된다. 

 

피드백은 언제나 환영입니다. 

 

 

 

 

 

반응형
반응형

리사이클러뷰를 사용할 때 거꾸로 출력해야할 때가 있는데

굉장히 간단하게 구현할 수 있다.

 

1
2
3
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);
cs

위와 같이 레이아웃 매니저를 생성하고 

두 줄의 코드를 추가로 입력해주면 된다. 

 

 

 

피드백은 언제나 환영입니다. 

반응형
반응형

 안드로이드 앱을 사용하면서 여러 개의 선택지 중에서 원하는 하나를 고르거나 또는 여러 개를 골라야할 때가 있다. 

이럴 때 사용하는 것이 '메뉴(Menu)' 인데, 메뉴는 평소에 아주 많이 쓰이는 UI 요소이고, 모든 기능들을 계층적으로 

표시할 수 있다.  이렇게 안드로이드 메뉴에는 옵션 메뉴, 컨텍스트 메뉴, 팝업 메뉴와 같은 여러 가지의 종류의 메뉴가 있는데, 이번 시간에는 액티비티의 주된 메뉴라고 할 수 있는 '옵션 메뉴(Option Menu)' 를 알아볼 것이다. 

 

 먼저, '옵션 메뉴(Option Menu)' 를 만드려면 xml로 메뉴를 정의해야한다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
 
    <item
        android:id="@+id/two"
        android:title="2x2x2"
        app:showAsAction="never" />
    <item
        android:id="@+id/three"
        android:title="3x3x3"
        app:showAsAction="never" />
    <item
        android:id="@+id/onehand"
        android:title="3x3x3 One-Handed"
        app:showAsAction="never" />
</menu>
cs

위의 xml 코드에서 보면, app:showAsAction이라는 속성이 보일 것이다. 

이 속성은 메뉴 아이템들이 어떻게 보일 것인가에 대해 설정하는 것으로써 다음과 같은 속성들이 있다. 

showAsAction 속성 값 비고
ifRoom 앱 바에 표시할 여유 공간이 있을 때만 아이템을 표시한다.
always 항상 앱 바에 메뉴 아이템을 추가하여 표시한다.
never 앱 바에 아이템을 추가하여 표시하지 않는다. (디폴트, 더보기를 누르면 리스트 형식으로
표시됨)
withText android:title 속성에 정의한 제목을 표시한다.
collapseActionView 아이템에 설정한 뷰의 아이콘만 표시한다. 

메뉴를 위한 xml파일

 

xml 파일을 만들고 나면 이것을 액티비티에다가 '팽창(Inflate)' 시켜줘야한다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.event_list, menu);
        return true;
    }
 
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()) {
            case R.id.two:
                Toast.makeText(getApplicationContext(), "2x2x2 종목이 선택되었습니다. ", Toast.LENGTH_SHORT).show();
                break;
 
            case R.id.three:
                Toast.makeText(getApplicationContext(), "3x3x3 종목이 선택되었습니다. ", Toast.LENGTH_SHORT).show();
                break;
 
            case R.id.onehand:
                Toast.makeText(getApplicationContext(), "3x3x3한손 종목이 선택되었습니다. ", Toast.LENGTH_SHORT).show();
                break;
        }
        return super.onOptionsItemSelected(item);
    }
cs

 

이렇게 간단한 코드를 작성해주면 메뉴 xml이 액티비티에 팽창이 되어서

앱 바의 더보기 아이콘을 누르면 옵션 메뉴들이 리스트 형식으로 나타나게 된다. 

 

 

피드백은 언제나 환영입니다. 

반응형

+ Recent posts