본문 바로가기
Android

Custom ListView + DB연동하기 ( SQLite )

by noddu 2021. 4. 3.
728x90
반응형

 

바로가기 버튼을 누르면 해당url로 이동, 추가하기 누르면 url추가하는 앱 만들기

 

 

 

 

 

 

에뮬레이터 재실행했을때 데이터 안날라가게 하는 방법

1. 핸드폰 내장 DataVase에 저장하기 -> SQLite -> App삭제시 사라짐

2. 서버( JSP/Servlet, DAO )를 통해 Database에 저장하기 -> Volley ( 라이브러리 ) -> 인터넷 연결 필요

3. 실시간으로 데이터 주고받기 -> Google FireBase Realtime DataBase 

 

 

 

 

 

DataBase에 연결할 class 하나 생성 - DBManager.java

 

 

ListView 항목에 클릭리스너 달아줄때 ( setOnitemClickListener 할때 )

Cutom을 했을 경우 클릭리스너가 동작하지 않는다

-> ListView의 옵션과 항목뷰의 옵션을 수정해야함

     1. ListView의 옵션 중 clickable 속성을 true로 변경 ( main.xml)

     2. 항목 뷰를 전부 선택해서 focusable, focusbleInTouchMode를 false로

 

 

 

 

●MainActivity

public class MainActivity extends AppCompatActivity {
    ArrayList<directVO> data = new ArrayList<>();
    ListView lv;
    Button btn_add;
    final int ADD = 1;

    DBManager manager;

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

        manager = new DBManager(getApplicationContext());   // DB 파일생성,테이블생성,connection 알아서 해줌

        lv = findViewById(R.id.listview);
        btn_add = findViewById(R.id.btn_add);

        data.add(new directVO("네이버","https://www.naver.com"));
        data.add(new directVO("다음","https://www.daum.net"));
        data.add(new directVO("Youtube","https://www.youtube.com"));
        data.add(new directVO("스마트인재개발원","https://www.smhrd.or.kr"));

        DirectAdapter adapter = new DirectAdapter(getApplicationContext(),R.layout.directlist, data);
        lv.setAdapter(adapter);

        btn_add.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, AddActivity.class);
                startActivityForResult(intent, ADD);
            }
        });

        Cursor cursor = manager.getAllData();
        // Cursor 란 JDBC 에서 ResultSet과 같은 역할
        // 데이터(행) 을 가리키고 있는 화살표

        while(cursor.moveToNext()){
            // 커서를 아래칸으로 옮기는동안 데이터있으면 true, 없으면 false
            // 데이터가 존재하는 동안 반복하기 위해 while 문 사용

            // 해당 행의 데이터 가져와서 arrayList 에 축적하기
            String title = cursor.getString(0);
            String address = cursor.getString(1);

            data.add(new directVO(title, address));
        }

        adapter.notifyDataSetChanged();

        // 리스트뷰 항목을 터치했을 때 해당항목 지워버리기
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // 이전 예제에서는 position (위치)로 해당 데이터를 지웠음 (ArrayList 에서)
                // DB에 index 를 부여할 순 있지만 position(매개변수) 과 index(DB) 가 맞지 않을 수 있음
                // title 로 지워야함

                // -> 지금 클릭한 항목의 title 을 알아야함 凸
                // 1. ArrayList의 position번째 값을 꺼내는 방법
                // 2. 클릭이 이러난 항목의 textview에서 getText하는 방법

                // DB에서 지우기
                TextView tv_address = view.findViewById(R.id.tv_title);
                manager.delete(tv_address.getText().toString());

                // 눈에 뵈는 ListView에서도 지워야함
                data.remove(position);
                adapter.notifyDataSetChanged();
            }
        });

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if(requestCode == ADD){
            if (resultCode == RESULT_OK){
                String title = data.getStringExtra("title");
                String address = data.getStringExtra("address");

                this.data.add(new directVO(title,address));

                // manager 클래스의 insert 메소드 호출
                manager.insert(title,address);
            }
        }
    }
}

 

 

 

 

 

 

 

●AddActivity

public class AddActivity extends AppCompatActivity {

    EditText edt_title, edt_edt_address;
    Button btn_ok;

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

        edt_title = findViewById(R.id.edt_title);
        edt_edt_address = findViewById(R.id.edt_address);
        btn_ok = findViewById(R.id.btn_ok);

        btn_ok.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String title = edt_title.getText().toString();
                String address = edt_edt_address.getText().toString();

                Intent intent = new Intent();
                intent.putExtra("title",title);
                intent.putExtra("address",address);

                setResult(RESULT_OK, intent);
                finish();
            }
        });

    }
}

 

 

 

DBManager

public class DBManager extends SQLiteOpenHelper {


    public DBManager(@Nullable Context context) {
        super(context, "Direct.db", null, 1);
        // 1. context -> 화면(Activity)정보
        // 2. name -> DataBase 파일이름
        // 3. factory -> JDBC의 ResultSet 과 같은 일을 하는 객체
        // 4. version -> DB의 버전 , 최초 만들때는 1


        // 자식클래스의 생성자에 매개변수가 너무 많다 -> 적당히 지우기 ( Context 만 남기고 다 지우기)

    }

