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

리사이클러뷰 url 질문

0 추천

아래처럼 한 아이템은 링크가 안걸리게 막아놓고 이런식으로 구현하려고 해서요!

 

new ItemData(R.drawable.ic_1, "")
new ItemData(R.drawable.ic_2, "youtube")
enerigpy (2,110 포인트) 님이 2023년 2월 19일 질문
링크를 막는다는 의미를 좀 더 정확하게 해보시겠어요? 링크가 URL이 아닐 때 막겠다는 것인지, 아니면 버튼이 체크가 되지 않았을 때 막겠다는 것인지.
아 버튼은 두 개인데 하나는 체크가 되도록 하는거고 하나는 링크로 타지는거로 하려구요! 근데 여기서 어떤 아이템은 링크타지는 버튼이 이동안하도록 이벤트를 없애고 싶어서요

2개의 답변

+1 추천
 
채택된 답변

버튼2 추가한 소스코드를 올려 드릴게요.

public class ItemData {
    private int image;
    private boolean checked = false;
    @Nullable private String link = null;

    public ItemData(int image) {
        this.image = image;
    }

    public ItemData(int image, @NonNull String link) {
        this.image = image;
        this.link = link;
    }

    public int getImage() {
        return image;
    }

    @Nullable
    public String getLink() {
        return link;
    }

    public void setChecked(boolean checked) {
        this.checked = checked;
    }

    public void toggleChecked() {
        this.checked = !this.checked;
    }

    public int getDrawableId() {
        return checked ? R.drawable.ic_sc_btn1 : R.drawable.ic_sc_btn;
    }
}



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

    private final List<ItemData> itemData;

    public MyRecyclerAdapter(List<ItemData> itemData) {
        this.itemData = itemData;
    }

    public interface MyRecyclerViewClickListener {
        void onItemClicked(int position);

        void onImageViewClicked(int position);

        void onLinkClick(@Nullable String link);
    }

    private MyRecyclerViewClickListener mListener;

    public void setOnClickListener(MyRecyclerViewClickListener listener) {
        this.mListener = listener;
    }

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

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
        final ItemData item = getItem(position);
        holder.bind(item);

        holder.button.setOnClickListener(v -> {
            if (mListener != null)
                mListener.onItemClicked(holder.getAdapterPosition());
        });

        holder.linkBtn.setOnClickListener(v -> {
            if (mListener != null)
                mListener.onLinkClick(item.getLink());
        });

        holder.itemView.setOnClickListener(v -> {
            if (mListener != null)
                mListener.onItemClicked(holder.getAdapterPosition());
        });

        holder.image.setOnClickListener(v -> {
            if (mListener != null)
                mListener.onImageViewClicked(holder.getAdapterPosition());
        });
    }

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

    private ItemData getItem(int position) {
        return itemData.get(position);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        Button button, linkBtn;
        ImageView image;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            image = itemView.findViewById(R.id.image);
            button = itemView.findViewById(R.id.rebtn);
            linkBtn = itemView.findViewById(R.id.linkBtn);
        }

        public void bind(ItemData item) {
            image.setImageResource(item.getImage());
            button.setBackgroundResource(item.getDrawableId());
            // 필요시 추가
            // linkBtn.setEnabled(item.canOpenLink());
        }
    }
}




public class MainActivity extends AppCompatActivity implements MyRecyclerAdapter.MyRecyclerViewClickListener {

    private List<ItemData> dataList = new ArrayList<>();

    private MyRecyclerAdapter adapter;

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

        setupViews();
    }

    private void setupViews() {
        RecyclerView recyclerView = findViewById(R.id.recyclerView);

        initialiseAdapterDataSet();
        adapter = new MyRecyclerAdapter(dataList);
        recyclerView.setAdapter(adapter);
        adapter.setOnClickListener(this);
    }

    private void initialiseAdapterDataSet() {
        List<ItemData> initialData = getItems();

        dataList.clear();
        dataList.add(initialData.get(0));
        dataList.add(initialData.get(1));
    }

    private List<ItemData> getItems() {
        return Arrays.asList(new ItemData(R.drawable.ic_1), new ItemData(R.drawable.ic_2, "https://youtu.be/"));
    }

    public void removeItem(int position) {
        dataList.remove(position);
        adapter.notifyItemRemoved(position);
    }

    @Override
    public void onItemClicked(int position) {
        dataList.get(position).toggleChecked();
        adapter.notifyItemChanged(position);
    }

    @Override
    public void onLinkClick(@Nullable String link) {
        boolean isNullOrEmpty = link == null || link.isEmpty();
        if (isNullOrEmpty) return;

        if (!URLUtil.isValidUrl(link)) {
            Toast.makeText(this, "올바른 링크가 아닙니다.", Toast.LENGTH_SHORT).show();
            return;
        }

        openLink(link);
    }

    @Override
    public void onImageViewClicked(int position) {

    }

    // TODO : 재사용을 위해 유틸클래스에 옮길 것.
    private void openLink(String link) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(link));
        startActivity(intent);
    }
}


 

spark (226,720 포인트) 님이 2023년 2월 19일 답변
enerigpy님이 2023년 2월 19일 채택됨
+1 추천

