본문 바로가기
교육 정리/안드로이드 앱 제작(Java)

6일차. 데이터 저장과 관리2, 파일, 서비스, 브로드캐스트, 프로바이더, 맵

by Jint 2022. 11. 12.

버츄얼 디바이스 켜기

 

 

1. 데이터 저장과 관리2
Database1_CURD2 프로젝트 만들기

Device File Explorer - data - data 에서 해당 프로젝트의 DB 파일 얻을 수 있다.

- activity_main.xml

<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">

    <EditText
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="40dp"
        android:layout_marginEnd="48dp"
        android:layout_marginRight="48dp"
        android:ems="10"
        android:inputType="text"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <requestFocus />
    </EditText>

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="61dp"
        android:text="이름"
        android:textAppearance="?android:attr/textAppearanceMedium"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="34dp"
        android:layout_marginLeft="34dp"
        android:onClick="insert"
        android:text="추가"
        app:layout_constraintBaseline_toBaselineOf="@+id/button2"
        app:layout_constraintStart_toStartOf="parent" />

    <TextView
        android:id="@+id/textView5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="22dp"
        android:text="전화번호"
        android:textAppearance="?android:attr/textAppearanceMedium"
        app:layout_constraintBottom_toTopOf="@+id/button1"
        app:layout_constraintEnd_toEndOf="@+id/textView1"
        app:layout_constraintStart_toEndOf="@+id/textView1" />

    <EditText
        android:id="@+id/tel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:ems="10"
        android:inputType="number|text"
        app:layout_constraintStart_toStartOf="@+id/name"
        app:layout_constraintTop_toBottomOf="@+id/name" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="11dp"
        android:onClick="search"
        android:text="탐색"
        app:layout_constraintStart_toStartOf="@+id/tel"
        app:layout_constraintTop_toBottomOf="@+id/tel" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginTop="45dp"
        android:layout_marginBottom="48dp"
        android:text="여기에 모든 데이터가 표시됩니다."
        android:padding="10dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button1" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="11dp"
        android:layout_marginEnd="5dp"
        android:layout_marginRight="5dp"
        android:onClick="select_all"
        android:text="전체 조회"
        app:layout_constraintEnd_toEndOf="@+id/tel"
        app:layout_constraintTop_toBottomOf="@+id/tel" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

- MainActivity.java

package com.example.database1_curd2;

import static android.database.sqlite.SQLiteDatabase.openOrCreateDatabase;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

/*
// SQLiteOpenHelper 클래스 생성
   -- SQLiteOpenHelper : 데이터베이스를 감싸고 있는 도우미 클래스이다.
              . SQLiteDatabase getWritableDatabase() - 읽기/쓰기 모드로 데이터베이스를 오픈한다.
              . SQLiteDatabase getReadableDatabase() - 읽기 전용 모드로 데이터베이스를 오픈한다.

   -- SQLiteDatabase
              . void execSQL(String sql) - select문을 제외한 insert, upgrade, delete에 사용된다.
              . Cursor rawQuery(String sql, String[] selectionArgs)
              ---------------------전용 메소드 지원-------------------------------------
              . Cursor query(boolena distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, orderBy, String limit)
                                  - distinct : 만약 각 행이 유일하다며 true이다.
                                  - table : 쿼리 대상이 되는 테이블
                                  - columns : 어떤 컬럼을 반환할 것인지를 결정한다. null은 모든 컬럼을 반환한다는 의미이다.
                                  - selection : SQL WHERE에 해당되는 필터이다. null은 모든 행을 의미한다.
                                  - groupBy : SQL GROUP BY절에  해당하는 필터이다.
                                  - having : SQL Having절에 해당하는 필터이다.
                                  - orderBy : SQL ORDER BY절에 해당하는 필터이다.
                                  - limit : 반환되는 행의 개수를 제한한다.

              . long insert(String table, String nullColumnHack, ContentValues values)
                                  - table : 행을 추가하는 테이블
                                  - nullColumnHack : 만약 null이 아니면 null값을 삽입하는 컬럼의 이름이 된다.
                                  - values : 삽입되는 값

              . int delete(String table, String whereClause, String[] whereArgs)
                                  - 데이터베이스에서 조건에 맞는 행을 삭제

              . int update(String table, ContentValues values, String whereClause, String[] whereArgs)
                                  - 데이터베이스에서 조건에 맞는 행을 갱신한다.
*/

class DBHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "mycontacts.db";
    private static final int DATABASE_VERSION = 2;

    DBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("CREATE TABLE contacts(" +
            " _id INTEGER PRIMARY KEY AUTOINCREMENT," +
            "name TEXT," +
            "tel TEXT)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldversion, int newversion) {
        sqLiteDatabase.execSQL("DROP TABLE IF EXISTS  contacts"); //현재것은 지우고
        onCreate(sqLiteDatabase); //다시 생성한다.
    }

}


public class MainActivity extends AppCompatActivity {

    DBHelper helper;
    SQLiteDatabase db;
    EditText edit_name , edit_tel;
    TextView edit_result;

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

        //1. DBHelper 객체 생성
        helper = new DBHelper(this);
        //2. 쓰기/읽기 모드로 DB 객체를 얻는다.
        try {
            db = helper.getWritableDatabase();
        }catch (SQLiteException e) {
            db = helper.getReadableDatabase();
        }
        edit_name = (EditText) findViewById(R.id.name);
        edit_tel = (EditText) findViewById(R.id.tel);
        edit_result = (TextView) findViewById((R.id.textView));
    }

    //쓰기
    public void insert(View targe) {
        String name = edit_name.getText().toString();
        String tel = edit_tel.getText().toString();
        db.execSQL("INSERT INTO contacts VALUES (null, '"+name+" ',' "+tel+"');");
        Toast.makeText(getApplicationContext(), "성공적으로 추가되었습니다", Toast.LENGTH_SHORT).show();
        edit_name.setText(" ");
        edit_tel.setText(" ");
    }

    //특정검색
    public void search(View target) {
        String name = edit_name.getText().toString();
        Cursor cursor = db.rawQuery("SELECT name, tel FROM contacts WHERE name = ' "+name+" ';", null);
        while(cursor.moveToNext()) {
            String tel = cursor.getString(1);
            edit_tel.setText(tel);
        }
    }

    //전체검색
    public void select_all(View target) {
        Cursor cursor = db.rawQuery("SELECT * FROM contacts", null);
        String s = "id               name            tel \r\n";
        while(cursor.moveToNext()) {
            s += cursor.getString(0)+"          ";
            s += cursor.getString(1)+"             ";
            s += cursor.getString(2)+"          \r\n";
        }
        edit_result.setText(s);
    }

}

