🟨 목 차 🟨
1. 앨범에서 사진 가져오기
1-1. 앨범 접근하기(Permission)
1-2. 앨범에서 사진 가져오기(onActivityResult)
1-3. 가져온 앨범 사진들의 리사이클러뷰 Adapter 작성
1-4. 앨범에서 가져온 이미지와 리사이클러뷰 연동하기
2. 상품 등록 버튼을 누르면 입력한 데이터( 앨범에서 가져온 사진, 제목, 선택한 카테고리, 가격, 현재 위치에 의해 설정된 지역, 게시글 내용) 공통으로 쓰는 상품 정보( static arraylist[arrayList33] )에 추가하기
2-1. 상품 데이터 저장 공간(Trade_RecyclerProductData.java)
2-2. 상품 데이터
2-2-1. 제목, 가격 게시글 데이터 가져오기
2-2-2. 상품 카테고리 만들기(Spinner)
2-2-3. 상품 카테고리(Spinner가 선택된 값) 데이터 가져오기
2-2-4. 선택된 사진 데이터 가져오기
2-2. 상품 데이터 저장 공간(Trade_RecyclerProductData.java)의 생성자를 이용하여 객체를 생성한다.
3. 상품 등록 버튼을 누른 정보를 바탕으로 상품 목록 생성하기(Fragment1.java)
3-1. 물품 등록을 보여주는 리사이클러뷰의 어댑터( Trade_RecyclerProductAdapter.jave )
3-1-1. 물품 등록을 보여주는 리사이클러뷰의 어댑터의 좋아요 구현
3-1-2. 물품 등록을 보여주는 리사이클러뷰의 어댑터의 가장 인기있는 물품을 주기적으로 Toast로 띄우는 기능 구현
중고거래 앱 프로젝트를 진행하면서 당연한 기능으로 상품 등록 기능을 만들었다.
만든 기능들을 간략히 말해보자면 사진, 상품 제목, 상품 카테고리, 가격, 지역(구글 Map API를 통한 현재 위치 값), 상품 내용에 관해 입력을 하고 등록을 완료 버튼을 누르게 되면 홈으로 나가지면서 물품 등록된 정보들이 리사이클러뷰를 통해 표현된다.(단, 지역 정보를 저장할때 현재 위치를 제공하지 않으면(구글 Map API를 이용하기 위한 Permission의 유무) 지역없음이라고 자동으로 저장된다.)
리사이클러뷰에 데이터를 저장하는것 전에 해야 할 일은 데이터를 입력을 하는 것 이다. 내가 데이터를 입력을 해야하는 것은 사진, 상품 제목, 상품 카테고리, 가격, 상품 내용의 값들이다. 차근차근 이 값들을 입력해 데이터로 가져오는것을 알아보자.
◼️ 1. 앨범에서 사진 가져오기 ◼️
사진 같은 경우에는 기기 앨범에서 사진을 가져오고 잘못 가져온 사진은 삭제할 수 있는 기능을 만들어보았다. 사진을 여러장 가져올 수 있으므로 이 부분은 recyclerview를 이용하여 가져오려는 사진의 수만큼 가져오고, 잘못 가져온 사진에 대해 삭제 버튼을 누르면 사진을 지울 수 있다.
◼️ 1-1. 앨범 접근하기(Permission)
우선적으로 앨범에서 사진을 가져올 수 있게 하기 위해서는 매니페스트에서 퍼미션을 추가해주고 사용자가 퍼미션의 허용 유무에 따른 예외 처리를 해주고 그 다음으로 recyclerview 어댑터를 이용하여 사진 여러장을 표현한다.
camera.setOnClickListener(new View.OnClickListener() { //카메라 이미지를 클릭했을때
@Override
public void onClick(View view) {
//퍼미션(허용)을 checkSelfPermission()메소드를 이용하여 내가 원하는 퍼미션인 READ_EXTERNAL_STORAGE(앨범) 접근이 PackageManager을 통해 PERMISSION_GRANTED(허용)인 지 아닌지 검사합니다.
if(ContextCompat.checkSelfPermission(Sell_Form.this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
//앨범 접근이 true 일때
Intent intent = new Intent(Intent.ACTION_PICK); //인텐트를 통해 앨범에 접근한다.
intent.setType(MediaStore.Images.Media.CONTENT_TYPE);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 2222);
//startActiviy가 아닌 startActivityForResult를 사용한 이유는 앨범에서 사진을 선택하고
//앨범이 닫히면서 선택한 사진 정보가 전달되는데 이것을 연동하는 부분이 onActivityResult에서 하기 때문이다.
}
else {
AlertDialog.Builder dlg = new AlertDialog.Builder(Sell_Form.this); //AlertDialog 객체 생성
dlg.setTitle("권한이 필요합니다."); //다이얼로그 제목
dlg.setMessage("갤러리 접근 권한이 필요합니다."); //다이얼로그 내용
dlg.setPositiveButton("동의하기", new DialogInterface.OnClickListener() { //다이얼로그의 동의하기 버튼을 클릭했을때
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(Sell_Form.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},2222);
//requestPermissions()메소드를 통해 READ_EXTERNAL_STORAGE(앨범) 퍼미션을 허용한다.
}
});
dlg.setNegativeButton("취소하기", new DialogInterface.OnClickListener() { //다이얼로그의 취소하기 버튼을 클릭했을때
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dlg.create(); //다이얼로그 생성
dlg.show(); //다이얼로그 실행
}
}
});
◼️ 1-2. 앨범에서 사진 가져오기(onActivityResult)
앨범이 닫히면서 선택한 사진들의 사진 정보가 전달되는데 이것을 연동하는 부분이 onAcitivyResult 에서 한다.
// 앨범에서 액티비티로 돌아온 후 실행되는 메서드
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
complete = findViewById(R.id.complete);
mFirebaseAuth = FirebaseAuth.getInstance();
mDatabaseRef = FirebaseDatabase.getInstance().getReference("shopproject");
super.onActivityResult(requestCode, resultCode, data);
if(data == null){ // 어떤 이미지도 선택하지 않은 경우
Toast.makeText(getApplicationContext(), "이미지를 선택하지 않았습니다.", Toast.LENGTH_LONG).show();
}
else{ // 이미지를 하나라도 선택한 경우
if(data.getClipData() == null){ // 이미지를 하나만 선택한 경우
Log.e("single choice: ", String.valueOf(data.getData()));
Uri imageUri = data.getData();
uriList.add(imageUri);
}
else{ // 이미지를 여러장 선택한 경우
ClipData clipData = data.getClipData();
Log.e("clipData", String.valueOf(clipData.getItemCount()));
if(clipData.getItemCount() > 10){ // 선택한 이미지가 11장 이상인 경우
Toast.makeText(getApplicationContext(), "사진은 10장까지 선택 가능합니다.", Toast.LENGTH_LONG).show();
}
else{ // 선택한 이미지가 1장 이상 10장 이하인 경우
Log.e(TAG, "multiple choice");
for (int i = 0; i < clipData.getItemCount(); i++){
String a = String.valueOf(i);
Uri imageUri = clipData.getItemAt(i).getUri(); // 선택한 이미지들의 uri를 가져온다.
String strUri = imageUri.toString();
image_data.add(strUri);
StorageReference sotrageRef = storage.getReference();
StorageReference riversRef = sotrageRef.child(mFirebaseAuth.getUid()).child(a);
UploadTask uploadTask = riversRef.putFile(imageUri);
try {
uriList.add(imageUri); //uri를 list에 담는다.
uriList2.add(imageUri);
} catch (Exception e) {
Log.e(TAG, "File select error", e);
}
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),imageUri);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG,100,stream);
byte[] reviewImage = stream.toByteArray();
String simage = byteArrayToBinaryString(reviewImage);
product_information.setProduct_image(simage);
} catch (IOException e) {
e.printStackTrace();
}
recyclerView.removeAllViewsInLayout();
itemRefresh();
complete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String product_price1 = price.getText().toString().trim();
String product_title1 = product_title.getText().toString().trim();
String product_category1 = product_category.getSelectedItem().toString().trim();
String product_content1 = product_content.getText().toString().trim();
product_info.setProduct_title(product_title1);
product_info.setPrice(product_price1);
product_info.setSpinner(product_category1);
product_info.setProduct_content(product_content1);
arrayList33.add(new Trade_RecyclerProductData(Integer.toString(cc),product_info.getImage_url(),R.drawable.heart_black,R.drawable.heart_red ,"0",product_title1,product_price1,loction.getText().toString().trim(),product_content1,product_info.getSpinner(),product_title1,image_data,image_data.toString(),Integer.toString(0),loction.getText().toString().trim()));
cc++;
info_data = new Trade_RecyclerProductData(Integer.toString(cc),product_info.getImage_url(),R.drawable.heart_black,R.drawable.heart_red, "0",product_title1,product_price1,loction.getText().toString().trim(),product_content1,product_info.getImage_url(),product_title1,ss,image_data.toString(),Integer.toString(0),loction.getText().toString().trim());
mDatabaseRef.child(info_data.getProduct_name()).setValue(info_data);
recyclerProductAdapter.notifyDataSetChanged();
finish();
}
});
}
}
}
}
aContext = this;
}
◼️ 1-3. 가져온 앨범 사진들의 리사이클러뷰 Adapter 작성
앨범 사진 리사이클러뷰 Adapter와 연결한 xml 코드.(사진이 들어갈 ImageView 와 삭제를 누르면 사진이 삭제 될 Button 구성)
<multiImageAdapter.xml>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="120dp"
android:orientation="vertical">
<ImageView
android:id="@+id/image"
android:layout_width="100dp"
android:layout_height="75dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:scaleType="center"
android:layout_marginHorizontal="5dp"/>
<Button
android:id="@+id/image_del"
android:layout_width="70dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:text="삭제"
android:textSize="8dp">
</Button>
</LinearLayout>
앨범 사진을 리사이클러뷰에 등록할 어댑터의 대략적인 흐름은 객체 생성시 전달받은 list 객체에 들어있는 Uri 정보를 Glide 라이브러리를 통해 보여준다.
(Gilde 라이브러리를 사용하기 위해선 build.gradle(Module)에 implementation 'com.github.bumptech.glide:glide:4.11.0' 를 추가해준다.
<MultImageAdapter.java>
package com.example.shopproject;
import static com.example.shopproject.Sell_Form.product_info;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import java.util.ArrayList;
public class MultiImageAdapter extends RecyclerView.Adapter<MultiImageAdapter.ViewHolder>{
private ArrayList<Uri> mData = null ;
private Context mContext = null ;
private FirebaseAuth mFirebaseAuth;
private DatabaseReference mDatabaseRef;
// 생성자에서 데이터 리스트 객체, Context를 전달받음.
MultiImageAdapter(ArrayList<Uri> list, Context context) {
mData = list ;
mContext = context;
}
// 아이템 뷰를 저장하는 뷰홀더 클래스.
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView image;
Button image_del;
ViewHolder(View itemView) {
super(itemView) ;
// 뷰 객체에 대한 참조.
image = itemView.findViewById(R.id.image);
image_del = itemView.findViewById(R.id.image_del);
}
}
// onCreateViewHolder() - 아이템 뷰를 위한 뷰홀더 객체 생성하여 리턴.
// LayoutInflater - XML에 정의된 Resource(자원) 들을 View의 형태로 반환.
@Override
public MultiImageAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext() ;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) ; // context에서 LayoutInflater 객체를 얻는다.
View view = inflater.inflate(R.layout.multi_image_item, parent, false) ; // 리사이클러뷰에 들어갈 아이템뷰의 레이아웃을 inflate.
MultiImageAdapter.ViewHolder vh = new MultiImageAdapter.ViewHolder(view) ;
return vh ;
}
// onBindViewHolder() - position에 해당하는 데이터를 뷰홀더의 아이템뷰에 표시.
@Override
public void onBindViewHolder(MultiImageAdapter.ViewHolder holder, int position) {
mFirebaseAuth = FirebaseAuth.getInstance();
mDatabaseRef = FirebaseDatabase.getInstance().getReference("shopproject");
Uri image_uri = mData.get(position) ; //어댑터 객체 생성할때 생성자를 이용하여 mdata를 이용하여 사진 Uri를 가져온다.
String product_info_setImageUrl = image_uri.toString();
product_info.setImage_url(product_info_setImageUrl);
Glide.with(mContext)
.load(image_uri)
.into(holder.image); //Glide()메소드를 이용하여 image_uri를 holder(뷰 객체에 대한 참조)의 image에 넣는다.
holder.image_del.setOnClickListener(new View.OnClickListener() { //holder의 image_del(버튼)을 클릭하면
@Override
public void onClick(View v) {
mData.remove(position); // 각 위치에 대한 mdata(정보)를 삭제한다.
notifyItemRemoved(position);
notifyItemRangeRemoved(position,mData.size()-position);
Uri image_uri = mData.get(position);
String product_info_setImageUrl = image_uri.toString();
product_info.setImage_url(product_info_setImageUrl);
}
});
}
// getItemCount() - 전체 데이터 갯수 리턴.
@Override
public int getItemCount() {
return mData.size() ;
}
}
◼️ 1-4. 앨범에서 가져온 이미지와 리사이클러뷰 연동하기
RecyclerView recyclerView; // 이미지를 보여줄 리사이클러뷰
MultiImageAdapter adapter; // 리사이클러뷰에 적용시킬 어댑터
recyclerView = findViewById(R.id.image_recyclerview);
recyclerView.setHasFixedSize(true);
adapter = new MultiImageAdapter(uriList, getApplicationContext());
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true)); // 리사이클러뷰 수평 스크롤 적용
MultiIamgeAdapter의 생성자를 이용하여 uriList, Context를 변수로 넣어주고 adapter를 생성하고 생성한 어댑터를 만든 recyclerView에 setAdapter(연동한다) 그 후 리스트의 크기와 아이템이 둘 다 변경되기 때문에 notifyDataSetChatged() 메소드를 adapter에 적용시켜준다.
[ 참고 : https://todaycode.tistory.com/55 ]
◼️ 2. 상품 등록 버튼을 누르면 입력한 데이터
(앨범에서 가져온 사진, 제목, 선택한 카테고리, 가격, 현재 위치에 의해 설정된 지역, 게시글 내용)
공통으로 쓰는 상품 정보(static arraylist[arrayList33])에 추가하기 ◼️
상품정보인 앨범에서 가져온 사진, 제목, 선택한 카테고리, 가격, 현재 위치에 의해 설정된 지역, 게시글 내용 들을 등록 버튼을 누르면
공통으로 쓰는 상품 정보(static arraylist)에 add(추가가 된다)된다. (향후에 이 공통으로 쓰는 상품 정보(static arraylist)들의 데이터는 등록한 상품을 보여주는 리사이클러뷰에 이용이 된다.)
complete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String product_price1 = price.getText().toString().trim();
String product_title1 = product_title.getText().toString().trim();
String product_content1 = product_content.getText().toString().trim();
String product_category1 = product_category.getSelectedItem().toString().trim();
product_info.setProduct_title(product_title1);
product_info.setPrice(product_price1);
product_info.setSpinner(product_category1);
product_info.setProduct_content(product_content1);
arrayList33.add(new Trade_RecyclerProductData(Integer.toString(cc),product_info.getImage_url(),R.drawable.heart_black,R.drawable.heart_red ,"0",product_title1,product_price1,loction.getText().toString().trim(),product_content1,product_info.getSpinner(),product_title1,image_data,image_data.toString(),Integer.toString(0),loction.getText().toString().trim()));
cc++;
info_data = new Trade_RecyclerProductData(Integer.toString(cc),product_info.getImage_url(),R.drawable.heart_black,R.drawable.heart_red, "0",product_title1,product_price1,loction.getText().toString().trim(),product_content1,product_info.getImage_url(),product_title1,ss,image_data.toString(),Integer.toString(0),loction.getText().toString().trim());
mDatabaseRef.child(info_data.getProduct_name()).setValue(info_data);
recyclerProductAdapter.notifyDataSetChanged();
finish();
}
});
완료를 클릭 했을 때의 코드들이다. 중요한 것은 arrayList33인데 이 arrayList는 Trade_RecyclerProductData의 정보를 담고 있고 이것은 static(전역 변수)이기 때문에 향후 상품 등록한 제품을 보여줄 리시클러뷰에 사용될 것이다.
◼️ 2-1. 상품 데이터 저장 공간(Trade_RecyclerProductData.java)
입력한 상품 데이터를 저장하기 위한 Trade_RecyclerProductData 클래스를 만들어 이 클래스에는 상품 데이터들을 이용하기 위한 변수들과 get,set 메소드들을 구현하고 여기서 저장하고 꺼내쓴다.
<Trade_RecyclerProductData.java>
package com.example.shopproject;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
public class Trade_RecyclerProductData extends RecyclerView.Adapter {
private String product_count;
private String product_image;
private int product_heart_black_image;
private int product_heart_red_image;
private String product_heart_count;
private String product_name;
private String product_price;
private String product_city;
private String product_content;
private String product_category;
private String product_image_url;
private ArrayList product_image_urls;
private String product_imageurls;
private String click_count;
private String product_location;
public Trade_RecyclerProductData(String product_count, String product_image, int product_heart_black_image, int product_heart_red_image, String product_heart_count, String product_name, String product_price, String product_city, String product_content, String product_category, String product_image_url, ArrayList product_image_urls, String product_imageurls, String click_count, String product_location) {
this.product_count = product_count;
this.product_image = product_image;
this.product_heart_black_image = product_heart_black_image;
this.product_heart_red_image = product_heart_red_image;
this.product_heart_count = product_heart_count;
this.product_name = product_name;
this.product_price = product_price;
this.product_city = product_city;
this.product_content = product_content;
this.product_category = product_category;
this.product_image_url = product_image_url;
this.product_image_urls = product_image_urls;
this.product_imageurls = product_imageurls;
this.click_count = click_count;
this.product_location = product_location;
}
public int getProduct_heart_red_image() {
return product_heart_red_image;
}
public void setProduct_heart_red_image(int product_heart_red_image) {
this.product_heart_red_image = product_heart_red_image;
}
public String getProduct_location() {
return product_location;
}
public void setProduct_location(String product_location) {
this.product_location = product_location;
}
public String getClick_count() {
return click_count;
}
public void setClick_count(String click_count) {
this.click_count = click_count;
}
public String getProduct_imageurls() {
return product_imageurls;
}
public void setProduct_imageurls(String product_imageurls) {
this.product_imageurls = product_imageurls;
}
public ArrayList getProduct_image_urls() {
return product_image_urls;
}
public void setProduct_image_urls(ArrayList product_image_urls) {
this.product_image_urls = product_image_urls;
}
public String getProduct_content() {
return product_content;
}
public void setProduct_content(String product_content) {
this.product_content = product_content;
}
public String getProduct_category() {
return product_category;
}
public void setProduct_category(String product_category) {
this.product_category = product_category;
}
public String getProduct_image_url() {
return product_image_url;
}
public void setProduct_image_url(String product_image_url) {
this.product_image_url = product_image_url;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return 0;
}
public String getProduct_count() {
return product_count;
}
public void setProduct_count(String product_count) {
this.product_count = product_count;
}
public String getProduct_image() {
return product_image;
}
public void setProduct_image(String product_image) {
this.product_image = product_image;
}
public int getProduct_heart_black_image() {
return product_heart_black_image;
}
public void setProduct_heart_black_image(int product_heart_black_image) {
this.product_heart_black_image = product_heart_black_image;
}
public String getProduct_heart_count() {
return product_heart_count;
}
public void setProduct_heart_count(String product_heart_count) {
this.product_heart_count = product_heart_count;
}
public String getProduct_name() {
return product_name;
}
public void setProduct_name(String product_name) {
this.product_name = product_name;
}
public String getProduct_price() {
return product_price;
}
public void setProduct_price(String product_price) {
this.product_price = product_price;
}
public String getProduct_city() {
return product_city;
}
public void setProduct_city(String product_city) {
this.product_city = product_city;
}
}
◼️ 2-2. 상품 데이터
위의 Trade_RecyclerProductData.java의 객체(상품 데이터)를 만들어 set(arraylist에 보관하기) 위해서 일단 보관할 데이터(상품데이터)를 만들어야한다.
보관하기에 앞서서 먼저 앨범에서 가져온 사진, 제목, 선택한 카테고리, 가격, 현재 위치에 의해 설정된 지역, 게시글 내용 의 상품데이터를 가져와야한다.
◼️ 2-2-1. 제목, 가격 게시글 데이터 가져오기 ◼️
그 중 제목, 가격 게시글 내용은 내가 입력한 EditText에서 입력한 데이터를 가져오는 방식(getText()메소드를 이용)을 취한다.
private EditText product_title, product_content,price ;
product_title = findViewById(R.id.product_title);
price = findViewById(R.id.price);
product_content = findViewById(R.id.product_content);
String product_price1 = price.getText().toString().trim();
String product_title1 = product_title.getText().toString().trim();
String product_content1 = product_content.getText().toString().trim();
그 중 상품 카테고리는 Spinner 이며 만드는 방법은 Adapter를 이용한다.
◼️ 2-2-2. 상품 카테고리 만들기(Spinner) ◼️
< strings3.xml ( Spinner 사용 될 아이템,res-values-string3 ) >
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="shopproject1"> </string>
<string-array name="category">
<item>
- 카테고리를 선택해주세요 -
</item>
<item>
가방
</item>
<item>
옷
</item>
<item>
신발
</item>
<item>
가전제품
</item>
<item>
생필품
</item>
</string-array>
</resources>
< simple_spinner_item.xml( Spinner가 표현 될 xml ) >
<?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
style="?android:attr/spinnerItemStyle"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:textAlignment="inherit"/>
<Spinner 사용 될 activity>
private Spinner product_category;
product_category = findViewById(R.id.product_category);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,R.array.category,android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
product_category.setAdapter(adapter);
product_category.setOnItemSelectedListener(this);
◼️ 2-2-3. 상품 카테고리(Spinner가 선택된 값) 데이터 가져오기 ◼️
String product_category1 = product_category.getSelectedItem().toString().trim();
◼️ 2-2-4. 선택된 사진 데이터 가져오기◼️
사진의 경우 1개의 데이터가 아니라 여러개의 데이터가 있을 수 있으므로 ArrayList로 따로 이미지 보관함을 만들고 / 앨범에서 선택하여 화면에 띄어줄때(onActivityResult)에 사진의 값을 따로 만든 ArrayList에 보관한다.
(static(전역 변수) 이므로 onCreate 가 될 때 image_data 객체를 초기화 시켜줘야한다.(image_data.clear();)
static ArrayList image_data = new ArrayList();
Uri imageUri = clipData.getItemAt(i).getUri(); // 선택한 이미지들의 uri를 가져온다.
String strUri = imageUri.toString();
image_data.add(strUri);
◼️ 2-2. 상품 데이터 저장 공간(Trade_RecyclerProductData.java)의 생성자를 이용하여 객체를 생성한다.
public Trade_RecyclerProductData(String product_count, String product_image, int product_heart_black_image, int product_heart_red_image, String product_heart_count, String product_name, String product_price, String product_city, String product_content, String product_category, String product_image_url, ArrayList product_image_urls, String product_imageurls, String click_count, String product_location) {
this.product_count = product_count;
this.product_image = product_image;
this.product_heart_black_image = product_heart_black_image;
this.product_heart_red_image = product_heart_red_image;
this.product_heart_count = product_heart_count;
this.product_name = product_name;
this.product_price = product_price;
this.product_city = product_city;
this.product_content = product_content;
this.product_category = product_category;
this.product_image_url = product_image_url;
this.product_image_urls = product_image_urls;
this.product_imageurls = product_imageurls;
this.click_count = click_count;
this.product_location = product_location;
}
위는 Trade_RecyclerProductData의 생성자이다.
static ArrayList<Trade_RecyclerProductData> arrayList33 = new ArrayList<>();
arrayList33.add(new Trade_RecyclerProductData(Integer.toString(cc),product_info.getImage_url(),R.drawable.heart_black,R.drawable.heart_red ,"0",product_title1,product_price1,loction.getText().toString().trim(),product_content1,product_info.getSpinner(),product_title1,image_data,image_data.toString(),Integer.toString(0),loction.getText().toString().trim()));
위는 static arraylist인 arrayList33에 Trade_RecyclerProductData의 생성자를 이용해 상품의 데이터 값들을 add(추가 해준다.)
(arrayList33 는 Trade_RecyclerProductData의 생성자를 이용한 객체 arraylist 이고 상품을 등록했을때 물품 목록을 보여주는 리사이클러뷰 어댑터의 생성자의 변수로 이용이 된다.)
◼️ 3. 상품 등록 버튼을 누른 정보를 바탕으로 상품 목록 생성하기(Fragment1.java) ◼️
◼️ 3-1. 물품 등록을 보여주는 리사이클러뷰의 어댑터( Trade_RecyclerProductAdapter.jave )
public class Trade_RecyclerProductAdapter extends RecyclerView.Adapter<Trade_RecyclerProductAdapter.ViewHolder> {
private ArrayList<Trade_RecyclerProductData> arrayList; //데이터 ArrayList 생성
private Context aContext; //Context 값을 aContext 이름 설정
private ArrayList image_arrayList;
static int max;
public Trade_RecyclerProductAdapter(Context context, ArrayList<Trade_RecyclerProductData> arrayList, ArrayList image_arrayList) { //Trade_RecyclerProductAdapter의 생성자[Context, ArrayList<Trade_RecyclerProductData> arrayList, ArrayList image_arrayList] 의 변수를 넣어줘야한다.
this.aContext = context;
this.arrayList = arrayList;
this.image_arrayList = image_arrayList;
}
Trade_RecyclerProductAdapter는 RecyclerView.Adapter를 상속받고 ViewHolder를 구현해야한다.
위의 코드는 초기 변수 생성과 생성자를 설정해주었다.
public class ViewHolder extends RecyclerView.ViewHolder{ //내가 이름을 정한 ViewHolder는 RecyclerView.ViewHolder를 상속받아 생성한다.
//데이터 xml에 대한 각 항목들을 연결 시켜주기 위해 미리 변수들을 만들어 타입을 지정해 준다.
protected TextView product_count;
protected ImageView product_image;
protected ImageView product_heart_black_image;
protected TextView product_heart_count;
protected TextView product_name;
protected TextView product_price;
protected TextView product_location;
protected TextView product_category;
protected TextView product_image_urls;
protected TextView product_content;
protected TextView click_count;
protected ImageView heart_red;
public ImageView getHeart_red() {
return heart_red;
}
public void setHeart_red(ImageView heart_red) {
this.heart_red = heart_red;
}
public TextView getProduct_count() {
return product_count;
}
public void setProduct_count(TextView product_count) {
this.product_count = product_count;
}
public ImageView getProduct_image() {
return product_image;
}
public void setProduct_image(ImageView product_image) {
this.product_image = product_image;
}
public ImageView getProduct_heart_black_image() {
return product_heart_black_image;
}
public void setProduct_heart_black_image(ImageView product_heart_black_image) {
this.product_heart_black_image = product_heart_black_image;
}
public TextView getProduct_heart_count() {
return product_heart_count;
}
public void setProduct_heart_count(TextView product_heart_count) {
this.product_heart_count = product_heart_count;
}
public TextView getProduct_name() {
return product_name;
}
public void setProduct_name(TextView product_name) {
this.product_name = product_name;
}
public TextView getProduct_price() {
return product_price;
}
public void setProduct_price(TextView product_price) {
this.product_price = product_price;
}
public TextView getProduct_location() {
return product_location;
}
public void setProduct_location(TextView product_location) {
this.product_location = product_location;
}
public ViewHolder(@NonNull View itemView) {
super(itemView);
//데이터 xml에 대한 각 항목들을 연결 시켜주기 위해 미리 변수들을 만들어 놓은것과 데이터 xml에 대한 각 항목들을 연결시켜준다.
this.product_count = (TextView) itemView.findViewById(R.id.product_count);
this.product_image =(ImageView) itemView.findViewById(R.id.product_image);
this.product_heart_black_image =(ImageView) itemView.findViewById(R.id.heart_black_image);
this.heart_red = (ImageView) itemView.findViewById(R.id.heart_red);
this.product_heart_count = (TextView) itemView.findViewById(R.id.heart_count);
this.product_name = (TextView) itemView.findViewById(R.id.product_name);
this.product_price = (TextView) itemView.findViewById(R.id.product_price);
this.product_location = (TextView) itemView.findViewById(R.id.product_location);
this.product_category = (TextView) itemView.findViewById(R.id.adapter_category);
this.product_content = (TextView) itemView.findViewById(R.id.adapter_content);
this.product_image_urls = (TextView) itemView.findViewById(R.id.adapter_image_urls);
}
}
위의 코드는 상속받을 Viewholder를 구현한 코드이다. RecyclerView.ViewHolde를 상속받아 구현하였고 이름은 ViewHolder로 설정하였다. 또한 데이터 xml에 대한 각 항목들을 연결 시켜주기 위해 미리 변수들을 만들어 타입을 지정해준다.
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { //뷰홀더 생성될때
Context context = parent.getContext();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); //XML에 미리 정의해둔 틀을 실제 메모리에 올려주는 역할인 LayoutInflater를 사용한다.
View view = inflater.inflate(R.layout.trade_recyclerview_data, parent, false); // trade_recyclerview_data 라는 xml과 연결해준다.
Trade_RecyclerProductAdapter.ViewHolder holder = new Trade_RecyclerProductAdapter.ViewHolder(view); // new Trade_RecyclerProductAdapter.ViewHolder(view)를 통해 각각의 목록에 접근가능한 holder를 생성한다.
return holder; //holder(리사이클러뷰의 데이터) 값을 반환 받는다.
}
위의 코드는 뷰홀더가 생성될 때의 코드이다.
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, @SuppressLint("RecyclerView") int position) {
//holder(리사이클러뷰의 데이터)들의 각각의 부분에 대해서 내용을 채워준다.
// < arrayList의 위치를 참조받고 거기서 각각의 get함수의 대한 내용을 얻어온다. >
holder.product_count.setText(Integer.toString(Integer.parseInt(arrayList.get(position).getProduct_count()) + 1)); //holder.product_count(물품 등록 수)에 생성자를 통한 arrayList.get(position).getProduct_count())을 이용하여 값을 넣는다.
holder.product_image.setVisibility(View.VISIBLE); //holder.product_image의 이미지를 보이게 설정
Glide.with(holder.itemView).load(arrayList.get(position).getProduct_image()).placeholder(R.drawable.camera)
.error(R.drawable.heart_red)
.fallback(R.drawable.heart_black)
.into(holder.product_image);
//Glide 함수를 통해 holder.itemView의 into(holder.product_image)에
//load(이미지 값(url[arrayList.get(position).getProduct_image()]))을 넣는다
//또한 placeholder(로딩 중일때는 R.drawble.camera 값)을 넣고 오류(error 일때는 R.drawable.heart_red의 값을 넣고)
//또한 fallback(null 값일 때는 R.drawable.heart_black)을 넣는다.
holder.product_name.setText(arrayList.get(position).getProduct_name()); //holder.product_name(물품 제목)에 생성자를 통한 arrayList.get(position).getProduct_name())을 이용하여 값을 넣는다.
holder.product_heart_black_image.setImageResource(arrayList.get(position).getProduct_heart_black_image());
//holder.product_heart_black_image(물품의 좋아요 사진(검은색하트)에 생성자를 통한 arrayList.get(position).getProduct_heart_black_image())을 setImageResource()를 이용하여 값을 넣는다.
holder.heart_red.setImageResource(arrayList.get(position).getProduct_heart_red_image());
//holder.product_heart_black_image(물품의 좋아요 사진(빨간색)에 생성자를 통한 arrayList.get(position).getProduct_heart_red_image())을 setImageResource()를 이용하여 값을 넣는다.(이 값은 실제로 공간이 있는 값이 아니라 빨간 하트를 가져오기 위한 참조 값이다. xml 파일에서 android:visibility="gone" 설정.)
Drawable blackheart = holder.product_heart_black_image.getDrawable(); //holder.product_heart_black_image에 들어간 검정색 하트 Url 형식을 Drawable 형식으로 만들기
Drawable redheart = holder.heart_red.getDrawable(); //holder.product_heart_black_image에 들어간 검정색 하트 Url 형식을 Drawable 형식으로 만들기
//참고 : https://www.masterqna.com/android/24619/imageview%EC%97%90-src%EB%A1%9C-%EB%84%A3%EC%9D%80-%EC%9D%B4%EB%AF%B8%EC%A7%80%EC%99%80-%EB%8B%A4%EB%A5%B8-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B9%84%EA%B5%90-%EC%A7%88%EB%AC%B8%EC%9E%85%EB%8B%88%EB%8B%A4
holder.product_heart_count.setText(arrayList.get(position).getProduct_heart_count());//holder.product_heart_count(물품 좋아요 수)에 생성자를 통한 arrayList.get(position).getProduct_heart_count())을 이용하여 값을 넣는다.
holder.product_location.setText(arrayList.get(position).getProduct_location()); //holder.product_location(물품 사용자 위치)에 생성자를 통한 arrayList.get(position).getProduct_location())을 이용하여 값을 넣는다.
//holder.product_city.setText(arrayList.get(position).getProduct_city());
holder.product_price.setText(arrayList.get(position).getProduct_price()+"원"); //holder.product_price(물품 가격)에 생성자를 통한 arrayList.get(position).getProduct_price())을 이용하여 값을 넣는다.
holder.product_category.setText(arrayList.get(position).getProduct_category().toString()); //holder.product_category(물품 카테고리)에 생성자를 통한 arrayList.get(position).getProduct_category())을 이용하여 값을 넣는다.
holder.product_content.setText(arrayList.get(position).getProduct_content().toString()); //holder.product_category(물품 카테고리)에 생성자를 통한 arrayList.get(position).getProduct_category())을 이용하여 값을 넣는다.
holder.product_image_urls.setText(arrayList.get(position).getProduct_imageurls().toString()); //holder.product_image_urls(물품 카테고리)에 생성자를 통한 arrayList.get(position).getProduct_imageurls())을 이용하여 값을 넣는다.
max = Integer.parseInt(arrayList.get(0).getProduct_count()); //max(최대값)은 arrayList.get(0).getProduct_count()을 고정값이다.
for(int i=1; i< getItemCount(); i++){ // 쓰레드 사용을 위한 max 변수 값 구하기[i=1에서 시작, i<아이템 갯수 만큼 for문 사용]
if(arrayList.get(i).getProduct_count().isEmpty()){ //arrayList.get(i).getProduct_count()이 비어있다면
}
else { //arrayList.get(i).getProduct_count()이 비어있지 않다면
if (max < Integer.parseInt(arrayList.get(i).getProduct_count())) { //max의 값(arrayList.get(0).getProduct_count())이 (arrayList.get(i).getProduct_count()) 보다 작다면
max = Integer.parseInt(arrayList.get(i).getProduct_count()); // max의 값을 arrayList.get(i).getProduct_count()으로 설정
}
else if( max > Integer.parseInt(arrayList.get(i).getProduct_count())) { //max의 값(arrayList.get(0).getProduct_count())이 (arrayList.get(i).getProduct_count()) 보다 크다면
// max의 값 변한 없음
}
}
}
{ // 사람들이 현재 가장 많이 보는 상품을 작업쓰레드를 이용하여 토스트 메세지로 10초마다 띄어준다.
String strmax = Integer.toString(max);
if (strmax.isEmpty()) {
} else {
BackThread most_popular_product = new BackThread(); //내가 만든 BackThread(작업스레드)객체 생성
most_popular_product.start();
}
}
holder.itemView.setOnClickListener(new View.OnClickListener() { //holder의 itemview를 클릭했을때 Buy_form.class(물품 정보 상세 페이지)로의 이동을 하는 기능
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onClick(View v) {
Intent intent = new Intent(aContext, Buy_form.class); //holder의 itemview를 클릭 시 Buy_form.class 이동을 위해 인텐트 이용을 위해 Fragment1에서 어댑터 객체 생성자로 부터 Context를 변수로 얻어 온다.
aContext.startActivity(intent); // 인텐트 시작
info_data.setProduct_price(holder.product_price.getText().toString()); //static(전역 변수)인 ArrayList<Trade_RecyclerProductData> info_data를 참조하여 holder.product_price.getText()로 부터 값을 불러와 setProduct_price 하여 값 저장한다.
info_data.setProduct_name(holder.product_name.getText().toString()); //static(전역 변수)인 ArrayList<Trade_RecyclerProductData> info_data를 참조하여 holder.product_name.getText()로 부터 값을 불러와 setProduct_name 하여 값 저장한다.
info_data.setProduct_category(holder.product_category.getText().toString()); //static(전역 변수)인 ArrayList<Trade_RecyclerProductData> info_data를 참조하여 holder.product_category.getText()로 부터 값을 불러와 setProduct_category 하여 값 저장한다.
info_data.setProduct_content(holder.product_content.getText().toString()); //static(전역 변수)인 ArrayList<Trade_RecyclerProductData> info_data를 참조하여 holder.product_content.getText()로 부터 값을 불러와 setProduct_content 하여 값 저장한다.
info_data.setProduct_imageurls( holder.product_image_urls.getText().toString()); //static(전역 변수)인 ArrayList<Trade_RecyclerProductData> info_data를 참조하여 holder.product_image_urls.getText()로 부터 값을 불러와 setProduct_imageurls 하여 값 저장한다.
Log.d("price ", info_data.getProduct_price());
Log.d("name ", info_data.getProduct_name());
Log.d("category ", info_data.getProduct_category());
Log.d("content ", info_data.getProduct_content());
Log.d("imageurls ", info_data.getProduct_imageurls());
}
});
holder.product_heart_black_image.setOnClickListener(new View.OnClickListener() {//holder의 product_heart_black_image(검정색 하트) 클릭했을때 빨간 하트로 변하고 좋아요 수가 1 증가 / 빨간색 하트 눌렀을 때 검정 하트로 변하고 좋아요 수 1 감소
@Override
public void onClick(View v) {
Log.d("검은색 하트 비트맵 값(고정값) : ", drawableToBitmap(blackheart).toString());
Log.d("빨간색 하트 비트맵 값(고정값) : ", drawableToBitmap(redheart).toString());
int heart_count = Integer.parseInt((String) holder.product_heart_count.getText()); //heart_count(좋아요 수)변수에 holder.product_heart_count.getText()의 값을 넣는다.
if(heart_count>=0) { //heart_count(좋아요 수)가 0보다 클 때
if (drawableToBitmap(holder.product_heart_black_image.getDrawable()).equals(drawableToBitmap(blackheart)) ) {
//현재 나의 상품 좋아요 하트 색인 (drawableToBitmap()메소드를 통해 holder.product_heart_black_image를 getDrawable()으로 Drawable형식을 Bitemap 형식으로 바꿈)
//이것이 변하지 않는 검정색 하트 색인 blackheart(drawableToBitmap()메소드를 통해 처음에 holder.product_heart_black_image를 getDrawable()으로 Drawable형식을 Bitmap 형식으로 저장하고 변하지 않은 변수값임)
// 즉, 현재 나의 상품 좋아요 하트 색 = 검정색 하트라면 / 현재 나의 상품 좋아요 하트 색이 검정색 이라면
holder.product_heart_black_image.setImageResource(R.drawable.heart_red); //holder.product_heart_black_image에 setImageResource()메소드를 통해 drawable 디렉토리에 저장되어 있는 빨간색 하트로 바꾼다.
holder.product_heart_count.setText(String.valueOf(heart_count + 1)); //holder.product_heart_count의 수를 1 증가 시킨다.
// android.content.res.Resources$NotFoundException: String resource ID #0x1 에러 해결
// String 자리에 int 를 넣어 줬음
Log.d("하트 색이 동일 한가 ? " , "하트 색 동일하다.(현재 하트 색= 검정색 하트색");
Log.d("현재 색(검정색)과 검정색 하트 색과 동일할 때 하트의 비트맵 값: ", drawableToBitmap(holder.product_heart_black_image.getDrawable()).toString());
}
else { // 현재 나의 상품 좋아요 하트 색 != 검정색 이라면 즉, 현재 나의 상품 좋아요 색이 빨간색 하트 이라면
holder.product_heart_black_image.setImageResource(R.drawable.heart_black); //holder.product_heart_black_image에 setImageResource()메소드를 통해 drawable 디렉토리에 저장되어 있는 검정색 하트로 바꾼다.
holder.product_heart_count.setText(String.valueOf(heart_count - 1));//holder.product_heart_count의 수를 1 감소 시킨다.
Log.d("하트 색이 동일 한가 ? " , "하트 색 동일하지 않다.(현재 하트 색 = 빨간색 하트색");
Log.d("현재 색(빨간색)과 검정색 하트 색과 동일할 때 하트의 비트맵 값:", drawableToBitmap(holder.product_heart_black_image.getDrawable()).toString());
}
}
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { //뷰홀더의 부분을 길게 클릭했을때(단, 버튼 같은 특정 작용을 작용하는 것들을 제외하고서)
@Override
public boolean onLongClick(View view) {
arrayList.remove(holder.getAdapterPosition()); //
notifyItemRemoved(holder.getAdapterPosition());
notifyItemRangeChanged(holder.getAdapterPosition(),arrayList.size());
// remove(holder.getAdapterPosition()); // holer의 getAdapterPosition()부분을 지운다.
return true; // true 값을 반환한다.
}
});
}
위의 코드는 holder(ViewHolder를 통해 xml과 연결해주는것)를 통해 xml(리사이클러뷰의 데이터)들의 각각의 부분에 대해서 내용을 채워준다.
리사이클러뷰의 데이터들을 넣어주는 대략적인 방법은
Trade_RecyclerProductAdapter의 생성자를 이용하여 데이터가 채워진 arraylist를 받아오는데 holder의 xml에 setText라던지 값을 입력하는 메소드를 통해 이 arraylist의 데이터들을 이용해 값을 채워넣는다.
주요기능
- 홀더의 각 부분에 대해서 상품사진, 상품 제목, 상품등록한 사람의 현재 위치, 물품 가격, 좋아요(하트색,수)를 넣어준다.
- 10초마다 작업 쓰레드를 이용하여 상품을 가장 많이 클릭한 상품(인기가 많은)을 Toast 메세지로 띄어준다.
- 각 홀더의 itemview를 클릭하면 Buy_form.class(물품 정보 상세 페이지)로 이동하며 현재 포지션의 리사이클러뷰 데이터를 저장을 하여 Buy_form.class(물품 정보 상세 페이지)로 바로 전송하여 띄어준다.[static(전역변수) 이용]
- 홀더의 itemview를 길게 클릭하게 되면 현재 포지션의 리사이클러뷰의 데이터가 삭제된다.
◼️ 3-1-1. 물품 등록을 보여주는 리사이클러뷰의 어댑터의 좋아요 구현
holder.product_heart_black_image.setOnClickListener(new View.OnClickListener() {//holder의 product_heart_black_image(검정색 하트) 클릭했을때 빨간 하트로 변하고 좋아요 수가 1 증가 / 빨간색 하트 눌렀을 때 검정 하트로 변하고 좋아요 수 1 감소
@Override
public void onClick(View v) {
Log.d("검은색 하트 비트맵 값(고정값) : ", drawableToBitmap(blackheart).toString());
Log.d("빨간색 하트 비트맵 값(고정값) : ", drawableToBitmap(redheart).toString());
int heart_count = Integer.parseInt((String) holder.product_heart_count.getText()); //heart_count(좋아요 수)변수에 holder.product_heart_count.getText()의 값을 넣는다.
if(heart_count>=0) { //heart_count(좋아요 수)가 0보다 클 때
if (drawableToBitmap(holder.product_heart_black_image.getDrawable()).equals(drawableToBitmap(blackheart)) ) {
//현재 나의 상품 좋아요 하트 색인 (drawableToBitmap()메소드를 통해 holder.product_heart_black_image를 getDrawable()으로 Drawable형식을 Bitemap 형식으로 바꿈)
//이것이 변하지 않는 검정색 하트 색인 blackheart(drawableToBitmap()메소드를 통해 처음에 holder.product_heart_black_image를 getDrawable()으로 Drawable형식을 Bitmap 형식으로 저장하고 변하지 않은 변수값임)
// 즉, 현재 나의 상품 좋아요 하트 색 = 검정색 하트라면 / 현재 나의 상품 좋아요 하트 색이 검정색 이라면
holder.product_heart_black_image.setImageResource(R.drawable.heart_red); //holder.product_heart_black_image에 setImageResource()메소드를 통해 drawable 디렉토리에 저장되어 있는 빨간색 하트로 바꾼다.
holder.product_heart_count.setText(String.valueOf(heart_count + 1)); //holder.product_heart_count의 수를 1 증가 시킨다.
// android.content.res.Resources$NotFoundException: String resource ID #0x1 에러 해결
// String 자리에 int 를 넣어 줬음
Log.d("하트 색이 동일 한가 ? " , "하트 색 동일하다.(현재 하트 색= 검정색 하트색");
Log.d("현재 색(검정색)과 검정색 하트 색과 동일할 때 하트의 비트맵 값: ", drawableToBitmap(holder.product_heart_black_image.getDrawable()).toString());
}
else { // 현재 나의 상품 좋아요 하트 색 != 검정색 이라면 즉, 현재 나의 상품 좋아요 색이 빨간색 하트 이라면
holder.product_heart_black_image.setImageResource(R.drawable.heart_black); //holder.product_heart_black_image에 setImageResource()메소드를 통해 drawable 디렉토리에 저장되어 있는 검정색 하트로 바꾼다.
holder.product_heart_count.setText(String.valueOf(heart_count - 1));//holder.product_heart_count의 수를 1 감소 시킨다.
Log.d("하트 색이 동일 한가 ? " , "하트 색 동일하지 않다.(현재 하트 색 = 빨간색 하트색");
Log.d("현재 색(빨간색)과 검정색 하트 색과 동일할 때 하트의 비트맵 값:", drawableToBitmap(holder.product_heart_black_image.getDrawable()).toString());
}
}
}
});
public static Bitmap drawableToBitmap (Drawable drawable) { //drawable 데이터 형태를 Bitmap 형태로 변환)
if (drawable instanceof BitmapDrawable) { //instanceof : 객체 타입을 확인하는 연산자,형변환 가능여부를 확인하며 true/false로 결과 반환
return ((BitmapDrawable)drawable).getBitmap(); // BitmapDrawable 형식에서는 getBitmap() 메소드 사용가능하다.
}
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); //임의의 bitmap 원하는 내용으로 그리기
Canvas canvas = new Canvas(bitmap); //일종의 도화지 생성
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); //위치 및 크기 설정
drawable.draw(canvas); // drawable 그리기
return bitmap;
}
[ 참고 사항인데, 물품이 마음에 들었을때 좋아요 하트를 클릭하여 빨간색 하트로 변하게 하고 마음이 변하여 마음에 안들어졌다면 다시 빨간색 하트를 눌러 검정색으로 변하게 하는 기능에 대해서
여기 검정,빨강 하트Image에 대해서 많은 시도와 오류가 있었는데 내가 해결한 방법은
기본적으로 상품에는 검정색 하트 이미지가 있어야 하는데 이것은 glide라이브러리를 통해 url을 넣어 구현을 한다. 하지만 이것의 값을 찍어보면 계속해서 변하게 되어 이 값을 고유값으로 쓸 수 없게 되었다. 그래서 내가 해결한 방법은 이 url을 drawable로 변환 한 다음 drawable-bitmap으로 변환하여 고유값을 만들어 사용을 하였다. (빨간색 하트도 이 방식과 동일) 변환하는 방법은 일단 url을 getdrawable()메소드를 이용하여 변환하고 변환된 drawable을 drawable-bitmap을 변환하는것은 함수를 만들어 함수에 drawable을 넣고 사용하였다. 위의 코드는 drawabletobitmap 코드이다. ]
◼️ 3-1-2. 물품 등록을 보여주는 리사이클러뷰의 어댑터의 가장 인기있는 물품을 주기적으로 Toast로 띄우는 기능 구현
{ // 사람들이 현재 가장 많이 보는 상품을 작업쓰레드를 이용하여 토스트 메세지로 10초마다 띄어준다.
String strmax = Integer.toString(max);
if (strmax.isEmpty()) {
} else {
BackThread most_popular_product = new BackThread(); //내가 만든 BackThread(작업스레드)객체 생성
most_popular_product.start();
}
}
// class BackRunnable implements Runnable { //작업 쓰레드를 Runnable를 상속 받아 구현
//
// @Override
// public void run() {
// while (true){
// mHandler.sendEmptyMessage(0);
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// }
// }
// }
class BackThread extends Thread { //작업 쓰레드를 Thread를 상속 받아 구현
@Override
public void run() {
while (true){
mHandler.sendEmptyMessage(0); //mHandler 에게 메세지로 0의 값을 전달한다.
try {
Thread.sleep(10000); // 5초 간격 마다
} catch (InterruptedException e) { //예외 처리
e.printStackTrace();
}
}
}
}
Handler mHandler = new Handler() { // mHandler라는 핸들러 객체를 생성한다.
@Override
public void handleMessage(@NonNull Message msg) {
if(msg.what == 0) { //만약에 받는 메시지가 0 이라면
int max1 = max; //
try {
Toast.makeText(aContext, "현재 사람들이 가장 많이 본 상품은 " + arrayList.get(max1).getProduct_name().toString(), Toast.LENGTH_SHORT).show();
//Toast 메세지를 통해 arrayList.get(max1).getProduct_name()의 값을 5초마다 띄운다.
Log.d("thread : ", arrayList.get(max).getProduct_name()); //값을 가져오는 arrayList.get(max).getProduct_name() 확인용
Log.d("thread : ", String.valueOf(max)); // 값을 가져오는 max 확인용
}
catch (Exception e){
}
}
}
};
[참고사항인데, 쓰레드를 한 번이라도 사용해보고 싶어 물품 번호에 따른 숫자를 이용하여 그 숫자가 가장 큰 물품의 번호를 띄어주는것을 쓰레드로 구현하였다.(원래는 물품마다 클릭을 했을때 클릭한 수를 DB에 저장하고 그 중 클릭 횟수가 가장 많은 물품을 작업쓰레드로 Toast 메세지로 띄우는것을 구현하기로 했지만, DB는 다음 프로젝트때 적용시켜본다.)
작업쓰레드를 생성하는 방법은 1.implements Runnable , 2. extends Thread의 방법 2가지로 해보았다.
작업쓰레드를 만들고 데이터가 아닌 UI(Toast)를 건드리기 위해선 Handler를 써야한다. 그래서 Handler의 객체를 생성하여 Toast메세지를 구현해보았다.]
느낀점 : 상품 정보 데이터를 arraylist로 만든것을 리사이클러뷰의 생성자를 이용해 그 값을 이용할 수 있으며 또한 Adapter에서 사용하지 못하는 Context 도 생성자를 통해 받아 올 수 있었다는 기초 개념은 확고해져갔고, 더불어 많은 오류와 기능을 만들면서 직접 겪으므로써 정말 많이 성장 했다는게 느껴진다.
옆에서 알려줘서 그대로 따라하는게 아니라 혹여 따라하더라도 내가 스스로 직접 원하는 기능을 찾아 따라하는것은 엄연히 엄청난 차이가 있다는것을 깨닫았고, 아직은 코드적으로 많이 부족하지만 계속해서 공부하고 노력을 하면 성장할 수 있겠구나 라는 생각이 많이 들고 계속해서 꾸준히 성실히 잘 성장해가야겠다는 생각이 많이 들었다.
'프로젝트 > Android Studio_중고거래앱_Project' 카테고리의 다른 글
Android Studio_중고거래 앱(구글 Map Api 사용을 하여 현재 위치 추출하기) (0) | 2022.08.04 |
---|---|
Android Studio_중고거래 앱(등록된 상품 목록을 클릭하면 자세한 상품 내용 보여주는 화면 구성) (0) | 2022.08.04 |
Android Studio_중고거래 앱(화면 구성 부분) (0) | 2022.07.27 |
Android Studio_중고거래 앱(회원가입,로그인) (4) | 2022.07.27 |
Android Studio_중고거래 앱(설계) (0) | 2022.07.27 |