{"id":3877,"date":"2021-11-17T20:45:18","date_gmt":"2021-11-17T11:45:18","guid":{"rendered":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=3877"},"modified":"2021-11-21T21:17:44","modified_gmt":"2021-11-21T12:17:44","slug":"android-mvvm-aac-livedata-recyclerview","status":"publish","type":"post","link":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=3877","title":{"rendered":"Android MVVM (AAC) LiveData RecyclerView"},"content":{"rendered":"<h1>Android MVVM (AAC) LiveData RecyclerView<\/h1>\n<p><a href=\"https:\/\/m.blog.naver.com\/PostView.naver?isHttpsRedirect=true&amp;blogId=tkddlf4209&amp;logNo=221555168690\">\ucc38\uc870<\/a><\/p>\n<h2>build.gradle<\/h2>\n<pre><code class=\"language-gradle\">android {\n    \/\/ ......\n    dataBinding {\n        enabled = true\n    }\n}<\/code><\/pre>\n<h2>ViewModel \uc0dd\uc131<\/h2>\n<p>ViewModel \uc744 \uc0dd\uc131\ud55c\ub2e4.<br \/>\nMutableLiveData \ub97c \uc0dd\uc131\ud558\uba74, MutableLiveData \uc758 \ub370\uc774\ud0c0\uac00 \ubcc0\uacbd\uc2dc \uc774\ubca4\ud2b8\uac00 \ubc1c\uc0dd\ud55c\ub2e4.<\/p>\n<p>\ub2e8\uc21c\ud788 \uc774\ubca4\ud2b8\ub97c \ubc1c\uc0dd\uc2dc\ud0a4\ub294\uac8c \uc544\ub2c8\ub77c,<br \/>\nLifecycle \uc5d0 \ub9de\ucdb0\uc11c \ubc1c\uc0dd\uc2dc\ud0a8\ub2e4.<\/p>\n<p>\uc774\ubca4\ud2b8 \ubc1c\uc0dd\uc774 \ud65c\uc131\uc0c1\ud0dc(started, resumed)\ub85c \uc9c0\uc5f0\ub418\ub294 \uac83\uc774 \uc544\ub2c8\ub77c,<br \/>\n\ub370\uc774\ud0c0 \uc5c5\ub370\uc774\ud2b8 \uc790\uccb4\uac00 \ud65c\uc131\uc0c1\ud0dc\ub85c \uc9c0\uc5f0\ub41c\ub2e4.<br \/>\n\ub530\ub77c\uc11c, \uc571\uc774 \ubc31\uadf8\ub77c\uc6b4\ub4dc\uc5d0\uc11c \uadf8\ub300\ub85c \uc885\ub958\ud574 \ubc84\ub9ac\ub294 \uacbd\uc6b0\ucc98\ub7fc,<br \/>\n\ubd88\ud544\uc694\ud55c \uc5c5\ub370\uc774\ud2b8 \ubc0f \uc774\ubca4\ud2b8\ubc1c\uc0dd\uc744 \ub9c9\uc544\uc900\ub2e4.<\/p>\n<p>\uacf3\uacf3\uc5d0 \ubd84\uc0b0\ub418\uc5b4 \uc788\ub294 DB\/API \ud638\ucd9c \ucf54\ub4dc\ub4e4\uc774 ViewModel \uc548\uc73c\ub85c \ubaa8\uc774\uac8c \ub41c\ub2e4.<\/p>\n<pre><code class=\"language-java\">public class FavoriteFolderViewModel extends AndroidViewModel {\n\n    private static final String TAG = &quot;FavoriteFolderViewModel&quot;;\n    private MutableLiveData&lt;ArrayList&lt;FavoriteFolder&gt;&gt; favoriteFolders;\n    AppDataBase appDataBase;\n\n    public FavoriteFolderViewModel(@NonNull Application application) {\n        super(application);\n        favoriteFolders = new MutableLiveData&lt;&gt;();\n    }\n\n    public void setAppDataBase(AppDataBase appDataBase) {\n        this.appDataBase = appDataBase;\n    }\n\n    public MutableLiveData&lt;ArrayList&lt;FavoriteFolder&gt;&gt; getFavoriteFolders() {\n        return favoriteFolders;\n    }\n\n    public void requestList() {\n        appDataBase.RoomDao().getFolderList(0)\n                .subscribeOn(Schedulers.io())\n                .observeOn(AndroidSchedulers.mainThread())\n                .doOnSuccess(items -&gt; {\n                    Log.d(TAG, &quot;Total count : &quot; + items.size());\n                    favoriteFolders.setValue((ArrayList&lt;FavoriteFolder&gt;) items);\n                })\n                .doOnError(throwable -&gt; Log.e(TAG, &quot;Error : &quot; + throwable.toString()))\n                .subscribe();\n    }\n\n    public void requestInsert(FavoriteFolder favoriteFolder) {\n        appDataBase.RoomDao().insertFolder(favoriteFolder)\n                .subscribeOn(Schedulers.io())\n                .observeOn(AndroidSchedulers.mainThread())\n                .doOnSuccess(id -&gt; {\n                    Log.d(TAG, &quot;Data inserted : &quot; + id);\n                    requestList();\n                })\n                .doOnError(throwable -&gt; {\n                    Log.e(TAG, &quot;Error : &quot; + throwable.toString());\n                })\n                .subscribe();\n    }\n\n    public void requestUpdate() {\n        \/\/\n    }\n\n    public void requestDelete(int id) {\n        appDataBase.RoomDao().deleteFolder(id)\n                .subscribeOn(Schedulers.io())\n                .observeOn(AndroidSchedulers.mainThread())\n                .doOnSuccess(affectedRows -&gt; {\n                    if (affectedRows == 0) {\n                        return;\n                    }\n\n                    Log.d(TAG, &quot;Data deleted : &quot; + id);\n                    requestList();\n                })\n                .doOnError(throwable -&gt; Log.e(TAG, &quot;Error : &quot; + throwable.toString()))\n                .subscribe();\n    }\n}<\/code><\/pre>\n<h2>Fragment<\/h2>\n<p>LiveData \uc5d0 Observer \ub97c \ubd99\uc5ec\uc8fc\uace0, \ub370\uc774\ud0c0 \ubcc0\uacbd\uc2dc \uc774\ubca4\ud2b8\ub97c \uc218\uc2e0\ud558\uace0, UI \uc5d0 \ubc18\uc601\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-java\">public class RestaurantInfoAddBottomSheetFragment extends BottomSheetDialogFragment {\n    \/\/ ......\n    FavoriteFolderViewModel favoriteFolderViewModel;\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n\n        \/\/ ......\n        favoriteFolderViewModel = new ViewModelProvider(this).get(FavoriteFolderViewModel.class);\n        favoriteFolderViewModel.setAppDataBase(appDataBase);\n        adapter.setViewModel(favoriteFolderViewModel);\n        Observer&lt;ArrayList&lt;FavoriteFolder&gt;&gt; observer = favoriteFolders -&gt; {\n            if (favoriteFolders.size() == 0) {\n                FavoriteFolder item = new FavoriteFolder(\n                        getResources().getString(R.string.base_folder),\n                        getResources().getString(R.string.hidden),\n                        1);\n                favoriteFolderViewModel.requestInsert(item);\n\n                return;\n            }\n            adapter.setItems(favoriteFolders);\n            \/\/ DiffUtil \uc774 \ub2e8\uc21c \ube44\uad50\ub9cc \ud558\ub294\uac8c \uc544\ub2c8\ub77c, UI \uc5c5\ub370\uc774\ud2b8\ud560 \ubaa9\ub85d\uae4c\uc9c0 \ub9cc\ub4e4\uc5b4\uc8fc\ubbc0\ub85c\n            \/\/ \ubcc4\ub3c4 \uc5c5\ub370\uc774\ud2b8\ub294 \ud544\uc694\uc5c6\ub2e4.\n            \/\/ adapter.notifyDataSetChanged();\n        };\n        favoriteFolderViewModel.getFavoriteFolders().observe(this, observer);\n        \/\/ ......\n    }\n}<\/code><\/pre>\n<h2>MutableLiveData<\/h2>\n<p>\uac12\uc744 \uc5c5\ub370\uc774\ud2b8\ud558\ub294 \ud568\uc218\ub294 setValue\/postValue \ub450\uac00\uc9c0\uac00 \uc788\ub2e4.<\/p>\n<p>setValue \ub294 Main thread \uc5d0\uc11c\ub9cc \ud638\ucd9c\ud560 \uc218 \uc788\uc73c\uba70, \ub3d9\uae30\ubc29\uc2dd\uc73c\ub85c, \uc21c\uc11c\uac00 \ubcf4\uc7a5\ub41c\ub2e4.<\/p>\n<p>postValue \ub294 \ubc31\uadf8\ub77c\uc6b4\ub4dc\uc5d0\uc11c\ub3c4 \uc2e4\ud589\ub418\uba70, \ube44\ub3d9\uae30\ubc29\uc2dd\uc73c\ub85c, \uc21c\uc11c\ub294 \ubcf4\uc7a5\ub418\uc9c0 \uc54a\ub294\ub2e4.<\/p>\n<h2>ListAdapter<\/h2>\n<p>RecyclerViewAdapter \ub97c \uc774\uc6a9\ud558\uac8c\ub418\uba74,<br \/>\n\uc911\uac04\uc5d0 \ub370\uc774\ud130\ub97c \ucd94\uac00\ud558\uac70\ub098 \uc218\uc815\/\uc0ad\uc81c\uc2dc\uc5d0,<br \/>\nRecyclerView \ub97c \uc0c8\ub85c\uace0\uce68\ud574\uc8fc\ub294 \ub85c\uc9c1\uc774 \ub9e4\uc6b0 \ubcf5\uc7a1\ud574\uc9c4\ub2e4.<\/p>\n<p>ListAdapter \ub97c \uc774\uc6a9\ud558\uac8c\ub418\uba74 UI \uc5c5\ub370\uc774\ud2b8\uac00 \uc790\ub3d9\ud654\ub418\uc5b4 \uc18c\uc2a4\uac00 \uac04\ub2e8\ud574\uc9c4\ub2e4.<\/p>\n<h3>Entity<\/h3>\n<p>Entity \uc5d0 Entity \ube44\uad50\ub97c \uc704\ud55c \uba54\uc18c\ub4dc\ub97c \ucd94\uac00\ud574 \uc900\ub2e4.<\/p>\n<pre><code class=\"language-java\">@Entity(tableName = &quot;tbl_favorite_folder&quot;, indices = {@Index(value = {&quot;id&quot;}, unique = true)})\npublic class FavoriteFolder {\n    \/\/ ......\n    public static DiffUtil.ItemCallback&lt;FavoriteFolder&gt; DIFF_CALLBACK = new  DiffUtil.ItemCallback&lt;FavoriteFolder&gt;() {\n        @Override\n        public boolean areItemsTheSame(@NonNull FavoriteFolder oldItem, @NonNull FavoriteFolder newItem) {\n            return oldItem.id == newItem.id;\n        }\n\n        @Override\n        public boolean areContentsTheSame(@NonNull FavoriteFolder oldItem, @NonNull FavoriteFolder newItem) {\n            return oldItem.equals(newItem);\n        }\n\n    };\n\n    @Override\n    public boolean equals(Object obj) {\n        if (obj == this)\n            return true;\n        FavoriteFolder myEntity = (FavoriteFolder) obj;\n        return myEntity.id == this.id &amp;&amp; myEntity.name.equals(this.name) &amp;&amp; myEntity.status.equals(this.status) &amp;&amp; myEntity.hasCount == this.hasCount;\n    }\n    \/\/ ......\n}<\/code><\/pre>\n<h3>ListAdapter<\/h3>\n<pre><code class=\"language-java\">public class FavoriteFolderListAdapter extends ListAdapter&lt;FavoriteFolder, FavoriteFolderListAdapter.ItemViewHolder&gt; {\n\n    Context context;\n    boolean isModifyEnabled = false;\n    FavoriteFolderViewModel viewModel;\n\n    public FavoriteFolderListAdapter() {\n        super(FavoriteFolder.DIFF_CALLBACK);\n    }\n\n    public void setViewModel(FavoriteFolderViewModel viewModel) {\n        this.viewModel = viewModel;\n    }\n\n    public void setModifyEnabled(boolean modifyEnabled) {\n        isModifyEnabled = modifyEnabled;\n    }\n\n    @NonNull\n    @Override\n    public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n\n        context = parent.getContext();\n        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n        View view = inflater.inflate(R.layout.recyclerview_item_restaurant_add, parent, false);\n\n        return new ItemViewHolder(view);\n    }\n\n    @SuppressLint(&quot;DefaultLocale&quot;)\n    @Override\n    public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) {\n        FavoriteFolder myEntity = getItem(position);\n\n        holder.name.setText(myEntity.getName());\n        holder.hasCount.setText(String.format(&quot;%d\/%d&quot;, myEntity.getHasCount(), Constant.MAX_COUNT_IN_FOLDER));\n        holder.status.setText(myEntity.getStatus());\n\n        if (myEntity.getStatus().equals(context.getString(R.string.hidden))) {\n            holder.status.setTextColor(Color.parseColor(&quot;#0000FF&quot;));\n        } else {\n            holder.status.setTextColor(Color.parseColor(&quot;#000000&quot;));\n        }\n\n        if (isModifyEnabled) {\n            holder.modifyFolder.setVisibility(View.VISIBLE);\n            holder.deleteFolder.setVisibility(View.VISIBLE);\n        } else {\n            holder.modifyFolder.setVisibility(View.INVISIBLE);\n            holder.deleteFolder.setVisibility(View.INVISIBLE);\n        }\n    }\n\n    class ItemViewHolder extends RecyclerView.ViewHolder {\n        TextView name;\n        TextView hasCount;\n        TextView status;\n        ImageButton modifyFolder;\n        ImageButton deleteFolder;\n\n        ItemViewHolder(View itemView) {\n            super(itemView);\n\n            name = itemView.findViewById(R.id.restaurant_group_title);\n            hasCount = itemView.findViewById(R.id.restaurant_group_count);\n            status = itemView.findViewById(R.id.restaurant_group_status);\n\n            modifyFolder = itemView.findViewById(R.id.modify_folder);\n            deleteFolder = itemView.findViewById(R.id.delete_folder);\n\n            deleteFolder.setOnClickListener(v -&gt; deleteFolder(getLayoutPosition()));\n        }\n    }\n\n    private void deleteFolder(int position) {\n\n        AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(context, R.style.AlertDialogTheme));\n        builder.setMessage(R.string.warn_delete_folder);\n        builder.setCancelable(true);\n        builder.setPositiveButton(R.string.ok,\n                (dialog, id) -&gt; {\n                    dialog.cancel();\n                    viewModel.requestDelete(getItem(position).getId());\n                });\n        builder.setNegativeButton(R.string.cancel,\n                (dialog, id) -&gt; dialog.cancel());\n\n        AlertDialog alertDialog = builder.create();\n        alertDialog.show();\n    }\n}<\/code><\/pre>\n<h3>Fragment<\/h3>\n<p><code>adapter.submitList(favoriteFolders);<\/code> \uc5d0 \uc758\ud574,<br \/>\n\uae30\uc874 \ub9ac\uc2a4\ud2b8\uc640 \uc0c8\ub85c \uc804\ub2ec\ubc1b\uc740 \ub9ac\uc2a4\ud2b8\ub97c \ube44\uad50\ud558\uc5ec,<br \/>\n\ubcc0\uacbd\ub41c \ubd80\ubd84\ub9cc UI \ub9ac\ub85c\ub4dc\ud574\uc900\ub2e4.<\/p>\n<pre><code class=\"language-java\">public class RestaurantInfoAddBottomSheetFragment extends BottomSheetDialogFragment {\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n\n        appDataBase = ((RestaurantInfo) requireActivity()).getAppDataBase();\n\n        favoriteFolderViewModel = new ViewModelProvider(this).get(FavoriteFolderViewModel.class);\n        favoriteFolderViewModel.setAppDataBase(appDataBase);\n        adapter.setViewModel(favoriteFolderViewModel);\n        Observer&lt;ArrayList&lt;FavoriteFolder&gt;&gt; observer = favoriteFolders -&gt; {\n            if (favoriteFolders.size() == 0) {\n                FavoriteFolder item = new FavoriteFolder(\n                        getResources().getString(R.string.base_folder),\n                        getResources().getString(R.string.hidden),\n                        1);\n                favoriteFolderViewModel.requestInsert(item);\n\n                return;\n            }\n\n            \/\/ ListAdapter\uc758 submitList\ub294 \uae30\uc874 \ub370\uc774\ud130\uc640 \ube44\uad50\ud558\uc5ec \ubcc0\uacbd\ub41c \ubd80\ubd84\ub9cc \uc5c5\ub370\uc774\ud2b8 \uc2dc\ud0a8\ub2e4. (Differ \uc0ac\uc6a9)\n            adapter.submitList(favoriteFolders);\n        };\n        favoriteFolderViewModel.getFavoriteFolders().observe(this, observer);\n    }\n}<\/code><\/pre>\n<h2>Data Binding<\/h2>\n<p>Layout \ud30c\uc77c\uc758 \ucd5c\uc0c1\ub2e8\uc5d0 <code>layout<\/code> \uc744 \ucd94\uac00\ud55c\ub2e4.<\/p>\n<p><code>data<\/code> \ud0dc\uadf8\ub97c \ucd94\uac00\ud558\uace0 Entity \ub97c \ucd94\uac00\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-xml\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\n\n&lt;layout xmlns:android=&quot;http:\/\/schemas.android.com\/apk\/res\/android&quot;\n    xmlns:app=&quot;http:\/\/schemas.android.com\/apk\/res-auto&quot;&gt;\n\n    &lt;data&gt;\n        &lt;variable\n            name=&quot;item&quot;\n            type=&quot;kr.pe.skyer9.muglangguide.db.FavoriteFolder&quot;\/&gt;\n    &lt;\/data&gt;\n\n    &lt;androidx.constraintlayout.widget.ConstraintLayout\n        android:layout_width=&quot;match_parent&quot;\n        android:layout_height=&quot;wrap_content&quot;&gt;<\/code><\/pre>\n<p>Binding \ud074\ub798\uc2a4\uba85\uc740 Layout \ud30c\uc77c\uba85\uc5d0 Binding \uc744 \ubd99\uc5ec\uc8fc\ub294 \ud615\uc2dd\uc774\ub2e4.<\/p>\n<pre><code class=\"language-java\">View view = inflater.inflate(R.layout.favorite_folder_item, parent, false);\n\npublic FavoriteFolderItemBinding binding;<\/code><\/pre>\n<p><code>binding.setItem(favoriteFolder);<\/code> \ud574\uc8fc\ub294 \uac83\ub9cc\uc73c\ub85c \ud504\ub85c\uadf8\ub798\ubc0d\uc774 \ud544\uc694\uc5c6\ub294 \ub2e8\uc21c \ucf54\ub529\ub4e4\uc744 \uc0dd\ub7b5\ud560 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-java\">    @NonNull\n    @Override\n    public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n\n        context = parent.getContext();\n        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n        View view = inflater.inflate(R.layout.favorite_folder_item, parent, false);\n\n        return new ItemViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) {\n        FavoriteFolder favoriteFolder = getItem(position);\n        if(favoriteFolder != null) {\n            holder.onBind(favoriteFolder);\n        }\n    }\n\n    class ItemViewHolder extends RecyclerView.ViewHolder {\n\n        public FavoriteFolderItemBinding binding;\n\n        ItemViewHolder(View itemView) {\n            super(itemView);\n            binding = DataBindingUtil.bind(itemView);\n        }\n\n        @SuppressLint(&quot;DefaultLocale&quot;)\n        void onBind(FavoriteFolder favoriteFolder) {\n            binding.setItem(favoriteFolder);\n\n            binding.restaurantGroupCount.setText(String.format(&quot;%d\/%d&quot;, favoriteFolder.getHasCount(), Constant.MAX_COUNT_IN_FOLDER));\n            if (favoriteFolder.getStatus().equals(context.getString(R.string.hidden))) {\n                binding.restaurantGroupStatus.setTextColor(Color.parseColor(&quot;#0000FF&quot;));\n            } else {\n                binding.restaurantGroupStatus.setTextColor(Color.parseColor(&quot;#000000&quot;));\n            }\n\n            if (isModifyEnabled) {\n                binding.modifyFolder.setVisibility(View.VISIBLE);\n                binding.deleteFolder.setVisibility(View.VISIBLE);\n            } else {\n                binding.modifyFolder.setVisibility(View.INVISIBLE);\n                binding.deleteFolder.setVisibility(View.INVISIBLE);\n            }\n\n            binding.deleteFolder.setOnClickListener(v -&gt; deleteFolder(getLayoutPosition()));\n        }\n    }<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Android MVVM (AAC) LiveData RecyclerView \ucc38\uc870 build.gradle android { \/\/ &#8230;&#8230; dataBinding { enabled = true } } ViewModel \uc0dd\uc131 ViewModel \uc744 \uc0dd\uc131\ud55c\ub2e4. MutableLiveData \ub97c \uc0dd\uc131\ud558\uba74, MutableLiveData \uc758 \ub370\uc774\ud0c0\uac00 \ubcc0\uacbd\uc2dc \uc774\ubca4\ud2b8\uac00 \ubc1c\uc0dd\ud55c\ub2e4. \ub2e8\uc21c\ud788 \uc774\ubca4\ud2b8\ub97c \ubc1c\uc0dd\uc2dc\ud0a4\ub294\uac8c \uc544\ub2c8\ub77c, Lifecycle \uc5d0 \ub9de\ucdb0\uc11c \ubc1c\uc0dd\uc2dc\ud0a8\ub2e4. \uc774\ubca4\ud2b8 \ubc1c\uc0dd\uc774 \ud65c\uc131\uc0c1\ud0dc(started, resumed)\ub85c \uc9c0\uc5f0\ub418\ub294 \uac83\uc774 \uc544\ub2c8\ub77c, \ub370\uc774\ud0c0 \uc5c5\ub370\uc774\ud2b8 \uc790\uccb4\uac00 \ud65c\uc131\uc0c1\ud0dc\ub85c \uc9c0\uc5f0\ub41c\ub2e4. \ub530\ub77c\uc11c, \uc571\uc774 \ubc31\uadf8\ub77c\uc6b4\ub4dc\uc5d0\uc11c\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=3877\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[32],"tags":[],"class_list":["post-3877","post","type-post","status-publish","format-standard","hentry","category-android"],"_links":{"self":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/3877","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3877"}],"version-history":[{"count":14,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/3877\/revisions"}],"predecessor-version":[{"id":3916,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/3877\/revisions\/3916"}],"wp:attachment":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3877"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3877"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3877"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}