Database1_CURD2 프로젝트 결과 화면

 

 

2. 로그인
Database3_Login 프로젝트 만들기

- activity_main.xml

<?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:id="@+id/linearLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="233dp"
        android:layout_height="61dp"
        android:layout_marginTop="28dp"
        android:text="로그인"
        android:textAlignment="center"
        android:textAllCaps="false"
        android:textColor="#3F51B5"
        android:textSize="34sp"
        android:textStyle="italic"
        android:typeface="normal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/id"
        android:layout_width="411dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:ems="10"
        android:hint="이메일 입력"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

    <EditText
        android:id="@+id/pass"
        android:layout_width="411dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:hint="패스워드 입력"
        android:inputType="textPassword"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/id" />

    <Button
        android:id="@+id/button"
        android:layout_width="315dp"
        android:layout_height="48dp"
        android:layout_marginTop="20dp"
        android:backgroundTint="#3F51B5"
        android:onClick="login"
        android:text="로그인"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/pass" />

    <Button
        android:id="@+id/button2"
        android:layout_width="308dp"
        android:layout_height="49dp"
        android:layout_marginStart="52dp"
        android:layout_marginTop="20dp"
        android:backgroundTint="#FF9800"
        android:onClick="enroll"
        android:text="회원등록"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

- MainActivity.java

package com.example.database3_login;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

class DBHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "login.db";
    private static final int DATABASE_VERSION = 1;

    public DBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE user ( _id INTEGER PRIMARY KEY AUTOINCREMENT, id TEXT, pass TEXT);");
    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP T" +
                "" +
                "" +
                "ABLE IF EXISTS user");
        onCreate(db);
    }

}

public class MainActivity extends AppCompatActivity {

    DBHelper helper;
    SQLiteDatabase db;
    EditText edit_id, edit_pass;
    TextView edit_result;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        helper = new DBHelper(this);
        //모드 지정
        try {
            db = helper.getWritableDatabase();
        }catch (SQLiteException ex) {
            db = helper.getReadableDatabase();
        }
        edit_id = (EditText) findViewById(R.id.id);
        edit_pass = (EditText) findViewById(R.id.pass);
        edit_result = (TextView) findViewById(R.id.textView);
    }

    public void enroll(View target) {
        String id = edit_id.getText().toString();
        String pass = edit_pass.getText().toString();
        db.execSQL("INSERT INTO user VALUES (null, '" + id + "', '" + pass+ "');");
        Toast.makeText(getApplicationContext(), "성공적으로 추가되었음", Toast.LENGTH_SHORT).show();
        edit_id.setText("");
        edit_pass.setText("");
    }

    // 로그인버튼을 누르면
    public void login(View target) {
        String id = edit_id.getText().toString();
        String pass = edit_pass.getText().toString();
        Cursor cursor;
        cursor = db.rawQuery("SELECT id, pass FROM user WHERE id='"+ id + "';", null);
        while (cursor.moveToNext()) {
            String pass2 = cursor.getString(1);
            if(pass.equals(pass2))
                Toast.makeText(getApplicationContext(), "로그인 성공입니다.",Toast.LENGTH_SHORT).show();
        }
    }

}

Database3_Login 프로젝트 결과 화면

 

 

3. SimpleCusorAdapter
Database4_SimpleCusorAdapter1 프로젝트 만들기

# Database Adapter : SimpleCusorAdapter
많은 데이터가 저장된 데이터베이스라면 쿼리를 실행하여 그 결과를 화면에 표시하는 시간이 많이 소요된다.
1) SimpleCusorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) : 데이터베이스와 화면을 연결하는 객체.
데이터베이스의 데이터를 읽어서 정해진 레이아웃에 출력해준다.
-> 매개변수 layout : 데이터를 표시할 레이아웃 소스
-> 매개변수 c : 데이터베이스에서 읽어온 커서
-> 매개변수 from : 화면에 표시하고 싶은 데이터베이스에서 읽어온 컬럼들 - 배열로 구현해 놓음
-> 매개변수 to : 각 from의 데이터를 출력할 뷰

- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:text="연락처"
        android:textSize="30sp"
        android:textAlignment="center"/>

    <!--어댑터 연결할 뷰-->
    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="500dp"
        android:padding="10dp"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:backgroundTint="#2196F3"
        android:text="전체검색"
        android:onClick="dbList"/>

</LinearLayout>

 

- list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#D9F6F697"
    android:padding="10dp">

    <TextView
        android:id="@+id/item_name"
        android:layout_width="wrap_content"
        android:layout_height="25dp"/>
    <TextView
        android:id="@+id/item_tel"
        android:layout_width="wrap_content"
        android:layout_height="25dp"/>

</LinearLayout>

 

- MainActivity.java

package com.example.database4_simplecusoradapter1;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

class DBHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "mycontacts.db";
    private static final int DATABASE_VERSION = 2;

    public DBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("CREATE TABLE contacts(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, tel TEXT )");
        for(int i=0 ; i < 10 ; i++) {
            sqLiteDatabase.execSQL("INSERT INTO contacts VALUES (null, '홍길동' , '010-1234-567 " + i + " '); ");
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldversion, int newversion) {
        sqLiteDatabase.execSQL("DROP TABLE IF EXISTS contacts");
        onCreate(sqLiteDatabase);
    }

}


public class MainActivity extends AppCompatActivity {

    DBHelper helper;
    SQLiteDatabase db;
    EditText edit_name,  edit_tel;

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

        helper = new DBHelper(this);
        db = helper.getWritableDatabase(); //쓰기모드
        Cursor cursor = db.rawQuery("SELECT * FROM contacts", null);
        //액티비티가 커서 객체를 관리하도록 함 - 액티비티의 생명주기와 커서의 생명주기를 일치시킨다.
        startManagingCursor(cursor);

        //list.xml을 뷰객체화
        LayoutInflater inflater = this.getLayoutInflater();
        View rowView = inflater.inflate(R.layout.list, null , false);

        //출력할 필드 배열로 지정
        String[] from = {"name", "tel"};

        //TextView tname = (TextView) rowView.findViewById(R.id.item_name);
        //TextView ttel = (TextView) rowView.findViewById(R.id.item_tel);
        //필드를 출력할 뷰
        int[] to = {R.id.item_name, R.id.item_tel};

