안녕하십니까! 저번 포스팅에선 DB에서 게시글 정보를 가져온 후 리사이클뷰로 띄우는 작업을 하였습니다. 이번 포스팅은 저번 '게시판 기능 구현' 포스팅에 이어서 글을 클릭하였을 때 게시글을 읽을 수 있는 기능을 구현해 보겠습니다!
<완성본 미리보기>
게시판에서 게시글 클릭 | 게시글 읽기 페이지 |
<1. acivitiy_read.xml>
> 우선 읽기 페이지는 다음과 같이 디자인해주었습니다.
↑ 읽기 페이지 UI
↓ 읽기 페이지 코드
<?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/post_read_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#3C3A3A"
tools:context=".ReadActivity">
<ImageButton
android:id="@+id/btn_back2"
android:layout_width="60dp"
android:layout_height="48dp"
android:layout_marginStart="16dp"
android:layout_marginTop="23dp"
android:contentDescription="back button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="?attr/actionModeCloseDrawable" />
<TextView
android:id="@+id/post_content"
android:layout_width="321dp"
android:layout_height="450dp"
android:layout_marginTop="-80dp"
android:background="#E9DADA"
android:gravity="center"
android:text="게시글 내용입니다"
android:textColor="#000000"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/post_title"
app:layout_constraintVertical_bias="0.501" />
<TextView
android:id="@+id/post_title"
android:layout_width="321dp"
android:layout_height="63dp"
android:layout_marginTop="100dp"
android:background="#E9DADA"
android:gravity="center"
android:text="제목입니다"
android:textColor="#000000"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<2. post_read.php 코드>
> 리사이클 뷰에서 게시글 클릭 시 DB에서 게시글 정보를 불러올 PHP 코드입니다.
<?php
include 'dbcon.php';
//subpage.php
session_start();
session_cache_expire(60);// 세션 유지시간 1시간
$inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE); // Json 형식에서 배열로 디코딩 ,$_POST를 사용할 수 없기 때문에 이것을 사용.
$idx = $input['idx'] ?? NULL; //입력값이 없으면 빈 문자열로 처리
$sql = "SELECT * FROM post_info WHERE idx=$idx";
$result = mysqli_query($db, $sql);
$posts = []; //게시글 정보를 담을 배열 생성
$posting = mysqli_fetch_assoc($result);
if ($posting) {
$posts[] = [ //게시글 정보를 담은 배열
'title' => $posting['post_title'],
'writer' => $posting['post_writer'],
'gender' => $posting['gender'],
'date' => $posting['post_date'],
'idx' => $posting['idx'],
'content' => $posting['content']
];
echo json_encode(['status' => 'success', 'posts' => $posts]);
} else {
echo json_encode(['status' => 'error', 'message' => '잘못된 접근입니다.']);
}
?>
<3. ReadActivity 코드>
> 핵심이 되는 ReadActivity 코드입니다.
package com.example.test_app
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.test_app.databinding.ActivityReadBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONObject
import java.io.BufferedOutputStream
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.net.HttpURLConnection
import java.net.URL
class ReadActivity : AppCompatActivity() {
private var mBinding: ActivityReadBinding? = null //mBinding이 null을 가질수 있다.
private val binding get() = mBinding!! //!! 를 붙여줌으로써 null 이 아니라는것을 보장.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_read)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.post_read_layout)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
mBinding = ActivityReadBinding.inflate(layoutInflater) //xml파일과 액티비티 연결
setContentView(binding.root) // xml의 부모 바인딩을 가져온다.
Log.d("post_idx: ", intent.getIntExtra("idx",-1).toString()) //게시글의 인덱스값을 가져온다.
val idx:Int =intent.getIntExtra("idx",-1)
CoroutineScope(Dispatchers.IO).launch {
val postinfo: ArrayList<Post> = sendPostRequest_read(idx).second //post요청은 IO스레드에서
withContext(Dispatchers.Main) { //UI 업데이트는 Main단에서
binding.postTitle.setText(postinfo.get(0).title)
binding.postContent.setText(postinfo.get(0).content)
binding.btnBack2.setOnClickListener { //뒤로가기 버튼
super.onBackPressed() //뒤로가기 기능
}
}
}
}
// 서버로 HTTP 요청을 보내는 함수
private fun sendPostRequest_read(idx: Int): Pair<Int,ArrayList<Post>> { //인덱스에 해당하는 게시물 1개만 가져오는 함수
val url = URL("http://192.168.0.10/post_read.php")
val postData = JSONObject()
postData.put("idx", idx) //json 형식으로 보낸다는것을 주의!! php 에서 $_POST로는 사용불가!
val result = with(url.openConnection() as HttpURLConnection) {
requestMethod = "POST"
doOutput = true
val outputStream = BufferedOutputStream(outputStream)
BufferedWriter(OutputStreamWriter(outputStream, "UTF-8")).use { writer ->
writer.write(postData.toString())
writer.flush()
}
//url로 데이터 전송후 서버로부터 응답을받는 부분
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader(InputStreamReader(inputStream)).use { reader ->
val response = StringBuilder() //동적문자열객체 선언(이로인해 이 문자열 뒤로 계속 추가해나갈수있음)이자체로는 문자열이 아님!
var line: String?
while (reader.readLine().also { line = it } != null) {
response.append(line) //json 응답을 문자열로 가져옴
}
//JSON 응답을 처리
val jsonResponse= JSONObject(response.toString())//응답을 다시 json객체로 변환
val status=jsonResponse.getString("status")//응답에서 key=status 인 데이터 저장
val postArray=jsonResponse.getJSONArray("posts")//응답에서 posts라는 이름의 배열 저장
//게시글 정보를 List로 변환 <PostAdapter와의 호환을 위하여 변환해야함>
val postList= ArrayList<Post>() //Post형식의 배열을 가진 동적List 생성
for (i in 0 until 1){
val postJson=postArray.getJSONObject(0)//i번째 게시글 정보를 가져온다.
val post= Post(
title=postJson.getString("title"),
writer=postJson.getString("writer"),
gender = postJson.getInt("gender"),
date = postJson.getString("date"),
idx=postJson.getInt("idx"),
content = postJson.getString("content")
)
//Post 객체 생성 후 리스트에 추가
postList.add(post)
}
Log.d("HTTP_POST", "Response: $response") // 결과값 Logcat 으로 확인가능!
return@with Pair(1,postList)
}
} else {
Log.e("HTTP_POST", "Error: $responseCode") //에러발생시 에러코드 출력!
return@with Pair(0, ArrayList<Post>())
}
}
return result
}
}
1. sendPostRequest_Read 함수
> DB에서 게시글 정보를 가져온 PHP파일에 출력된 내용을 Kotlin으로 가져오는 함수입니다.
2. 게시글의 idx 값은 어떻게 가져온건가요?
위에 달아드린 링크 속 글에서 설명했지만 리사이클 뷰를 위해서 list_post.xml 이란 파일을 만들었습니다. xml 요소 중 post_idx 란 textview를 만들고 안 보이게끔 처리해 주었습니다. 게시글 클릭 시 textview에 저장되어 있던 idx값 을 intent.putExtra("idx",post.idx) 를 이용하여 게시글 읽기 페이지로 넘어가면서 idx도 같이 넘겨주었습니다.
긴 글 읽어주셔서 감사합니다!
'모바일 앱개발(Kotlin-PHP-Mysql)' 카테고리의 다른 글
[Android Studio] PHP 서버와 통신시 세션ID 활용하는 방법 -Kotlin (0) | 2024.10.17 |
---|---|
[Android Studio] 게시글 CRUD(생성,읽기,수정,삭제)기능 구현 -Kotlin (0) | 2024.10.15 |
[Android Studio] 게시판 기능 구현 + 리사이클 뷰 생성 (Kotlin) (0) | 2024.10.11 |
[Android Studio] 무선 디버깅 연결이 안될때 수동으로 연결하는법. (0) | 2024.10.07 |
[Android Studio] 회원가입 기능 구현 - Kotlin (0) | 2024.10.05 |