본문 바로가기
Android

Android [포스팅앱] 중복코드 함수화 / 액티비티별 액션바의 구성 / 양방향 객체 전달 / {}안의 [] JSON Volley로 GET해서 인덱싱 / 프로그래스바 보이기,숨기기

by leopard4 2023. 2. 7.

 

 

MainActivity 

package com.leopard4.postinglist;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.leopard4.postinglist.adapter.PostingAdapter;
import com.leopard4.postinglist.model.Post;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    ProgressBar progressBar;
    FloatingActionButton fab;

    final String URL = "https://block1-image-test.s3.ap-northeast-2.amazonaws.com";

    RecyclerView recyclerView;
    PostingAdapter adapter;
    ArrayList<Post> postList = new ArrayList<>();

    // 내가 실행한 액티비티로부터, 데이터를 다시 받아오는 경우에 작성하는 코드
    public ActivityResultLauncher<Intent> launcher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {   // setResult()의 결과와 매핑된것.
                    // 액티비티를 실행한후, 이 액티비티로
                    // 돌아왔을때 할 일을 여기에 작성

                    // AddActivity가 넘겨준
                    // Post 객체를 받아서 원상복구 시키고
                    // 리스트에 넣어주고
                    // 화면 갱신 해준다.
                    if (result.getResultCode() == AddActivity.SAVE) {
                        Post post = (Post) result.getData().getSerializableExtra("post");
                        postList.add(0, post); // 리스트의 맨앞에 추가
                        adapter.notifyDataSetChanged(); // 화면 갱신
                    }
                }
            });



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

        getSupportActionBar().setTitle("포스팅리스트"); // 이코드가 예전버전도 호환이 됨

        progressBar = findViewById(R.id.progressBar);
        fab = findViewById(R.id.fab);

        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        // fab 버튼을 누르면, 새로운 액티비티를 띄운다.
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startAddActivity();
            }
        });

        // 네트워크 통해서 데이터를 받아오고, 화면에 표시
        RequestQueue queue = Volley.newRequestQueue(this);
        JsonObjectRequest request = new JsonObjectRequest( // 파라미터 총5개
                Request.Method.GET,
                URL + "/posting.json",
                null,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        // 네트워크 호출이 끝나면, 프로그래스바를 화면에서 숨긴다.
                        progressBar.setVisibility(View.GONE);

                        try {
                            JSONArray data = response.getJSONArray("data");

                            for (int i = 0; i < data.length(); i++) {

                                Post post = new Post(
                                    data.getJSONObject(i).getInt("userId"),
                                    data.getJSONObject(i).getInt("id"),
                                    data.getJSONObject(i).getString("title"),
                                    data.getJSONObject(i).getString("body")
                                );
                                postList.add(post); // 리스트란 힙에있는 post객체의 위치값만 선으로 연결하는것
                            }

                        } catch (JSONException e) {
                            return;
                        }

                        // 데이터를 화면에 표시
                        adapter = new PostingAdapter(MainActivity.this, postList);
                        recyclerView.setAdapter(adapter);

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        // 네트워크 호출이 끝나면, 프로그래스바를 화면에서 숨긴다.
                        progressBar.setVisibility(View.GONE);

                    }
                }
        );
        // 네트워크 호출할때, 프로그래스바를 화면에 보이게 한다.
        progressBar.setVisibility(View.VISIBLE);
        // 네트워크 호출
        queue.add(request);

    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        int itemId = item.getItemId();

        if(itemId == R.id.menuAdd){
            // AddActivity 를 실행한다.
            startAddActivity();
        }

        return super.onOptionsItemSelected(item);
    }

    // AddActivity 를 실행하는 함수 만든다.
    // 기획문서가 자주 바뀌니, 똑같은 코드는 함수화 시키는게 좋다.
    void startAddActivity(){
        Intent intent = new Intent(MainActivity.this, AddActivity.class);
        launcher.launch(intent);
    }
}