        //어댑터 생성
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.list, cursor, from, to);
        ListView list = (ListView)findViewById(R.id.list);
        
        //어댑터를 list에 설정
        list.setAdapter(adapter);
    }

}

Database4_SimpleCusorAdapter1 프로젝트 결과 화면

 

 

4. 파일
File1_basic 프로젝트 만들기

# 내부 저장소
1) 내부저장소에 저장되는 file은 해당 앱에서만 접근이 가능하다.
2) 위치 : data/data/패키지명/files/파일
3) 구현방법
-> try ~ catch문 안에서 구현한다.
-> 쓰기 : write(), 읽기 : read()
(1) 파일쓰기
-> 출력스트림 : FileOutPutStream fos = openFileOutput("파일명", mode);
mode 종류로는
MODE_PRIVATE : 새로운 파일을 생성, 같은 이름이 있으면 삭제 후 생성
MODE_APPEND : 기존 파일에 이어서 추가 생성
-> 쓰기 : fos.write(str.getBytes());
-> 닫기 : fos.close();
(2) 파일읽기
-> 입력스트림 : FileInputStream fis = openFileInput("파일명");
-> 바이트 배열 준비 : byte[] buffer = new byte[크기];
-> 바이트 단위로 읽기 : fis.read(buffer);
-> 닫기 : fis.close();
(3) 경로 알아오기
-> 디렉터리 알아오기 : File file = getApplicationContext().getFilesDir();
file.getPath();
-> 파일명까지 읽기 : File file = getApplicationContext().getFilesStreamPath(파일명);
file.getPath();
-> 리스트로 가져오기 : getApplicationContext().filelist().toString();
-> 파일 삭제 : File file = getApplicationContext().deleteFile(파일명);

- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="15dp"
        android:text="내부저장장치의 File에 데이터 저장"
        android:textSize="25sp"
        android:textAlignment="center"
        android:textStyle="italic|bold"/>

    <EditText
        android:id="@+id/data"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="6"
        android:layout_marginTop="10dp"
        android:background="#E7E6E6"
        android:gravity="left|top"
        android:padding="15dp"
        android:singleLine="false"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal"
        android:layout_marginTop="10dp"
        android:gravity="center_horizontal">
        <Button
            android:id="@+id/read"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:text="읽기"/>
        <Button
            android:id="@+id/write"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="저장"/>
    </LinearLayout>

</LinearLayout>

 

- MainActivity.java

package com.example.file1_basic;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOError;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class MainActivity extends AppCompatActivity {

    String FILENAME = "test.txt";
    EditText data;

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

        //위젯을 가져온다.
        data = (EditText) findViewById(R.id.data);
        Button readBtn = (Button) findViewById(R.id.read);
        Button writeBtn = (Button) findViewById(R.id.write);
        //쓰기
        writeBtn.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                try{
                    FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_APPEND); //Context.MODE_PRIVATE
                    fos.write(data.getText().toString().getBytes());
                    fos.close();
                    data.setText(" ");
                    Toast.makeText(getApplicationContext(), "저장되었습니다.", Toast.LENGTH_SHORT).show();
                }catch (IOException e) {}
                return true;
            }
        });
        // 읽기
        readBtn.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                try {
                    FileInputStream fis = openFileInput(FILENAME);
                    byte[] buffer = new byte[1000];
                    fis.read(buffer);
                    // File file = getApplicationContext().getFilesDir();
                    File file = getApplicationContext().getFileStreamPath(FILENAME);
                    data.setText(new String(buffer) + "\n 파일경로: " + file.getPath());
                    fis.close();
                }catch (IOException e) {
                    Toast.makeText(getApplicationContext(), "파일을 읽을수가 없습니다.", Toast.LENGTH_SHORT).show();
                }
                return true;
            }
        });
    }

}

File1_basic 프로젝트 결과 화면

 

 

5. 파일 - 메모
File2_Memo 프로젝트 생성

- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="간단 메모앱"
        android:textSize="30sp"
        android:textStyle="italic|bold"
        android:textAlignment="center"/>

    <EditText
        android:id="@+id/fileName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:hint="파일이름"/>

    <EditText
        android:id="@+id/memo"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="4"
        android:hint="여기에 메모내용을 작성해 주십시요"
        android:gravity="left|top"
        android:padding="15dp"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="horizontal"
        android:layout_weight="1"
        android:gravity="center_horizontal">
        <Button
            android:id="@+id/readBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:text="READ"
            android:backgroundTint="#3F51B5"
            android:textColor="#ffffff"/>
        <Button
            android:id="@+id/writeBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:text="WRITE"
            android:backgroundTint="#009688"
            android:textColor="#ffffff"/>
        <Button
            android:id="@+id/deleteBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="DELETE"
            android:backgroundTint="#FF5722"
            android:textColor="#ffffff"/>
    </LinearLayout>

</LinearLayout>

 

- MainActivity.java

package com.example.file2_memo;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {

    EditText fileName;
    EditText memo;
    String filestr;

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

        fileName = (EditText)findViewById(R.id.fileName);
        memo = (EditText)findViewById(R.id.memo);

        //저장
        Button writeBtn = (Button) findViewById(R.id.writeBtn);
        writeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try{
                    filestr = fileName.getText().toString();

                    //출력스트림을 연다
                    FileOutputStream fos = openFileOutput(filestr,  Context.MODE_PRIVATE);
                    fos.write(memo.getText().toString().getBytes());
                    memo.setText(" ");
                    fos.close();

                    File file =  getApplicationContext().getFileStreamPath( filestr );
                    Toast.makeText(getApplicationContext(), file.getPath() + "파일이 생성되었습니다.", Toast.LENGTH_SHORT).show();
                }catch (IOException e) {}
            }
        });

        //읽기
        fileName.setText(filestr);
        Button readBtn = (Button) findViewById(R.id.readBtn);
        readBtn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                try {
                    FileInputStream fis = openFileInput(filestr);
                    byte[] buffer = new byte[fis.available()];
                    fis.read(buffer);
                    memo.setText(new String(buffer));
                    fis.close();
                } catch (IOException e) {
                }
            }
        });

        //삭제
        Button deleteButton = (Button) findViewById(R.id.deleteBtn);
        deleteButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if(filestr != null) {
                    deleteFile(filestr);
                    memo.setText(" ");
                    fileName.setText(" ");
                }
                //이제부터는  파일리스트를 출력해보자 -        String[]    getApplicationContext().fileList()   활용
                String filelist ="";
                String[] file = getApplicationContext().fileList();
                for (int i=0; i<file.length; i++){
                    filelist += file[i].toString()+",  ";
                }
                if(filelist != null && filelist != ""){
                    Toast.makeText(getApplicationContext(), "남아있는 파일은 : " + filelist, Toast.LENGTH_LONG).show();
                }else {
                    Toast.makeText(getApplicationContext(), "남아있는 파일이 없습니다.", Toast.LENGTH_LONG).show();
                }
            }
        });
    }

}