규칙을 먼저 정하세요. 예를 들면 link  null이거나 "" 인거를 링크가 없는 것으로 간주하기로 한다고 치죠.

onOpenLink() 메소드에서 이 규칙만 체크를 하시면 될 것 같은데요.

public class ItemData {
    ...

    public boolean canOpenLink() {
         return link != null && !link.isEmpty();
    }
}

ItemData item = getItem(position);

holder.button2.setOnClickListener(new View.OnClickListener() {
   @Override
   public boolean onClick(View v) {
       if (mListner == null || !item.canOpenLink()) return;
       mListener.onOpenLink(item.getLink());
  }
});

 

액티비티의 onOpenLink 메소드에서는 열어여 할 링크만 넘어오므로, 링크를 여시면 되겠죠. 링크 검사하는 부분은 액티비티에서 해도 상관 없습니다.

 

혹시 링크의 URL 유효성 검사하려면 URLUtil 클래스를 사용하면 됩니다.

https://developer.android.com/reference/kotlin/android/webkit/URLUtil

spark (226,720 포인트) 님이 2023년 2월 19일 답변
@Override
    public void onButton2Clicked(int position) {
        ItemData selectedItem = dataList.get(position);
        selectedItem.toggleChecked2(checked2);
        adapter.notifyItemChanged(position);

        if(selectedItem.getChecked2(checked2) && selectedItem.canOpenLink()) {
            onOpenLink(selectedItem.getLink());
        }
    }

public boolean canOpenLink() {
        return link != null && !link.isEmpty();
    }

new ItemData(R.drawable.ic_1, null);
new ItemData(R.drawable.ic_2, "https://youtu.be/"

이렇게 했는데 2번 아이템은 열리고 1번 아이템은 튕기네요

openlink에서 link 디버깅하면 null로 되고 있어요
코드가 살짝 뒤죽박죽 되어있는 거 같아요.


@Override
public void onButton2Clicked(int position) {
        ItemData selectedItem = dataList.get(position);
        // 아래 세라인은 사용하지 않는다고 하셨으니, 삭제하세요.
        // selectedItem.toggleChecked2(checked2);
        // adapter.notifyItemChanged(position);
        //if(selectedItem.getChecked2(checked2) && selectedItem.canOpenLink()) {

         if (selectedItem.canOpenLink()) { // <- 이 라인이 동작하지 않는다고 하셨으니, 여기에 브레이크 포인트를  디버깅하세요.

            // onOpenLink는 어댑터 리스너의 메소드 아닌가요?
            // 혹 onOpenLink에서 canOpenLink 사용하고 있는 멤버변수인 link를 사용하고 계신건 아닌가요?
            // onOpenLink(selectedItem.getLink());

            openLink(Objects.requireNonNull(selectedItem.getLink())); // getLink() 의 값을 확인해 보세요.
        }
}

private void openLink(@NonNull String url) {;
   // 유투브 여는 코드
}


아래 메소드는  link는 각 아이템의 링크이므로,  link를 인자로 추가해야 그리고 사용하지 않으면 헷갈리기만 하니 지우세요. 정정: 클래스이름이 없어서 마치 액티비티 메소드처럼 보여 착각했어요.
private boolean canOpenLink(String link) {
    return link != null && !link.isEmpty(); //<- link.isEmpty가 아니고 !link.isEmpty() 예요. ! => not
}
public boolean canOpenLink() {
     return link != null && !link.isEmpty();
}

위의 메소드가 이상해요. 제가 작성한 거랑 다르네요.

!link.isEmpty()
link.isEmpty()
위 둘은 다릅니다. !은 not에 해당하는 연산자예요.
아 제말은 각 아이템에 버튼은 2개씩 있는거고 한 버튼은 체크상태 보여주고
한버튼은 링크 연결하는 거로 하고있어요!
public void onButton2Clicked(int position)에서
    // selectedItem.toggleChecked2(checked2);
        // adapter.notifyItemChanged(position);
        //if(selectedItem.getChecked2(checked2) && selectedItem.canOpenLink())

이거는 무조건 있어야 할거같은데

private boolean canOpenLink(String link) {
    return link != null && !link.isEmpty();
}

이거는 뭐가 문제인건가요? 그대로 쓴거입니다!
button2는 링크만 여는 버튼 아니었나요? 그게 맞으면, 제가 바로 위에 올린 onButton2Clicked 가 맞는 코드예요. 혹시 버튼2를 클릭할 때 버튼1의 선택상태도 바꾸려고 하는 건가요? 그렇다면, 이미 다른 버튼에 대한 이벤트 코드가 존재하니 가져다 쓰시면 되구요.

그리고 canOpenLink는 제가 잘못본 것 같네요. 아까는 not 연산자가 안붙어 있는 걸로 봤어요.
네 onOpenLink는 어댑터 리스너이고 holder의 link를 url로 변경했어요

if(selectedItem.canOpenLink()) {
            onOpenLink(Objects.requireNonNull(selectedItem.getLink()));
            Log.d("1", selectedItem.getLink());
        }

하면

PID: 29062
    java.lang.NullPointerException: uriString

나오네요
...