1. GitHub에서 Contribution에 반영하는 법
: 로컬 리포지터리(local repository) 경로에서 user.name과 user.email 세팅 필요
(GitHub 계정의 이름과 email이 같아야 반영)
1) 확인하기
** 이름 : git config --local user.name
** 이메일 : git config --local user.email
2) 세팅하기
** 커맨드 창에서 로컬 리포지터리(local repository) 경로 이동
** git config --local user.name "github에 가입시 등록한 자신의 이름"
** git config --local user.email "github에 가입시 등록한 이메일"
2. a010_storage 모듈
1) MainActivity 액티비티, activity_main 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a010_storage">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Internal Storage"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<EditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:text="안녕하세요" />
<Button
android:id="@+id/btnAppend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="추가저장" />
<Button
android:id="@+id/btnRead"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="읽어오기" />
<TextView
android:id="@+id/tvResult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="결과창" />
</LinearLayout>
package com.lec.android.a010_storage;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
/**
* 안드로이드 에서 자료를 저장하는 4가지 수단
* 1. 내부파일 사용 (Internal Storage) : '앱 데이터' 저장 영역
* 2. 외부메모리 사용 (External Storage) : 사진, 동영상등 '사용자 영역'
* 3. SQLite (내장 DataBase)
* 4. SharedPreference
*
* ** 외부에 (서버, 네트워크, 외부 DB) 사용이 아닌 내부 저장수단
*
* https://developer.android.com/training/data-storage
*
* 내부 파일 사용 (Internal Storage, App-specific storage)
* - 앱 데이터가 저장되는 영역
* - 별도의 permission 없이 사용 가능
* - 자신의 앱에서만 사용 가능, 다른 앱에서 접근 못함
* - 앱 제거시, Internal Storage 영역의 모든 데이터도 제거됨.
* - openFileOutput() 를 사용하여 저장 ( FileOutputStream 객체 리턴함 )
*/
// Device File Explrer 에서 생성된 파일 확인 가능
// Pixel2 폰의 경우
// /data/data/com.lec.android.a010_storage/files/myfile.txt
public class MainActivity extends AppCompatActivity {
EditText et;
Button btnAppend, btnRead;
TextView tvResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et = findViewById(R.id.et);
btnAppend = findViewById(R.id.btnAppend);
btnRead = findViewById(R.id.btnRead);
tvResult = findViewById(R.id.tvResult);
// R(write), A(append), R(read)
// 추가하기 버튼 클릭하면 파일에 추가로 저장하기
btnAppend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String data = et.getText().toString();
try {
// openFileOutput 을 사용하여 OutputStream 객체 뽑아내기
FileOutputStream os = openFileOutput("myfile.txt", MODE_APPEND);
PrintWriter out = new PrintWriter(os);
out.println(data);
out.close();
tvResult.setText("파일 저장 완료");
} catch (IOException e) {
e.printStackTrace();
}
}
});
// 파일의 내용을 읽어서 보여주기
btnRead.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
FileInputStream is = openFileInput("myfile.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuffer data = new StringBuffer();
String str = reader.readLine(); // 파일에서 한줄을 읽어 오기
while (str != null) {
data.append(str + "\n");
str = reader.readLine();
} // end while
tvResult.setText(data);
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
} // end onCreate()
} // end Activity
[추가] data/data/com.lec.android.a010_storage/files/myfile.txt에서 생성된 파일을 확인할 수 있음
2) Main2Activity 액티비티, activity_main2 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a010_storage">
<!-- 외부 저장소 사용 권한 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/AppTheme">
<activity android:name=".Main2Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity" />
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="External Storage"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<EditText
android:id="@+id/etInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:text="안녕하세요" >
<requestFocus />
</EditText>
<Button
android:id="@+id/btnSave"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="저장하기" />
<Button
android:id="@+id/btnRead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="읽어오기" />
<TextView
android:id="@+id/tvResult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="결과창"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
package com.lec.android.a010_storage;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 외부 메모리 (External Memory 혹은 Shared storage)
* 사용자 영역 에 저장 ( sdcard 같은 외장 메모리를 의미하는게 아니다)
* 메모리가 장착(mount)되어 있어야 사용 가능
* 모든 앱에서 접근 가능 (공유 가능)
*
* 외부 메모리에 파일 읽기/쓰기
* 1. 외부 메모리 장치가 있는지 확인해야한다 : getExternalStorageState()
* 2-1 AndroidManifest.xml 외부메모리 저장권한을 선언해야 함 (API 23 이전 버젼)
* WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE
* 2-2 API 23+ (마시멜로): 새로운 권한 획득 방법 사용.
* Run-time 에 onRequestPermissionsResult() 사용 해야 한다!!!
* https://developer.android.com/training/permissions/requesting.html
*
* 3. 읽기/쓰기 경로를 지정한다
*/
public class Main2Activity extends AppCompatActivity {
EditText etInput;
Button btnSave, btnRead;
TextView tvResult;
// permission 관련
final String[] PERMISSIONS = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
final int REQUEST_CODE = 100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
etInput = findViewById(R.id.etInput);
btnRead = findViewById(R.id.btnRead);
btnSave = findViewById(R.id.btnSave);
tvResult = findViewById(R.id.tvResult);
// 위험권한 획득
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
checkSelfPermission(String.valueOf(PERMISSIONS)) == PackageManager.PERMISSION_DENIED) {
requestPermissions(PERMISSIONS, REQUEST_CODE); // 권한 요청하기
}
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!checkExternalStorage()) {return;} // 외부 메모리 사용 못하면 종료
String data = etInput.getText().toString();
try {
// 저장 경로 가져오기
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File f = new File(path, "external.txt"); // 경로/파일명
FileWriter writer = new FileWriter(f, false); // true 이면 append 모드로 생성
PrintWriter out = new PrintWriter(writer);
out.println(data);
out.close();
tvResult.setText("저장완료");
} catch (IOException e) {
e.printStackTrace();
}
}
});
btnRead.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!checkExternalStorage()) {return;} // 외부메모리 사용 가능 여부 체크
try {
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File f = new File(path, "external.txt");
BufferedReader reader = new BufferedReader(new FileReader(f));
StringBuffer data = new StringBuffer();
String str = reader.readLine();
while (str != null) {
data.append(str);
str = reader.readLine();
}
tvResult.setText(data);
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
} // end onCreate()
// 권한 획득 결과 받으면 실행되는 콜백
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "권한 승인", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "권한 거부", Toast.LENGTH_LONG).show();
// 권한이 없으면 더이상 진행 못하게 하든지 다른 조치를 취해야 한다.
// onDestroy();
}
return;
} // end switch
} // end onRequestPermissionsResult()
// 외부 메모리 상태 확인 메소드
protected boolean checkExternalStorage() {
String state = Environment.getExternalStorageState();
String msg = "";
// 외부 메모리 상태
if (Environment.MEDIA_MOUNTED.equals(state)) { // "mounted"
// 읽기, 쓰기 모두 가능
msg = "외부메모리 읽기 쓰기 모두 가능";
Log.d("mpapp", msg);
Toast.makeText(this,msg, Toast.LENGTH_LONG).show();
return true;
} else if(Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { // "mounted_ro"
// 읽기 전용
msg = "외부메모리 읽기만 가능";
msg = " 외부메모리 읽기만 가능";
Log.d("mpapp", msg);
Toast.makeText(this,msg, Toast.LENGTH_LONG).show();
return false;
} else {
// 읽기 쓰기 모두 안됨..!!
msg = "외부메모리 읽기쓰기 모두 안됨 : " + state;
Log.d("myapp", msg);
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
return false;
}
} // end checkExternalStorage()
} // end Activity
[추가] sdcard/Pictures/external.txt에서 생성된 파일을 확인할 수 있음
3) Main3Activity 액티비티, activity_main3 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a010_storage">
<!-- 외부 저장소 사용 권한 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".Main3Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Main2Activity" />
<activity android:name=".MainActivity" />
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Main3Activity">
<TextView
android:id="@+id/textView"
android:layout_width="146dp"
android:layout_height="88dp"
android:text="SQLite"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
** MySQLiteOpenHelper3 클래스
package com.lec.android.a010_storage;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import androidx.annotation.Nullable;
// SQLiteOpenHelper
// 안드로이드에서 SQLite3 데이터베이스를 좀 더 쉽게 사용할 수 있도록 제공되는 클래스
public class MySQLiteOpenHelper3 extends SQLiteOpenHelper {
public MySQLiteOpenHelper3(@Nullable Context context, @Nullable String name,
@Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
Log.d("myapp", "SQLiteOpenHelper 생성");
}
// 앱 설치 후 최소에 데이터베이스가 '없는 경우', 데이터 베이스 생성을 위해 호출되는 콜백
// 최소의 가동될 때만 실행됨...!! 딱 한 번만...!!
// 주로 DDL 등 테이블 생성하는 코드 작성
@Override
public void onCreate(SQLiteDatabase db) {
Log.d("myapp", "SQLiteOpenHelper] onCreate() 호출");
String sql = "CREATE TABLE myTable (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"name TEXT" +
")";
db.execSQL(sql);
}
// 데이터베이스의 '버전'이 바뀌었을때 호출되는 콜백
// '버전'이 바뀌었을때 기존의 설치 운영되고 있는 데이터베이스를 어떻게 변경할 것인지 작성
// '버전'이 바뀔 때마다 실행됨...!!
// 각 버전의 변경 내용들을 버전마다 작성해야 함
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.d("myapp", "SQLiteOpenHelper] onUpgrade 호출" + oldVersion + " -> " + newVersion);
String sql = "DROP TABLE myTable"; // 기존 테이블 삭제
db.execSQL(sql);
onCreate(db); // 다시 테이블 생성
}
}
** Main3Activity 액티비티
package com.lec.android.a010_storage;
import androidx.appcompat.app.AppCompatActivity;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
// SQLite3 : 안드로이드에 기본탑재된 모바일 용으로 제작된 경량화 DB
// C언어로 엔진이 제작되어 가볍다
// 안드로이드에서 sqLite3 를 쉽게 사용할 수 있도록 SQLiteOpenHelper클래스제공
// SQLite 를 사용한 데이터 저장
// 1. SQLiteOpenHelper 를 상속받은 클래스 정의
// onCreate(), onUpgrade() 작성
// 2. 위 Helper 로부터 SQLiteDatabase DB 객체 추출
// 3. DML 명령은 : execSQL()
// SELECT 명령은 : rawQuery() --> 결과는 Cursor 객체 사용하여 다룸
public class Main3Activity extends AppCompatActivity {
MySQLiteOpenHelper3 helper;
String dbName = "st_file.db"; // '파일'의 형태로 DB가 저장된다.
int dbVersion = 2; // 데이터베이스 버전
SQLiteDatabase db;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
helper = new MySQLiteOpenHelper3(
this, // 현재 화면의 제어권자
dbName, // DB 이름
null, // 커서팩토리-null : 표준 커서가 사용됨
dbVersion // DB버전
);
try {
db = helper.getWritableDatabase(); // 읽고 쓰기 가능한 DB
//db = helper.getReadableDatabase(); // 읽기 전용 DB ( 예. SELECT 만 사용하는 경우 )
} catch (SQLException e) {
e.printStackTrace();
Log.e("myapp", "데이터베이스를 얻어올 수 없음");
finish(); // 액티비티 종료
}
insert();
select();
update();
select();
delete();
select();
} // end onCreate()
void delete() {
db.execSQL("DELETE FROM myTable WHERE id = 2");
Log.d("myapp", "DELETE 완료");
}
void update() {
db.execSQL("UPDATE myTable SET name = '홍성용' WHERE id = 5");
Log.d("myapp", "UPDATE 완료");
}
void select() {
Cursor c = db.rawQuery("SELECT * FROM myTable", null);
while(c.moveToNext()) {
int id = c.getInt(0); // 컬럼 인덱스 0부터 시작!!!
String name = c.getString(1);
Log.d("myapp", "id : " + id + ", name : " + name);
}
} // end select()
void insert() {
db.execSQL("INSERT INTO myTable (name) values ('김민호')");
db.execSQL("INSERT INTO myTable (name) values ('이승환')");
db.execSQL("INSERT INTO myTable (name) values ('남윤주')");
db.execSQL("INSERT INTO myTable (name) values ('이성은')");
db.execSQL("INSERT INTO myTable (name) values ('윤종섭')");
Log.d("myapp", "INSERT 성공~");
} // end insert()
} // end Activity
[추가] data/data/com.lec.android.a010_storage/databases에서 생성된 파일을 확인할 수 있음
4) Main4Activity 액티비티, activity_main4 레이아웃
[추가] 기존의 MySQLiteOpenHelper3 클래스를 복사하여 MySQLiteOpenHelper4로 클래스 파일 만들기
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a010_storage">
<!-- 외부 저장소 사용 권한 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".Main4Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Main3Activity" />
<activity android:name=".Main2Activity" />
<activity android:name=".MainActivity" />
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".Main4Activity">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="SQLite 예제"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="이름"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<EditText
android:id="@+id/etName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvAge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="나이"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<EditText
android:id="@+id/etAge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvAddress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="주소"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<EditText
android:id="@+id/etAddress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName" />
</TableRow>
</TableLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btnInsert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="INSERT" />
<Button
android:id="@+id/btnUpdate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="UPDATE" />
<Button
android:id="@+id/btnDelete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="DELETE" />
<Button
android:id="@+id/btnSelect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="SELECt" />
</LinearLayout>
<TextView
android:id="@+id/tvResult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="결과창"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
</LinearLayout>
** Main4Activity 액티비티
package com.lec.android.a010_storage;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
// DML 이나 일반적인 SQL 문은 execSQL() 사용,
// 그러나 affected row 개수등 int 값을 리턴하지는 않음!
// int 값 받고 싶으면 SQLiteDatabase 의 insert(), update(), delete() 사용해야 한다
// 기존의 JDBC 프로그래밍과 다른 독특한 메소드들 제공
public class Main4Activity extends AppCompatActivity {
String dbName = "st_file2.db";
int dvVersion = 1;
MySQLiteOpenHelper4 helper;
SQLiteDatabase db;
String tableName = "student";
EditText etName, etAge, etAddress;
Button btnInsert, btnUpdate, btnDelete, btnSelect;
TextView tvResult; // 결과창
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
etName = findViewById(R.id.etName);
etAge = findViewById(R.id.etAge);
etAddress = findViewById(R.id.etAddress);
btnInsert = findViewById(R.id.btnInsert);
btnUpdate = findViewById(R.id.btnUpdate);
btnDelete = findViewById(R.id.btnDelete);
btnSelect = findViewById(R.id.btnSelect);
tvResult = findViewById(R.id.tvResult);
helper = new MySQLiteOpenHelper4(
this,
dbName,
null,
dvVersion
);
try {
db = helper.getWritableDatabase();
} catch (SQLiteException e) {
e.printStackTrace();
Log.e("myapp", "데이터베이스를 열 수 없음"); // Logcat 의 error 에 표시함
}
btnInsert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String name = etName.getText().toString();
String age = etAge.getText().toString();
String address = etAddress.getText().toString();
if("".equals(name)) {
tvResult.setText("INSERT 실패 : 필수 항목을 입력하세요");
return;
}
int a = 0;
try {
a = Integer.parseInt(age);
} catch (NumberFormatException e) {
tvResult.setText("INSERT 실패 - age 는 숫자로 입력하세요");
}
insert(name, a, address);
}
});
btnUpdate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String name = etName.getText().toString();
String age = etAge.getText().toString();
String address = etAddress.getText().toString();
if("".equals(name)) {
tvResult.setText("UPDATE 실패 : 필수 항목을 입력하세요");
return;
}
int a = 0;
try {
a = Integer.parseInt(age);
} catch (NumberFormatException e) {
tvResult.setText("UPDATE 실패 - age 는 숫자로 입력하세요");
}
update(name, a, address);
}
});
btnDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String name = etName.getText().toString();
if("".equals(name)) {
tvResult.setText("DELETE 실패 - 삭제된 이름을 입력하세요");
return;
}
delete(name);
}
});
btnSelect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tvResult.setText("");
select();
}
});
} // end onCreate()
void insert(String name, int age, String address) {
ContentValues values = new ContentValues(); // name-value 쌍으로 저장하는 객체
// 키, 값의 쌍으로 데이터 입력
values.put("name", name);
values.put("age", age);
values.put("address", address);
// INSERT INTO tableName(name, age, address) values(?, ?, ?)
// 리턴값은 auto-generated key 값, 실패하면 -1 리턴
long result = db.insert(tableName, null, values);
Log.d("myapp", result + "번째 row INSERT 성공");
tvResult.setText(result + "번째 row INSERT 성공");
select();
} // end insert()
void select() {
// SELECT 문을 위한 query() 메소드
Cursor c = db.query(tableName, null, null,
null, null, null, null);
// db.query("sku_table", columns, "owner=?", new String[] { "Mike" }, null, null, null);
// --> WHERE owner='Mike'
// db.query("sku_table", columns, "owner=? AND price=?", new String[] { "Mike", "100" }, null, null, null);
// --> WHERE owner='Mike' AND price=100
while (c.moveToNext()) {
int id = c.getInt(0);
String name = c.getString(1);
int age = c. getInt(2);
String address = c.getString(3);
String msg = String.format("id:%d, name:%s, age:%d, address:%s", id, name, age, address);
Log.d("myapp", msg);
tvResult.append("\n" + msg);
} // end while
// 키보드 내리기
InputMethodManager imm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
} // end select()
void update(String name, int age, String address) {
ContentValues values = new ContentValues();
values.put("age", age); // 변경할 값
values.put("address", address); // 변경할 값
// UPDATE student SET age = ?, address = ? WHERE name = ?
// 리턴값은 affected rows
int cnt = db.update(tableName, // 테이블명
values, // 변경할 값들
"name=?", // WHERE 조건절
new String[] {name} // 조건절의 ? 값들
);
String msg = cnt + " 개의 row update 성공";
tvResult.setText(msg);
select();
} // end update()
// 특정 name 값을 가진 레코드(들) 삭제
void delete (String name) {
// 리턴값은 affected rows
int cnt = db.delete(tableName, // 테이블명
"name=?", // WHERE 조건절
new String[] {name} // 위 조건절의 ? 값들
);
String msg = cnt + "개 row delete 성공";
tvResult.setText(msg);
Log.d("myapp", msg);
select();
} // end delete()
} // end Activity
/*
insert() 의 두번째 매개변수 nullColumnHack 의 의미
어떤 테이블의 모든 컬럼이 NULL 입력이 가능하다고 하자.
이 경우 INSERT INTO suchTable; 과 같이 SQL 구문을 작성할 수 있지만 SQLite3 에서는 유효한 구문이 아니다.
이 대신 INSERT INTO suchTable(column) VALUES(NULL); 처럼 하나라도 값을 채워주어야 SQL 문이 정상적으로 수행한다.
이처럼 입력하는 레코드의 데이터가 빈 경우, 즉 ContentValues 객체에 put() 메서드로 입력된 값이 없는 경우에는 두 번째 인자인 nullColumnHack 에 문자열로 테이블의 한 컬럼을 지정해줘야 에러 없이 정상적으로 SQL 문이 수행된다.
*/
** MySQLiteOpenHelper4 클래스
package com.lec.android.a010_storage;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import androidx.annotation.Nullable;
// SQLiteOpenHelper
// 안드로이드에서 SQLite4 데이터베이스를 좀 더 쉽게 사용할 수 있도록 제공되는 클래스
public class MySQLiteOpenHelper4 extends SQLiteOpenHelper {
public MySQLiteOpenHelper4(@Nullable Context context, @Nullable String name,
@Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
Log.d("myapp", "SQLiteOpenHelper 생성");
}
// 앱 설치 후 최소에 데이터베이스가 '없는 경우', 데이터 베이스 생성을 위해 호출되는 콜백
// 주로 DDL 등 테이블 생성하는 코드 작성
@Override
public void onCreate(SQLiteDatabase db) {
Log.d("myapp", "SQLiteOpenHelper] onCreate() 호출");
String sql = "CREATE TABLE student (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"name TEXT, age INTEGER, address TEXT" +
")";
db.execSQL(sql);
}
// 데이터베이스의 '버전'이 바뀌었을때 호출되는 콜백
// '버전'이 바뀌었을때 기존의 설치 운영되고 있는 데이터베이스를 어떻게 변경할 것인지 작성
// 각 버전의 변경 내용들을 버전마다 작성해야 함
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.d("myapp", "SQLiteOpenHelper] onUpgrade 호출" + oldVersion + " -> " + newVersion);
String sql = "DROP TABLE IF EXISTS student"; // 기존 테이블 삭제
db.execSQL(sql);
onCreate(db); // 다시 테이블 생성
}
}
5) Main5Activity 액티비티, activity_main5 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a010_storage">
<!-- 외부 저장소 사용 권한 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".Main5Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Main4Activity" />
<activity android:name=".Main3Activity" />
<activity android:name=".Main2Activity" />
<activity android:name=".MainActivity" />
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".Main5Activity">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="SharedPreference"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<EditText
android:id="@+id/etInput"
android:layout_width="match_parent"
android:layout_height="83dp"
android:ems="10"
android:inputType="textPersonName"
android:text="Name" />
</LinearLayout>
package com.lec.android.a010_storage;
import androidx.appcompat.app.AppCompatActivity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.widget.EditText;
// SharedPreference
// key-value 쌍으로 데이터 저장
// 작은 데이터들 (세팅값들) 저장 용도로 활용
public class Main5Activity extends AppCompatActivity {
EditText etInput;
String sfName = "myFile";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main5);
etInput = findViewById(R.id.etInput);
// 저장되어 있는 값을 꺼내서 보여주기
SharedPreferences sf = getSharedPreferences(sfName, MODE_PRIVATE);
String str = sf.getString("name", ""); // 키값으로 꺼냄
String xx = sf.getString("xx", "ABC");
String yy = sf.getString("yy", "XY2");
etInput.setText(str);
Log.d("myapp", str + " - " + xx + " - " + yy);
} // end onCreate()
@Override
protected void onPause() {
super.onPause();
// Activity 가 종료되기 전에 저장
SharedPreferences sf = getSharedPreferences(sfName, MODE_PRIVATE);
SharedPreferences.Editor editor = sf.edit(); // 저장하려면 Editor 객체 필요
String str = etInput.getText().toString(); // 사용자가 입력한 값
editor.putString("name", str);
editor.putString("xx", "가나다");
editor.commit(); // 파일에 최종 반영함.
} // end onPause()
} // end Activity
3. a013_Menu 모듈
1) MainActivity 액티비티, activity_main 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a013_menu">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="OptionMenu"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<ImageView
android:id="@+id/imageView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:srcCompat="@android:drawable/ic_input_add" />
</LinearLayout>
[추가] 옵션 레이아웃 만들기
① 먼저 폴더를 만들어야 함
: res > New > Android Resource Directory 선택
> Resource type을 menu로 선택 후 OK 클릭하면 폴더 생성
② 폴더 만든 후 메뉴 레이아웃 만들기
: 생성한 menu 폴더 선택 후 우클릭 > New > Menu Resource File 선택
> File name 설정 후 OK 클릭하면 레이아웃 생성
③ 메뉴 레이아웃 만들기..!!
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_login"
android:title="로그인"
android:orderInCategory="100"
app:showAsAction="never" />
<item
android:id="@+id/menu_logout"
android:title="로그아웃"
android:orderInCategory="100"
app:showAsAction="never" />
<item
android:id="@+id/menu_next"
android:title="다음"
android:orderInCategory="100"
app:showAsAction="never" />
<!-- #3
showAsAction :
이 메뉴를 '액션바' 영역에 보이게 할지 여부
always : 항상 보이게
never : 항상 안보이게 하기
ifRoom : 액션바에 여유공간이 있을때만 표시
withTextView : title 속성으로 설정된 제목 같이 표시
collapseActionView : 아이템에 설정한 뷰의 아이콘만 표시
-->
<item
android:id="@+id/menu_pref"
android:title="이전"
android:orderInCategory="100"
app:showAsAction="always" />
<!-- 아이콘 가능: 아이콘이 있으면
title 대신 icon 이 우선적으로 보임 -->
<item
android:id="@+id/menu_first"
android:title="처음"
android:orderInCategory="100"
app:showAsAction="always"
android:icon="@android:drawable/ic_media_rew" />
<item
android:id="@+id/menu_last"
android:title="마지막"
android:orderInCategory="100"
app:showAsAction="always"
android:icon="@android:drawable/ic_media_ff" />
<!-- 액션바 공간 비좁다 -->
<item
android:id="@+id/menu_1"
android:orderInCategory="100"
android:title="첫번째"
app:showAsAction="always"/>
<item
android:id="@+id/menu_2"
android:orderInCategory="100"
android:title="두번째"
app:showAsAction="always"/>
<item
android:id="@+id/menu_3"
android:orderInCategory="100"
android:title="세번째"
app:showAsAction="always"/>
<item
android:id="@+id/menu_4"
android:orderInCategory="100"
android:title="네번째"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_5"
android:orderInCategory="100"
android:title="다섯번째"
app:showAsAction="ifRoom"/>
</menu>
** MainActivity 액티비티
package com.lec.android.a013_menu;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.LinearLayout;
import android.widget.Toast;
/* 안드로이드의 메뉴
1. Option Menu : '메뉴' 버튼을 눌렀을때 나타나는 메뉴
각각의 '화면' (액티비티) 마다 설정
2. Context Menu : 길게 눌렀을때 나타나는 메뉴
각각의 '뷰' 마다 설정 (화면도 가능)
*/
public class MainActivity extends AppCompatActivity {
boolean blog = false; // 로그인 상태
LinearLayout ll;
// #2
static final int MENUITEM_YELLOW = 1;
static final int MENUITEM_ORANGE = 2;
static final int MENUITEM_CYAN = 3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ll = findViewById(R.id.ll);
} // end onCreate()
// onCreateOptionsMenu()
// '옵션메뉴'버튼이 '처음' 눌러졌을 때 실행되는 메소드
// 메뉴버튼을 눌렀을 때 보여줄 menu 에 대해서 정의
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main1, menu); // menu 리소스(xml)로부터 Menu 생성
Log.d("myapp", "onCreateOptionsMenu - 최초 메뉴키를 눌렀을때 호출됨");
// #2. 심지어 MenuItem 을 동적으로 추가 가능하다!
// add(), MenuItem 리턴
MenuItem item1 = menu.add(1, MENUITEM_YELLOW, 100, "노랑");
MenuItem item2 = menu.add(1, MENUITEM_ORANGE, 100, "오렌지");
MenuItem item3 = menu.add(1, MENUITEM_CYAN, 100, "퍼렁");
return true; // false 리턴하면 메뉴는 보여지지 않는다
}
// onPrepareOptionsMenu()
// '옵션메뉴'가 화면에 보여질때마다 호출되는 메소드
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
Log.d("myapp", "onPrepareOptionsMenu - 옵션메뉴가 화면에 보여질때 마다 호출됨");
// 메뉴가 보여질때마다 '로그인', '로그아웃'이 enable/disable 토글되어 보이기
if(blog) { // 로그인 상태
// getItem(index) index 번째 MenuItem 객체 리턴
menu.getItem(0).setEnabled(true);
menu.getItem(1).setEnabled(false);
} else { // 로그아웃 상태
menu.getItem(0).setEnabled(false);
menu.getItem(1).setEnabled(true);
}
blog = !blog; // 값을 바꿈
return super.onPrepareOptionsMenu(menu); // false 리턴하면 메뉴 보여지지 않음
}
// onOptionsItemSelected()
// '옵션메뉴의 아이템'이 선택(클릭) 되었을때 호출되는 메소드
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
Log.d("myapp", "onOptionsItemSelected - 메뉴 항목을 클릭했을때 호출됨");
showInfo(item);
// #2 특정 MenuItem 에 대한 동작,
// 각 색상이 눌렸을때
switch (item.getItemId()) {
case MENUITEM_YELLOW:
ll.setBackgroundResource(R.color.bgColorYellow);
break;
case MENUITEM_ORANGE:
ll.setBackgroundResource(R.color.bgColorOrange);
break;
case MENUITEM_CYAN:
ll.setBackgroundResource(R.color.bgColorCyan);
break;
}
return super.onOptionsItemSelected(item);
}
public void showInfo(MenuItem item) {
int id = item.getItemId(); // 옵션 메뉴 아이템의 id 값 (정수)
String title = item.getTitle().toString(); // 옵션 메뉴 아이템의 title 값
int groupId = item.getGroupId(); // 옵션 메뉴 아이템의 그룹 id 값 (정수)
int order = item.getOrder(); // 메뉴 아이템의 순번
String msg = "id: " + id + " title: " + title + " groupId: " + groupId + " order: " + order;
Log.d("myapp", msg);
Toast.makeText(this, title + " 메뉴 클릭", Toast.LENGTH_SHORT).show();
}
} // end Activity
[추가] R.color.bgColorYellow, R.color.bgColorOrange, R.color.bgColorCyan와 같은
아래의 사진과 같은 코드를 작성하려면 색상 리소스 추가가 필요하다.
[색상 리소스 추가하기] res > values > colors.xml 의 파일에서 아래의 사진에 표시한 부분을 추가해야 한다...!!
2) Main2Activity 액티비티, activity_main2 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a013_menu">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".Main2Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity" />
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".Main2Activity">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ContextMenu"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<TextView
android:id="@+id/tvCtxMenu"
android:layout_width="match_parent"
android:layout_height="59dp"
android:layout_margin="5dp"
android:background="#CDDC39"
android:text="→여기를 롱클릭 하시면 ContextMenu 등장"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<ImageView
android:id="@+id/ivCtxView"
android:layout_width="match_parent"
android:layout_height="138dp"
app:srcCompat="@mipmap/ic_launcher" />
</LinearLayout>
** 아래의 사진처럼 사진 추가 후...!!
** Main2Activity 액티비티 작성하기
package com.lec.android.a013_menu;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
/* ContextMenu - 뷰 객체를 롱클릭했을 때 나오는 메뉴
PC 에서 마우스 우클릭으로 부가정보들을 제공하는 방법을
스마트폰에서는 롱클릭의 ContextMenu 로 대체하여 구현한다
*/
public class Main2Activity extends AppCompatActivity {
TextView tvCtxMenu;
ImageView ivCtxMenu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
tvCtxMenu = findViewById(R.id.tvCtxMenu);
ivCtxMenu = findViewById(R.id.ivCtxView);
registerForContextMenu(tvCtxMenu); // 뷰 객체(위젯 등...) 에 contextMenu 를 등록함
//unregisterForContextMenu(tvCtxMenu); // 뷰 객체(위젯 등...) 에 등록된 contextMenu 제거
// #2
registerForContextMenu(ivCtxMenu);
} // end onCreate()
// onCreateContextMenu()
// 컨텍스트 메뉴가 생성될 때, 호출되는 콜백 메서드
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
Log.d("myapp", "onCreateContextMenu()");
// 각각의 뷰 (위젯) (View v) 마다 다르게 메뉴 작동하도록 설정 가능
switch (v.getId()) {
case R.id.tvCtxMenu:
menu.setHeaderTitle("색상을 선택하세요");
menu.add(0, 1, 100, "빨강");
menu.add(0, 2, 100, "녹색");
menu.add(0, 3, 100, "파랑");
break;
case R.id.ivCtxView:
menu.setHeaderTitle("얼굴을 선택하세요");
menu.add(1, 1, 100, "아이언맨");
menu.add(1, 2, 100, "캡틴그분");
menu.add(1, 3, 100, "헐크");
break;
}
}
// onContextItemSelected(MenuItem)
// ContextMenu 의 메뉴아이템 항목을 선택(클릭) 했을 때 호출
@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
Log.d("myapp", "onContextItemSelected()");
showInfo(item);
int id = item.getItemId(); // 메뉴아이템의 id값
int groupId = item.getGroupId(); // 메뉴아이템의 그룹아이디 값
switch(groupId){
case 0:
switch (id){
case 1 : // 빨강
tvCtxMenu.setTextColor(Color.RED);
return true;
case 2 : // 녹색
tvCtxMenu.setTextColor(Color.GREEN);
return true;
case 3 : // 파랑
tvCtxMenu.setTextColor(Color.BLUE);
return true;
}
break;
case 1:
switch (id) {
case 1 :
ivCtxMenu.setImageResource(R.drawable.face01);
return true;
case 2:
ivCtxMenu.setImageResource(R.drawable.face02);
return true;
case 3:
ivCtxMenu.setImageResource(R.drawable.face03);
return true;
}
break;
}
return super.onContextItemSelected(item);
}
public void showInfo(MenuItem item){
int id = item.getItemId(); // 옵션메뉴 아이템의 id 값
String title = item.getTitle().toString(); // 옵션 메뉴의 title
int groupId = item.getGroupId(); // 옵션 메뉴의 그룹아이디
int order = item.getOrder();
String msg = "id:" + id + " title:" + title + " groupid:" + groupId + " order:" + order;
Log.d("myapp", msg);
Toast.makeText(getApplicationContext(), title + " 메뉴 클릭", Toast.LENGTH_SHORT).show();
}
} // end Activity
'웹_프론트_백엔드 > JAVA프레임윅기반_풀스택' 카테고리의 다른 글
2020.04.24 (0) | 2020.04.24 |
---|---|
2020.04.23 (0) | 2020.04.23 |
2020.04.21 (0) | 2020.04.21 |
2020.04.20 (0) | 2020.04.20 |
2020.04.17 (0) | 2020.04.17 |