File2_Memo 프로젝트 결과 화면

 

 

6. 서비스 - 시작타입 서비스
Service1_startService1 프로젝트 만들기

res/raw 폴더 만들고 old_pop.mp3 파일 넣기

- AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.service1_startservice1">

    <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/Theme.Service1_startService1">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--다른 컴포넌트들이 이 서비스를 사용할 수 있도록 하려면 이렇게 선언해야하고. 만약 애플리케이션 안에서만 하려면 선언안해도된다.-->
        <service
            android:name=".MusicService"
            android:enabled="true"/>
    </application>

</manifest>

 

- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="top|center"
    android:orientation="vertical"
    android:padding="10dp">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="20dp"
        android:text="음악 서비스 테스트"
        android:textSize="30sp"/>

    <Button
        android:id="@+id/start"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:backgroundTint="#3F51B5"
        android:textColor="#ffffff"
        android:text="시작">
    </Button>

    <Button
        android:id="@+id/stop"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:backgroundTint="#FF5722"
        android:textColor="#ffffff"
        android:text="중지">
    </Button>

</LinearLayout>

 

- MainActivity.java

package com.example.service1_startservice1;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
/*
    서비스(Service)
        . 사용자 인터페이스 없이(화면없이) 백그라운드에서 실행되는 동작을 구현한다.

        . 특징
           - 사용자 인터페이스를 가지지 않는다.
           - 일반적으로 애플리케이션에 의해 시작된다.
           - 한번 시작된 서비스는 사용자가 다른 애플리케이션으로 이동하더라도 계속 백그라운드에서 실행된다.

            . 사용자 인터페이스 없이 백그라운드에서 실행되게 하는 메커니즘이다.
            . 애플리케이션에 의해 시작되고, 한번 시작된 서비스는 애플리케이션이 이동되더라도 계속 백그라운드에서 실행된다.
            . 활용용도
                  -  배경 음악재생, 파일 입출력, 네트워크 트랜젝션, 콘텐트 제공자와  통신 등에 활용된다.
            . 종류
                1)  시작타입 서비스  :  서비스가 실행되면  서비스 시작을 담당했던  컴포넌트가 소멸되더라도  서비스는 백그라운드에서 실행된다.
                                       중지하는 방법은....  stopService()호출   또는   서비스 스스로   stopSelf() 사용 자체적으로 중지처리  두가지가 있다.

                                                    (MainActivity)                                              (Service)
                            -  startService( intent ) 호출   :  서비스 시작    --- > onStartComman()에서 서비스를 시작시킨다.
                            -  stopService( intent )  호출  :   서비스 종료    --- > 여기에 대응되는 콜백메소드가 없다.
                                                                                     onDestory()에서   실행하고 있는 서비스를 중지처리 하면된다.

                2)  연결타입 서비스: 클라이언트 - 서버 모델에서  서버의 역할을 하는 서비스이다.
                                                 컴포넌트들로 부터 요청을 받고  결과를 보낼수 있다.
                                                 애플리케이션의 컴포넌트들이  연결되어 있는 한, 해당 작업을 수행한다.

                        - bindService() 호출 : 서비스 시작
                        - unbindService()로 연결해체 : 서비스 종료

          .  구현방법
                    1) 사용자 인터페이스는 필요없다 -  xml, view 필요없다.
                    2) Service를 상속받은  클래스로 서비스를 구현한다. 이때 클래스는 public이어야 한다.
                        .  Service의 onBind() 추상메소드 구현
                        .  onCreate() 재정의 - 어떤 서비스를 할것인지 서비스 생성
                        .  onStartCommand() 재정의 - 서비스객체. start() - 서비스시작
                        .  onDestroy() 재정의 - 서비스객체.stop() - 서비스종료
                    2) MainActivity.java에서 startService(inten)로 서비스 매니페스트에 서비스 등록
                        .  startService( new Intent(this, 서비스클래스.class)
                        .  stopService( new Intent(this, 서비스클래스.class)
                    3) 매니페스트에 서비스 등록
                        <application>안에 <serviec> 등록
                -  다른 컴포넌트가 이 액티비티
*/

public class MainActivity extends AppCompatActivity implements View.OnClickListener {//View.OnClickListener 구현

    Button start, stop;

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

        start = (Button)findViewById(R.id.start);
        stop = (Button)findViewById(R.id.stop);

        //View.OnClickListen 인터페이스의 메소드
        start.setOnClickListener(this);
        stop.setOnClickListener(this);
    }

    //View.OnClickListen 인터페이스의 메소드 추상메소드
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.start:
                startService(new Intent(this, MusicService.class)); //사용자 인터페이스 없이 넘어간다. manifest에 등록 안해도 된다.
                break;
            case R.id.stop:
                stopService(new  Intent(this, MusicService.class));
                break;
        }
    }

}

 

- MusicService.java

package com.example.service1_startservice1;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.widget.Toast;

//public 클래스이어야 한다.
public class MusicService extends Service {

    MediaPlayer player;

    //Service가 가지고 있는 추상메소드 - 오버라이딩 꼭 해둬야 한다.
    //클라이언트가 데이터를 보내고 서비스 결과를 받아야 하는 연결서비스에서 구현한다.
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    //아래 필요한 Life Cycle 메소드들을 꺼내서 오버라이딩해서 구현한다.
    @Override
    public void onCreate() {//준비
        super.onCreate();
        player = MediaPlayer.create(this, R.raw.old_pop);
        player.setLooping(false); //무한반복 - true
    }

    //서비스 시작 - 서비스.start()
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        player.start();  //시작
        Toast.makeText(getApplicationContext(), "서비스가 시작되었습니다.", Toast.LENGTH_SHORT).show();
        return super.onStartCommand(intent, flags, startId);
    }

    //서비스 종료 - 서비스.stop()
    @Override
    public void onDestroy() {
        super.onDestroy();
        player.stop(); // 종료
        Toast.makeText(getApplicationContext(), "서비스가 종료되었습니다.", Toast.LENGTH_SHORT).show();
    }

    //이제  AndroidManifest.xml의 <application> 안에 <service>를 등록한다.
    //물론 다른 액티비티에서 이 액티비를 실행하겠다고 한다면 인텐트필터를 등록해둘 수 있다.

}

