마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

DB pk 갱신에 대해서..[코드추가]

0 추천

폰 내부 db 를 사용해서, select로 저장된 값들을 커스텀 리스트뷰에 연동하여 보여주고 있습니다.

특정 값을 삭제할 때, 롱클릭으로 해당 position값을 받은 후 id값으로 넣어 삭제하는 방식을 구현하고있습니다.

일단 삭제 자체는 잘되는데... pk인 id값(int형)을 재 정렬 할 수 있을까요?

가령,

num  name

0        박철수

1        김민희

2       나윤지

이런식으로 회원이 있다면 ,1번 김민희를 삭제 시킨 후 다시 DB를 조회하면

0 박철수 / 2 나윤지가 남습니다... 가운데 공백이 생겨버리는데, DB데이터를 변경 후

pk값을 다시 정렬해서 부여할 수있나요? (0박철수/1나윤지 이런식으로)

 

맨 처음 테이블을 생성할 때는 다음과 같이 하였습니다.

"CREATE TABLE 테이블명 (num INTEGER PRIMARY KEY AUTOINCREMENT,"

+"name TEXT);

 

 

+ 혹시몰라서 소스도 추가했습니다. 지적/조언 부탁드립니다..일단 대화를 insert하는 부분은 제외했습니다.

 


		// ExamData 객체를 관리하는 ArrayList 객체를 생성한다.
		ArrayList<ExamData> data_list = new ArrayList<ExamData>();
		// 사용자 정의 어댑터 객체를 생성한다.
		m_adapter = new ExamAdapter(data_list);

		// 리스트를 얻어서 어댑터를 설정한다.
		m_list = (ListView) findViewById(R.id.var_list);
		m_list.setAdapter(m_adapter);

		//현재시간
		m_date_format = new SimpleDateFormat("yyyy/MM/dd", Locale.KOREA);
		m_time_format = new SimpleDateFormat("HH:mm:ss", Locale.KOREA);

		Log.d("onCreate", "내용출력하기");
		// 스크롤 맨 아래로 내려준다.
		m_list.post(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				Log.d("listview post", "post");
				m_list.setSelection(m_adapter.getCount() - 1);
			}
		});
		ExamData data = null; // 이름,메세지,시간
		ExamData data2 = null; // 날짜

		dbHelper = new DBHelper(this, dbName, null, dbVersion);
		db = dbHelper.getReadableDatabase();
		sql = "SELECT * FROM student;";
		Cursor cursor = db.rawQuery(sql, null);
		String dbDate1 = null;
		String dbDate2 = null;
		if (cursor.getCount() > 0) // 하나라도 있는 경우
		{
			Log.d("메세지 총 갯수: ", "" + cursor.getCount() + "개");
			while (cursor.moveToNext()) {
				Log.d("조회결과:  ", String.format(
						"\n넘버: = %s ,이름: = %s, 메시지: = %s , 날짜: = %s , 시간: = %s",
						cursor.getString(0), cursor.getString(1), cursor.getString(2),
						cursor.getString(3), cursor.getString(4)));

				dbDate1 = cursor.getString(3);
				if (!dbDate1.equals(dbDate2)) {
					Log.d("바뀐 날짜 출력하기", dbDate1);
					data2 = new ExamData((int) 1, cursor.getString(3), null,
							null);
					m_adapter.add(data2);

				}
				dbDate2 = dbDate1;
				// Log.d("dbDate1",dbDate1);
				// Log.d("dbDate2",dbDate2);
				if (dbDate1.equals(dbDate2)) {
					Log.d("date", "date1 = date2");
				}

				//
				data = new ExamData((int) 0, cursor.getString(1),
						cursor.getString(2), cursor.getString(4));
				// 어댑터에 데이터를 추가한다.

				m_adapter.add(data);
			}
		} else 
		{
			null_text.setVisibility(View.VISIBLE);
			Log.d("onCreate조회결과가없습니다", "onCreate조회결과가없습니다.");
			
		}
		cursor.close();
		// 원하는 포지션으로 리스트뷰 스크롤하기.smoothScrollToPosition
		m_list.smoothScrollToPosition(m_adapter.getCount() - 1);
		mNotificationManager = (NotificationManager)
                this.getSystemService(Context.NOTIFICATION_SERVICE);
		mNotificationManager.cancelAll();
		
		
		
		//삭제
		m_list.setOnItemLongClickListener(new OnItemLongClickListener() {

			@Override
			public boolean onItemLongClick(AdapterView<?> parent, View view,
					int position, long id) {
				delete_dialog(position);
				return true;
				
			}
		});
		
		
	}// onCreate
	
	//aaa
	public void delete_dialog(final int position)
	{
		AlertDialog.Builder alert = new AlertDialog.Builder(MainActivity.this);
		alert.setPositiveButton("예", new DialogInterface.OnClickListener() {
		    @Override
		    public void onClick(DialogInterface dialog, int which) 
		    {
		    	Toast.makeText(getApplicationContext(), "예", 1000).show();
		    	db = dbHelper.getWritableDatabase();
		    	Log.d("position값",position+"");
				sql = "DELETE FROM student WHERE num ='"+ position +"';";
				db.execSQL(sql);
				;
				
		    }
		});
		alert.setNegativeButton("아니오", new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				// TODO Auto-generated method stub
				Toast.makeText(getApplicationContext(), "아니오", 1000).show();
				dialog.dismiss();     //닫기
			}
		});
		alert.setMessage("이 메세지를 삭제하시겠습니까?");
		alert.setTitle(position+"번째 메세지 삭제");
		alert.show();
		
	}
	
	// http://blog.daum.net/_blog/BlogTypeView.do?blogid=0NhTQ&articleno=251
	public static class ExamData {
		public int type = 0; // 레이어종류를 구분할 변수.
		public String data0 = null;
		public String data1 = null;
		public String data2 = null;

		// byte parm_type,
		public ExamData(int parm_type, String parm_data0, String parm_data1,
				String parm_data2) {
			type = parm_type;
			data0 = parm_data0; // 이름
			data1 = parm_data1; // 대화명
			data2 = parm_data2; // 시간
		}
	}

	

	// BaseAdapter 를 상속하여 어댑터 클래스를 재정의한다.
	private class ExamAdapter extends BaseAdapter {
		private LayoutInflater m_inflater = null;

		// ExamData 객체를 관리하는 ArrayList
		// private ArrayList<ExamData> m_data_list; //전역변수로 끌올
		public ExamAdapter(ArrayList<ExamData> items) {
			m_data_list = items;
			// 인플레이터를 얻는다.
			m_inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		}

		// ArrayList 에 ExamData 객체를 추가하는 메서드
		public void add(ExamData parm_data) {
			m_data_list.add(parm_data);
			// 데이터가 변화됨을 알려준다.
			notifyDataSetChanged();
		}

		// 어댑터에서 참조하는 ArrayList 가 가진 데이터의 개수를 반환하는 함수
		@Override
		public int getCount() {
			return m_data_list.size();
		}

		// 인자로 넘어온 값에 해당하는 데이터를 반환하는 함수
		@Override
		public ExamData getItem(int position) {
			return m_data_list.get(position);
		}

		// 인자로 넘어온 값에 해당하는 행 ID 를 반환하는 메서드
		@Override
		public long getItemId(int position) {
			return position;
		}

		// 인자로 넘어온 값에 해당하는 뷰의 타입을 반환하는 메서드
		@Override
		public int getItemViewType(int position) {
			return m_data_list.get(position).type;
		}

		// getView 메서드로 생성될 수 있는 뷰의 수를 반환하는 메서드
		@Override
		public int getViewTypeCount() {
			return 2;
		}

		// 각 항목에 출력될 뷰를 구성하여 반환하는 메서드
		public View getView(int position, View convertView, ViewGroup parent) {
			View view = null;
			// 해당 항목의 뷰 타입을 얻는다.
			int type = getItemViewType(position);
			// convertView 뷰는 어댑터가 현재 가지고 있는 해당 항목의 뷰객체이다.
			// null 이 넘어오는 경우에만 새로 생성하고, 그렇지않은 경우에는 그대로 사용한다.
			if (convertView == null) {
				view = m_inflater.inflate(R.layout.list_item1, null);
				switch (type) 
				{
				case 0://대화 형식 레이아웃
					view = m_inflater.inflate(R.layout.list_item1, null);
					break;
				case 1://시간타이틀 레이아웃
					view = m_inflater.inflate(R.layout.list_item3, null);
					break;
				}
			} 
			else 
			{
				view = convertView;
			}
			//요청하는 항목에 해당하는 데이터 객체를 얻는다.
			ExamData data = m_data_list.get(position);
		
			// 데이터가 존재하는 경우
			if (data != null) 
			{
				if (type == 0) 
				{
					TextView user_tv = null, msg_tv = null, date_tv = null;
					user_tv = (TextView) view.findViewById(R.id.user_view1);
					msg_tv = (TextView) view.findViewById(R.id.message_view1);
					date_tv = (TextView) view.findViewById(R.id.date_view1);

					// 이름, 대화내용, 시간정보를 텍스트뷰
					user_tv.setText(data.data0);
					msg_tv.setText(data.data1);
					date_tv.setText(data.data2);
				} 
				else if (type == 1) 
				{
					((TextView) view).setText(data.data0);
				}
				
				Log.d("getview","getview!");
			}
			return view;
		}
	}

	

 