AddActivity

package com.leopard4.postinglist;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.leopard4.postinglist.model.Post;

public class AddActivity extends AppCompatActivity {

    EditText editTitle;
    EditText editBody;
    Button btnSave;

    public static final int SAVE = 100;

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

        getSupportActionBar().setTitle("포스팅 생성");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true); // 뒤로가기 버튼


        editTitle = findViewById(R.id.editTitle);
        editBody = findViewById(R.id.editBody);
        btnSave = findViewById(R.id.btnSave);

        btnSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                savePosting();
            }
        });
    }

    @Override
    public boolean onSupportNavigateUp() {
        finish();
        return super.onSupportNavigateUp();
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.add, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {

        int itemId = item.getItemId();

        if(itemId == R.id.menuSave){
            savePosting();

        }
        return super.onOptionsItemSelected(item);
    }

    void savePosting(){
        String title = editTitle.getText().toString().trim();
        String body = editBody.getText().toString().trim();

        if (title.isEmpty() || body.isEmpty()) {
            Toast.makeText(AddActivity.this, "모두 입력해주세요", Toast.LENGTH_SHORT).show();
            return;
        }

        Post post = new Post(title, body);

        // post 를 인텐트에 담아서 메인액티비티로 전달하고
        // 나를실행한 액티비티한테 데이터를 전달해 주는 코드
        Intent intent = new Intent();
        intent.putExtra("post", post);
        setResult(SAVE, intent);

        // 이 액티비티는 사라져야 한다.
        finish();
    }
}

Post (클래스)

package com.leopard4.postinglist.model;

import java.io.Serializable;

public class Post implements Serializable {
    public int id;
    public int userId;
    public String title;
    public String body;

    public Post() {
    }

    public Post(String title, String body) {
        this.userId = -1; // 임의로 -1로 설정 // 설정을 안하면 디폴트로 0으로 됨.
        this.id = -1;
        this.title = title;
        this.body = body;
    }

    public Post(int id, int userId, String title, String body) {
        this.id = id;
        this.userId = userId;
        this.title = title;
        this.body = body;
    }
}

PostingAdapter

package com.leopard4.postinglist.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.leopard4.postinglist.R;
import com.leopard4.postinglist.model.Post;

import java.util.ArrayList;

public class PostingAdapter extends RecyclerView.Adapter<PostingAdapter.ViewHolder>{

    Context context;
    ArrayList<Post> postList;

    public PostingAdapter(Context context, ArrayList<Post> postList) {
        this.context = context;
        this.postList = postList;
    }

    @NonNull
    @Override
    public PostingAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.posting_low, parent, false);
        return new PostingAdapter.ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull PostingAdapter.ViewHolder holder, int position) {
        Post post = postList.get(position);
        holder.txtTitle.setText(post.title);
        holder.txtBody.setText(post.body);

    }

    @Override
    public int getItemCount() {
        return postList.size();
    }


    public class ViewHolder extends RecyclerView.ViewHolder{

        TextView txtTitle;
        TextView txtBody;
        ImageView imgDelete;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            txtBody = itemView.findViewById(R.id.txtBody);
            txtTitle = itemView.findViewById(R.id.txtTitle);
            imgDelete = itemView.findViewById(R.id.imgDelete);

        }
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:targetSandboxVersion="1">  <!-- 에뮬레이터 네트워크 설정 -->

    <uses-permission android:name="android.permission.INTERNET" />  <!-- 실배포시 이부분만해주면 됩니다. -->

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config" <!-- 에뮬레이터 네트워크 설정 -->
        android:supportsRtl="true"
        android:theme="@style/Theme.PostingList"
        android:usesCleartextTraffic="true"  <!-- 에뮬레이터 네트워크 설정 -->
        tools:targetApi="31">
        <activity
            android:name=".AddActivity"
            android:exported="false" />
        <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>

 

https://github.com/leopard4/PostingList