Service1_startService1 프로젝트 결과 화면

 

 

7. 서비스 - 연결타입 서비스
Service2_bindSevice1 프로젝트 만들기

- AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.service2_bindsevice1">

    <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/Theme.Service2_bindSevice1">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".MyService" android:enabled="true"/>
    </application>

</manifest>

 

- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:text="연결서비스계산기"
        android:textSize="30sp"
        android:textStyle="bold|italic"
        android:gravity="center_horizontal"/>

    <EditText
        android:id="@+id/editNum1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:gravity="center_horizontal"
        android:inputType="number"/>

    <EditText
        android:id="@+id/editNum2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:inputType="number"/>

    <Button
        android:id="@+id/btnCalc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:backgroundTint="#2196F3"
        android:layout_marginTop="50dp"
        android:onClick="mOnClick"
        android:text="두 수의 곱 계산"
        android:textColor="#F8F5F5"/>

</LinearLayout>

 

- MainActivity.java

package com.example.service2_bindsevice1;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

/*
    연결타입 서비스
            ; 컴포넌트들로 부터 서비스 요청을 받고 그 결과를 보낼수 있다
              그런 의미에서  클라이언트와 서버모델과 유사하며 서비스가 서버모델역할을 하는 것이다.

       (구현방법)
        1) MyService.java

               ① Binder를 상속받은  LocalService 내부 클래스를  구현해서  MyService의 객체를 담아 놓는다.
               ② onBind메소드에서    IBider타입의 객체를 만들어서  return해 놓는다.
                         public IBinder onBind(Intent intent) {
                                // LocalServce객체를  IBinder타입으로 리턴해 놓는다.
                        return  localBinder;
                ③ 서비스를 정의해 놓은  메소드를 구현해 놓는다.

         2)  MainActivity.java
                ① ServiceConnection인터페이스객체를 생성한다.  이때  두개의 추상메소드를 구현한다.
                    - onServiceConnected(ComponentName componentName, IBinder iBinder)
                           // 여기에서  매개변수로 받은  iBinder속에서  MyService객체를  가져온다.
                                >>  getService()를 호출해서   서비스를 연결한다.
                                >> 이 객체에서  서비스메소드를 호출해서  아래 이벤트로 처리하려고 하는 것이다.
                                >> 연결된것에 대해  flag 값을  둬서   true로  설정해 둔다.
                    - onServiceDisconnected(ComponentName componentName)
                               >> 연결해제 하면   flag값을  둬서  false로 설정해 둔다.

          3)  서비스를 연결한다.
                @Override
                protected void onStart() {
                    Intent intent = new Intent(this,MyService.class);
                    bindService(intent,  mCon, Context.BIND_AUTO_CREATE);  // 인텐트, 서비스객체, 바인드자동생성모드
                }
         4)  서비스 연결해제
                @Override
                protected void onStop() {
                    if(mBound){
                        unbindService(mCon);   // 서비스
                        mBound=false;
                    }
                }
         5)  서비스처리
*/

public class MainActivity extends AppCompatActivity {

    MyService mService;
    boolean mBound = false; //서비스와 연결여부 체크용 변수 : 연결되면 true, 연결안되면 false

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

    //1. ★ ServiceConnetcion객체생성 - 2개의 추상메소드 구현
    //1) onServiceConnected(컴포넌트, IBinder)로 IBinder가 MyService onBind()의 return된 IBinder로 받아와진다.
    //2) onServiceDisconnected(컴포넌트)
    ServiceConnection mCon = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {//iBinder라는 틀의 객체를 가져오는데.. 이것이 MyService객체가 들어있는 것이다.
            //3. 바인더 객체의 메서드  호출 : 서비스 객체얻기 --- MyService에서 만들어 놓은 LocalBinder클래스객체와 그속의 getService()메소드
            mService = ((MyService.LocalBinder)iBinder).getService(); //MyService클래스속의 내부클래스 LocalBinder타입의  iBinder(매개변수로 받은것)속의  getService()호출 >> MyService객체 가져온다
            mBound = true; //서비스와 연결되면 true
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBound = false; //서비스와 연결안되면 false
        }

    };

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, MyService.class);
        //2.서비스와 연결하기.
        bindService(intent, mCon, Context.BIND_AUTO_CREATE); //(인텐트, 서비스객체, 바인드자동생성모드)
    }

    @Override
    protected void onStop() {
        super.onStop();
        if(mBound) {
            unbindService(mCon); //5. 서비스와 연결해제
            mBound=false;
        }
    }

    //이벤트 메소드
    public void mOnClick(View view) {
        switch(view.getId()) {
            case R.id.btnCalc :
                if(mBound) {//해야할 서비스가 있다면
                    EditText editNum1 = (EditText)findViewById(R.id.editNum1);
                    EditText editNum2 = (EditText)findViewById(R.id.editNum2);
                    if(editNum1.length() > 0 && editNum2.length() > 0) {
                        int num1 = Integer.parseInt(editNum1.getText().toString());
                        int num2 = Integer.parseInt(editNum2.getText().toString());
                        //4. 서비스 객체를 통해 서비스 메서드 호출
                        int result = mService.CalcNum(num1, num2);
                        Toast.makeText(this,"계산결과 = "+result,Toast.LENGTH_LONG).show();
                    }
                }
                break;
        }
    }

}

//실행 :  두개의 숫자를 입력하고  두 수의 곱계산 버튼을 클릭하면 서비스와 통신하여 계산하고 그 결과를 토스트 메시지로 표시한다.

 

- MyService.java

package com.example.service2_bindsevice1;

/*
    바인더 클래스를 만들어서  onBind()에서   객체생성후 반환한다.
*/

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

// 1. [필수] Service추상클래스를 상속받는다.
public class MyService extends Service {

    public MyService() {}

    @Override
    public IBinder onBind(Intent intent) {
        //3. [필수] 아래 내부클래스로 구현해놓은 LocalBinder의 객체를 생성해서 IBinder타입으로 반환한다.
        //- LocalBinder속에는 MyService객체를 담고 있다.
        LocalBinder localBinder = new LocalBinder();
        return localBinder;
    }

    //2. [필수] 바인더 클래스 정의: 현재 서비스 객체 리턴 *************************************
    public class LocalBinder extends Binder {//Binder상속 - IBider타입에 MyService를 묶기위해 상속받아 구현한다.

        //현재 서비스 객체 리턴
        public MyService getService() {
            return MyService.this; //MyService 즉 이 클래스 객체를 호출한 곳으로 반환한다.
        }

    }
   // *******************************************************************************************