anci (19,950 포인트) 님이 2015년 4월 15일 질문
anci님이 2015년 4월 15일 수정

3개의 답변

+2 추천
무슨 이유인지는 모르겠지만, 그런 방식은 하지마세요.

순번이 필요하면 뷰에서 추가시키는 방식으로 하는게 낫습니다.
쎄미 (162,410 포인트) 님이 2015년 4월 15일 답변
일단 소스가 거의 보기가 힘드네요.. ㅋㅋ
ExamData 가 POJO 인거 같구요
애초에 Cursor 로 데이터 땡겨서 ExamData 만들때
ExamData 에다가 pk 정보를 넣어주라는 말이죠
그리고 getView 에서 setonLongClick 같은 것을 할때
position 이 아니라 data.getPrimaryKey() 와 같은 식으로 구현하시라는 말이었습니다.
답변 감사합니다..
저도 구글링으로 본 샘플에서 리스트에 추가 되는 레이아웃과 그 안에 들어갈 내용만 변경한지라.. 전체적인 이해도가 부족했던것 같습니다.
즉, cursor로 DB전체의 데이터를 조회해서 하나하나 추가할 때마다
new ExamData((int) 1, m_date_format.format(new Date()),
                    null, null); 이 부분에 각각해당하는 pk값을 넣고, getview에서 setOnItemLongClickListener 부분에 포지션이 아닌 해당 데이터의 pk값을 받아와서 처리하라 이 말씀이신거죠?