    // 부모 클래스에 매개변수가 잇는 생성자가 있다면
    // 자식 클래스에서 반드시 부모클래스의 생성자를 호출해 주어야한다
    // super -> 자식 클래스의 생성자에서만 호출가능
    @Override
    public void onCreate(SQLiteDatabase db) {
        // 데이터베이스 파일이 최초로 생성될 때 호출
        // 1.테이블 생성하는 소스코드 입력하기
        String sql = "create table direct(title text, address text)";
        // text(문자열)타입의 컬럼 2개생성

        // 2. sql 문장 전송하기( 매개변수로 주어진 SQLite DateBase 객체 사용 )
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 데이터베이스 파일의 버전이 바뀌었을때
        // 버전이 바뀌면 Table 지우고 다시 만드는 소스코드 입력
        String sql = "drop table direct";
        db.execSQL(sql);   //테이블 지우기

        onCreate(db);     //다시생성
    }

    public void insert(String title, String address) {
        // 리펙토링 -> 에러를 해결해나가는 방식으로 개발

        // 1. 쓸 수 있는 데이터베이스 객체 꺼내기
        SQLiteDatabase db = this.getWritableDatabase();
        // 2. 데이터를 insert -> Key, value 형태로 insert
        ContentValues cv = new ContentValues();
        cv.put("title",title);  //컬럼명과 데이터를 매개변수로 넣어준다
        cv.put("address",address);

        db.insert("direct",null,cv);
    }

    public Cursor getAllData() {
        // 1. DataBase 객체 꺼내기
        SQLiteDatabase db = this.getReadableDatabase();
        // 2. select 쿼리문 날리기
        String sql = "select * from direct";

        Cursor cs = db.rawQuery(sql, null);
        return cs;
    }

    public void delete(String text) {
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete("direct", "title='"+text+"'", null);//바로 변수에 넣었기 때문에 null
    }
}

 

 

●DirectVO

public class directVO {
    private String title;
    private String address;

    public directVO(String title, String address) {
        this.title = title;
        this.address = address;
    }

    public String getTitle() {
        return title;
    }

    public String getAddress() {
        return address;
    }
}

 

 

 

DirectAdapter

public class DirectAdapter  extends BaseAdapter {
    private Context c;
    private int layout;
    private ArrayList<directVO> data;
    private LayoutInflater inflater;

    public DirectAdapter(Context c, int layout, ArrayList<directVO> data) {
        this.c = c;
        this.layout = layout;
        this.data = data;
        this.inflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int position) {
        return data.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        if(convertView == null){
            convertView = inflater.inflate(layout, parent, false);
            // 최초 convertView 가 inflate 될때 ( 첫 항목이 만들어질때)
            holder = new ViewHolder(); // 새 Holder를 만든다

            holder.tv_title = convertView.findViewById(R.id.tv_title); //Holder 에 TextView , Button 저장
            holder.tv_address = convertView.findViewById(R.id.tv_address);
            holder.btn_go = convertView.findViewById(R.id.btn_go);
            convertView.setTag(holder); // 완성된 Holder를 convertView에 부착
        }else { //최초 한번이 아닐때
            holder = (ViewHolder)convertView.getTag();
        }

        // getView는 항목하나가 만들어 질 때마다 호출이 되는데
        // 항목을 만들 때 마다 findViewById 를 하면 굉장히 부하가 걸림
        // ViewHolder 패턴을 이용하여 효율적으로 View 들을 관리하기
        // ViewHolder - View 를 저장해둔 객체(VO랑 비슷)



        holder.tv_title.setText(data.get(position).getTitle());
        holder.tv_address.setText(data.get(position).getAddress());
        holder.btn_go.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 버튼 눌렀을때 address로 바로가기
                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(data.get(position).getAddress()));
                // Activity 클래스가 아니라서 (AppCompatActivity 클래스를 상속하지 않아서)
                // 바로 startActivity 메소드 사용x , 생성자를 통해서 전달받은 Context의 도움을 받아 실행

                // startActivity를 수행하면 task에 process 가 쌓이는데
                // 이곳은 Activity가 아니라 task에 접근 x
                // 그래서 intent에 옵션 (flag)을 설정하여 새로운 task를 생성

                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                c.startActivity(intent);
            }
        });

        return convertView;
    }

    // ViewHolder 설계
    public class ViewHolder{
        TextView tv_title;
        TextView tv_address;
        Button btn_go;


    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

'Android' 카테고리의 다른 글

로그인 후 채팅 방 만들기??  (0) 2021.04.06
서버 통신 로그인 DB연동( Volley 라이브러리 )  (0) 2021.04.03
Adapter -> Custom ListView활용  (0) 2021.03.25
Adapter View  (0) 2021.03.24
Intent 사용 2  (0) 2021.03.23