    //4. [필수] 서비스(두수를 받아서 곱해주는 서비스) 해야할 일을 정의한 메서드 추가
    public int CalcNum(int n, int m){
        return n*m;
    }

}

Service2_bindSevice1 프로젝트 결과 화면

 

 

8. 브로드캐스트 - connectedPower
BroadcastReceiver1_connectedPower 프로젝트 만들기

https://developer.android.com/reference/ - 안드로이드 API 개발자가이드 참조

# 방송수신자(Broadcast Receiver)
: 안드로이드에서 발생하는 이벤트를 받겠다고 등록해 놓고 수신받는다.
1) 종류
-> 문자수신 : Telephony.Sms.SMS_RECEIVED_ACTION
-> 충전기연결 : ACTION_POWER_CONNECTED
-> 외부장치연결 : ACTION_MEDIA_MOUNTED
등등...
2) 구현
-> BroadcastReceiver 객체 생성 : onReceive() {방송을 받았을 때 해야할 코드}
-> 인텐트 필터 생성 : IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_POWER_CONNECTED); 등등 필요한 것들
-> 등록 : registerReceiver(브로드캐스트 객체, 인텐트필터)
-> 등록해제 : unregisterReceiver(브로드캐스트 객체)

- MainActivity.java

package com.example.broadcastreceiver1_connectedpower;

import static android.content.Intent.ACTION_POWER_CONNECTED;

import androidx.appcompat.app.AppCompatActivity;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private BroadcastReceiver chargerReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //1. BroadcastReceiver인터페이스 객체생성 (구현) - onReceive()
        chargerReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Toast.makeText(getApplicationContext(), "전원이 연결되었습니다.", Toast.LENGTH_SHORT).show();
            }
        };
        //2. registerReceiver(브로드캐스트 객체, 인텐트필터) 구현 - 이런 이벤트액션을 받겠다고 등록
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_POWER_CONNECTED);
        registerReceiver(chargerReceiver, filter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //3. unregisterReceiver(브로드캐스트 객체) - 등록된 수신허용이벤트 해제
        unregisterReceiver(chargerReceiver);
    }

}

BroadcastReceiver1_connectedPower 프로젝트 결과 화면

 

 

9. 브로드캐스트 - SMS
BroadcastReceiver2_SMS 프로젝트 만들기

# 구현방법
1) BroadcastReceiver 객체생성
2) onReceive() 추상메서드 구현 - 방송을 받았을 때 해야할 코드
3) onCreate() 메서드에서 동적으로 권한 부여 처리
4) onResume()
-> 인텐트 필터 생성
-> 필터에 액션설정
-> 방송수신연결(등록) - registerReceiver(리시버객체, 인텐트필터)
5) onPause() 메서드에서 방송 수신 등록 해제 - unregisterReceiver(리시버)

- AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcastreceiver2_sms">

    <!--SMS받고 읽을 수 있는 권한부여 - 여기에 설정하면 앱이 시작되기 전에 부여된다.-->
    <uses-permission android:name="android.permission.READ_SMS"/>
    <uses-permission android:name="android.permission.RECEIVE_SMS"/>

    <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/Theme.BroadcastReceiver2_SMS">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:text="문자를 수신하는 앱입니다."
        android:textSize="25sp"
        android:textColor="#3F51B5"
        android:textStyle="bold"
        android:layout_gravity="center_horizontal"/>

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="100dp"
        android:layout_marginTop="100dp"
        android:hint="문자 메시지가 출력됩니다"
        android:textSize="25sp"
        android:textStyle="italic|bold"
        android:textColor="#E91E63"
        android:layout_gravity="center_horizontal"
        android:gravity="left|top"/>

</LinearLayout>

 

- MainActivity.java

package com.example.broadcastreceiver2_sms;

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.provider.Telephony;
import android.telephony.SmsMessage;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class MainActivity extends AppCompatActivity {

    private int MY_PERMISSIONS_REQUEST_SMS_RECEIVE = 10; //Request Code
    TextView sms;

    //1. 방송수신자 객체생성
    BroadcastReceiver receiver = new BroadcastReceiver() {

        //onReceive 구현 - 방송 수신시 해야할 코드
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent.getAction().equals(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)) {
                String smsSender = "홍길동님";
                String smsBody = " ";
                for(SmsMessage smsMessage : Telephony.Sms.Intents.getMessagesFromIntent(intent)) {
                    smsBody += smsMessage.getMessageBody();
                }
                //Toast.makeText(getApplicationContext(), smsBody, Toast.LENGTH_SHORT).show();
                sms.setText(smsSender+":   \n "+smsBody);
            }
        }

    };

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

        sms = (TextView)findViewById(R.id.tv);
        //앱에 권한이 설정되어 있는지 체크 - 매니페스트에 해놨지만, 앱이 실행되기전에 다시 허락을 맡는것이 필요하다. 그래서 동적으로 권한부여한다.
        //1) 권한들을 배열로 설정
        String[] permission = new String[]{
                Manifest.permission.READ_SMS,
                Manifest.permission.RECEIVE_SMS,
                Manifest.permission.INTERNET,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION
        };
        //2) 배열 체크 - 승인 : int PERMINSSION_GRANTED, 미승인 : int PackageManager.PERMISSION_DENIED
        for(int i = 0; i < permission.length; i++) {
            //권한 체크 - (checkSelfPermission(MainActivity.this, String permission[i]);
            int permChk = ContextCompat.checkSelfPermission(MainActivity.this, permission[i]);
            Toast.makeText(getApplicationContext(), permission[i] + "권한승인이 안되어 있습니다. 승인처리합니다.", Toast.LENGTH_SHORT).show();
            //권한 요청 - requestPermissions(Context context, permission, RequestCode)
            if(permChk != PackageManager.PERMISSION_GRANTED) {//PackageManager.PERMISSION_DENIED
                ActivityCompat.requestPermissions(MainActivity.this, permission, MY_PERMISSIONS_REQUEST_SMS_RECEIVE);
            }
        }
    }

    //앱이 실행되는 동안에만 방송수신을 하고 싶을때 : onResume()에서 연결 ~ onPause()에서 해제한다.
    public void onResume() {
        super.onResume();
        //1) 인텐트 필터
        IntentFilter filter = new IntentFilter();
        //2) 필요한 액션을 추가한다.
        filter.addAction("android.provider.Telephony.SMS_RECEIVED");
        //3) 등록한다. - 연결
        registerReceiver(receiver, filter);
    }

    public void onPause() {
        super.onPause();
        //4) 해제한다.
        unregisterReceiver(receiver);
    }

}