네 맞습니당 ㅇㅇㅇㅇㅇ
답변감사합니다. getview내에서 data != null 일 때, setOnItemLongClickListener 를 사용해서 data.data1 로, 일단은 선택된 아이템의 [대화내용]을 toast로 띄우고자 하는데요, data.data1을 사용하려고하니 Exam data 요녀석을 final로 처리 해야한다고 에러가 뜨네요; final로 처리하면 변수내용이 바뀌지 않고 같은것만 나오게 되지 않나요..? 또한, final로 처리해서 대화내용을 출력해보니 엉뚱한 값이 나옵니다. [스크롤 중간쯤에 출력된 메세지]
+1 추천
pk 를 drop 하고 다시 create 하면 될 수도 있으나 추천하지 않습니다.

공백을 없애야만 하는 크리티컬한 이유가 있지 않은 이상에 (대부분의 경우에는 이런 경우는 없습니다.)

db 내부적으로 pk 를 관리하므로 손대지 않는 것이 바람직합니다.
mamondebaltob (32,750 포인트) 님이 2015년 4월 15일 답변
+1 추천
db 의 데이터와 리스트뷰의 포지션 을 매칭시키기 위한것 같으시군요.

DB를 변경해서 재정렬하지마시고 adapter에서 관리하는 데이터셋을 이용하시는게 좋습니다.

리스트에서 데이터 삭제 -> db raw 를 제거함과 동시에 adapter에서 관리하는 데이터셋(리스트나 맵 등)을 삭제 해주시면 sync 가 맞겠지요.
포도맛카라 (700 포인트) 님이 2015년 4월 15일 답변
...