BroadcastReceiver2_SMS 프로젝트 결과 화면

 

 

10. 브로드캐스트 - SD카드, 배터리
BroadcastReceiver3_SdcardBattery 프로젝트 만들기

- AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcastreceiver3_sdcardbattery">

    <!--권한승인-->
    <uses-permission android:name="android.permission.BATTERY_STATS"/>
    <uses-permission android:name="android.permission.WRITE_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:theme="@style/Theme.BroadcastReceiver3_SdcardBattery">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="밧데리와 외장메모리 이벤트 체크"
        android:layout_marginTop="50dp"
        android:textStyle="bold"
        android:textSize="25sp"
        android:textColor="#3F51B5"
        android:gravity="center_horizontal"/>

    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="150sp"
        android:hint="발생 액션과  밧데리레벨이 출력됩니다. "
        android:textSize="20sp"/>

</LinearLayout>

 

- MainActivity.java

package com.example.broadcastreceiver3_sdcardbattery;

import androidx.appcompat.app.AppCompatActivity;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    TextView textfield;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textfield = (TextView) findViewById(R.id.textview);
    }

    @Override
    public void onResume() {
        super.onResume();
        // 방송받을 이벤트들  필터에 추가
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
        filter.addAction(Intent.ACTION_BATTERY_LOW);
        filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
        filter.addAction(Intent.ACTION_POWER_CONNECTED);
        filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
        filter.addAction(Intent.ACTION_MEDIA_REMOVED);
        registerReceiver(receiver, filter);
    }

    @Override
    public void onPause() {
        super.onPause();
        unregisterReceiver(receiver);
    }

    BroadcastReceiver receiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Toast.makeText(context, action, Toast.LENGTH_LONG).show();
            textfield.setText(action);
            if(action.equals(Intent.ACTION_BATTERY_CHANGED)) {
                int maxvalue=intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
                int value = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
                int level = value * 100 / maxvalue;
                textfield.setText(action + "\n현재 배터리 레벨="+ level);
            }else if(action.equals(Intent.ACTION_BATTERY_LOW)) {//밧데리가 부족하다면
                textfield.setText(action + "\n배터리 부족");
            }else if(action.equals(Intent.ACTION_MEDIA_MOUNTED)) {//SD카드를 장착했다면 (외부저장장치)
                textfield.setText(action + "\nSD카드 장착");
            }else if(action.equals(Intent.ACTION_MEDIA_REMOVED)) {//SD카드를 제거했다면 //오타!
                textfield.setText(action + "\nSD카드 장착 해제");
            }
        }

    };

}

BroadcastReceiver3_SdcardBattery 프로젝트 결과 화면

 

 

11. 프로바이더 - 컨텐츠
Provider1_picture 프로젝트 만들기

애뮬레이터 핸드폰으로 찍은 사진 경로
storage/emulated/0/Pictures/사진파일

# 컨텐츠 제공자(Content Provider)
: 다른 애플리케이션에 데이터를 공급하는 역할을 하는 컴포넌트이다.
: 안드로이드에서는 저장된 데이터를 관계형 데이터베이스의 테이블 형태로 외부 애플리케이션에 제공한다.
: 데이터 계층과 애플리케이션 계층을 분리하는 역할을 한다.
(앱)                    (데이터)
                        <컨텐츠 제공자> ----- SQLite, File, XML 등
액티비티 -- (테이블) -- <insert>
                        <update>
                        <delete>
                        <query>
1. 원하는 컨텐츠를 찾기
-> getContentResolver() 호출 - Context 객체에 있는 ContextResolver 객체 - CRUD 기능을 제공
-> query(Uri, projection, selection, sortOrder)
Uri (FROM 테이블명 역할)
: 컨텐츠 제공자의 데이터 식별 Uri
: 문자열로 텍스트, 비디오, 사운드클립, 동영상같은 컨텐츠를 식별하는 규격이다.
: 안드로이드가 제공하는 Uri 객체 상수들
사용자 사전제공자 - UserDictionary.Words.CONTENT_URI
이미지 제공자 - MediaStore.Image.Media.EXTERNAL_CONTENT_URI
비디오 제공자 - MediaStore.Video.Media.EXTERNAL_CONTENT_URI
오디오 제공자 - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
등등...
projection : 반환되는 레코드에 포함된 필드의 이름 (FROM 앞 컬럼, 컬럼, 컬럼 역할)
String[] projection = new String[] {필드명(컬럼), 필드명(컬럼), ...}
selection : 행을 선택하는 조건 (WHERE절 역할)
sortOrder : 레코드 집합에서 행이 나타나는 순서를 지정 (ORDER BY 역할)
2. 제공자로부터 데이터 읽기
1) 권한등록(Manifest)
최근에는 자바 코드로 동적으로 권한을 요청하도록 하고 있다.
ActivityCompat.requestPermission(this, new String[]) {Manifest.permission.권한,,,}, 요청코드)
2) 쿼리작성 - 커서객체 반환
Cursor cursor = getContentResolver().query(Uri, projection, selection, sortOrder);
컬럼인덱스 얻기 : int index = cursor.getColumnIndex(컨텐츠 제공자)
인덱스로 데이터 읽기
: while(cursor.moveToNext()) {
    data1 = cursor.getString(index)
    data2 = cursor.getInt(index)

활용

- AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.provider1_picture">

    <uses-permission android:name="android.permission.WRITE_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:theme="@style/Theme.Provider1_picture">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

- activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:padding="10dp">

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp">

        <Button
            android:id="@+id/previous"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="5dp"
            android:layout_weight="4"
            android:backgroundTint="#FF9800"
            android:onClick="displayFirstImage"
            android:text="previous"></Button>

        <Button
            android:id="@+id/next"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="4"
            android:backgroundTint="#009688"
            android:onClick="displaySecondImage"
            android:text="next"></Button>
    </LinearLayout>

    <ImageView android:id="@+id/picture"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="10dp">
    </ImageView>

</LinearLayout>

 

- MainActivity.java

package com.example.provider1_picture;

import android.Manifest;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import java.io.File;



public class MainActivity extends AppCompatActivity {

    private Cursor cursor;
    ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.picture);
        //동적으로 권한요청
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
    }

    public void displayFirstImage(View v) {
        Toast.makeText(getApplicationContext(), "displayFirstImage()", Toast.LENGTH_LONG).show();
        try {
            String[] projection = new String[] {
                MediaStore.Images.ImageColumns._ID,
                MediaStore.Images.ImageColumns.DATA
            };

            cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    projection,
                    null,
                    null,
                    null);

            int size = cursor.getCount();
            if(size == 0) {
                Toast.makeText(getApplicationContext(), "장치에 이미지가 없음!", Toast.LENGTH_LONG).show();
            }else {
                if(cursor.moveToFirst()) {
                    String imageLocation = cursor.getString(1); //두번째의 MediaStore.Images.ImageColumns.DATA
                    Toast.makeText(getApplicationContext(), imageLocation, Toast.LENGTH_LONG).show();
                    File imageFile = new File(imageLocation);
                    if(imageFile.exists()) {
                        Bitmap bm = BitmapFactory.decodeFile(imageLocation);
                        imageView.setImageBitmap(bm);
                    }
                }
            }
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

    public void displaySecondImage(View v) {
        Toast.makeText(getApplicationContext(), "displayFirstImage()", Toast.LENGTH_LONG).show();
        try {
            String[] projection = new String[] {
                    MediaStore.Images.ImageColumns._ID,
                    MediaStore.Images.ImageColumns.DATA,
                    MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
                    MediaStore.Images.ImageColumns.DATE_TAKEN,
                    MediaStore.Images.ImageColumns.MIME_TYPE
            };
            cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    projection,
                    null,
                    null,
                    null);
            int size = cursor.getCount();
            if(size == 0) {
                Toast.makeText(getApplicationContext(), "장치에 이미지가 없음!", Toast.LENGTH_LONG).show();
            }else {
                if (cursor.moveToLast()) {
                    String imageLocation = cursor.getString(1);
                    Toast.makeText(getApplicationContext(), imageLocation, Toast.LENGTH_LONG).show();
                    //파일 생성
                    File imageFile = new File(imageLocation);
                    if(imageFile.exists()) {
                        //비트맵 출력
                        Bitmap bm = BitmapFactory.decodeFile(imageLocation);
                        imageView.setImageBitmap(bm);
                    }
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Provider1_picture 프로젝트 결과 화면

 

 

12. 프로바이더 - 비디오 목록 뷰
Provider2_VideoListView 프로젝트 만들기

- AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.provider2_videolistview">

    <!-- 권한승인-->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_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:theme="@style/Theme.Provider2_VideoListView">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp"
    android:gravity="center_horizontal">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:text="All Video Files"
        android:textColor="#3F51B5"
        android:textSize="34sp"
        android:textStyle="italic"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:backgroundTint="#FF9800"
        android:layout_marginTop="50dp"
        android:onClick="onClick"
        android:text="모든 비디오 제목 표시" />

    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="50dp"/>

</LinearLayout>

 

- MainActivity.java

package com.example.provider2_videolistview;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    ArrayList<String> list ;
    ListView listview ;

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

        list = new ArrayList<>();
        listview = (ListView) findViewById(R.id.listview);
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
    }

    public void onClick(View v) {
        ContentResolver resolver = getContentResolver();
        Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
        Cursor cursor = resolver.query(uri, null, null, null, null);
        if(cursor != null && cursor.moveToFirst()) {
            do{
                int index = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);
                list.add(cursor.getString(index));
            } while (cursor.moveToNext());
        }
        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, android.R.id.text1, list);
        listview.setAdapter(adapter);
    }

}

Provider2_VideoListView 프로젝트 결과 화면

 

 

13. 맵 - getLocation
Map1_getLocation 프로젝트 만들기

- AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.map1_getlocation">

    <!--권한승인-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

    <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/Theme.Map1_getLocation">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:text="내가있는 위치정보"
        android:textSize="25sp"
        android:textStyle="bold|italic"
        android:textColor="#3F51B5"
        android:gravity="center_horizontal"/>

    <TextView
        android:id="@+id/status"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:padding="30dp"
        android:layout_marginTop="50dp"
        android:includeFontPadding="true"
        android:text="아직 수신되지 않았음.기다려주세요..."
        android:textSize="15sp"
        android:textStyle="italic"
        android:typeface="serif"/>

</LinearLayout>

 

- MainActivity.java

package com.example.map1_getlocation;

// 소스만 입력하고 Alt+Enter를 눌러서 import 문장을 자동으로 생성한다.

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

/*
   사용자 위치가져오기
    0. 매니페스트에 권한등록
    1. 동적으로 권한 부여
    2. LocationManager 객체생성 : getSystemService( Context.LOCATION_SERVICE )
    3. LocationListener  인터페이스 객체생성
    4. 위치가 변하면 자동으로 호출되는 콜백메소드 : 변했을때 할 일을 코드구현 : onLocationChanged(Location location)
    5. 위치를 업데이트받기위해 리스너를 LocationManager에게 등록:
       >> locationManager.requestLocationUpdates( LocationManager . GPS_PROVIDER, 0 , 0 , locationListener )
          . GPS콘텐트제공자 : LocationManager
          .  0 : 최소시간간격 (밀리초)
          .  0:  최소거리간격 (미터)
          . locationListener : 리스너
*/

public class MainActivity extends AppCompatActivity {

    //RequestCode 값
    private int MY_PERMISSIONS_REQUEST_LOCATION = 10;
    TextView status;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        status = (TextView) findViewById(R.id.status);
        //1. 동적으로 권한 부여
        //권한부여
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION);
        //2. LocationManager 객체생성 : getSystemService( Context.LOCATION_SERVICE )
        LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        //3. LocationListener 인터페이스 객체생성
        LocationListener locationListener = new LocationListener() {
            //4. 위치가 변하면 자동으로 호출되는 콜백메소드 : 변했을때 할 일을 코드구현
            public void onLocationChanged(Location location) {
                status.setText("위도; " + location.getLatitude() + "\n경도:"
                        + location.getLongitude() + "\n고도:"
                        + location.getAltitude());
            }
            //나머지 콜백메소드 그냥둔다.
            public void onStatusChanged(String provider, int status, Bundle extras) {}
            public void onProviderEnabled(String provider) {}
            public void onProviderDisabled(String provider) {}
        };

        //여기서 다시한번 권한체크 - 안되어 있으면 경고 토스트
        if(ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
        && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(MainActivity.this, "First enable LOCATION ACCESS in settings.", Toast.LENGTH_LONG).show();
            return;
        }

        //5. 위치를 업데이트 받기위해 리스너를 LocationManager에게 등록
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);

    }

}

Map1_getLocation 프로젝트 결과 화면

댓글