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

리스트뷰 내에 버튼을 추가해서 다른 액티비티로 인텐트 시키려는데 오류가납니다...

0 추천
package com.example.mygames;

import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    ArrayList<MyItem> myItems;
    MyListAdapter myAdapter;
    View view;
    Resources res = getResources();
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.listview);

        myItems = new ArrayList<>();
        myItems.add(new MyItem(R.drawable.line, "자유 곡선", "터치를 입력받아 자유 곡선을 그리기"));
        myItems.add(new MyItem(R.drawable.ball, "공 움직이기", "키 A(왼쪽), D(오른쪽), W(위쪽), S(아래쪽)를 입력받아 공 움직이기"));

        myAdapter = new MyListAdapter(this, R.layout.activity_main, myItems);

        ListView list = (ListView)findViewById(R.id.list);
        list.setAdapter(myAdapter);
    }
}

class MyItem {
    int mIcon;
    String mName;
    String mDes;

    public MyItem(int mIcon, String mName, String mDes) {
        this.mIcon = mIcon;
        this.mName = mName;
        this.mDes = mDes;
    }
}

class  MyListAdapter extends BaseAdapter {
    Context mContext;
    int mLayout;
    ArrayList<MyItem> mDatas;
    LayoutInflater mInflater;

    public MyListAdapter(Context context, int layout, ArrayList<MyItem> datas) {
        this.mContext = context;
        this.mLayout = layout;
        this.mDatas = datas;
        this.mInflater = LayoutInflater.from(context);
    }

    @Override
    public  int getCount() {
        return  mDatas.size();
    }

    @Override
    public Object getItem(int position) {
        return mDatas.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = mInflater.inflate(mLayout, parent, false);
        }

        ImageView img = (ImageView)convertView.findViewById(R.id.img01);
        img.setImageResource(mDatas.get(position).mIcon);

        TextView txt = (TextView)convertView.findViewById(R.id.text01);
        txt.setText(mDatas.get(position).mName);

        TextView txt2 = (TextView)convertView.findViewById(R.id.desc01);
        txt2.setText(mDatas.get(position).mDes);

        Button btn = (Button)convertView.findViewById(R.id.btn01);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(v.getContext(), FreeLine.class);
                mContext.startActivity(intent);
            }
        });

        return convertView;
    }
}

마지막 부분 버튼에 인텐트는 넣었는데 실행을 해보면 실행이 안됩니다.. 무슨 문제일까요ㅠㅠ

kokiyo1030 (160 포인트) 님이 2020년 10월 24일 질문
실행이 안된다는 의미가 컴파일이 안되는 건가요, 아니면 앱이 바로 크래쉬 되는 건가요? 실행이 안되면 거기에 따른 에러메세지도 존재할텐데요, 그걸 먼저 확인해 보시죠.

에레메세지 없이는 정확한 원인을 알기 힘들 것 같은데, 현재 추측으로는
Intent intent = new Intent(v.getContext(), FreeLine.class)
부분이 문제일 것 같은데...
btn.setOnClickListener 부분을 MainActivity로 빼셔서 MainActivity에서 Adapter쪽에 Listener를 전달해서 사용해 보세요.

class MyListAdapter extends BaseAdapter {

    private View.OnClickListener buttonClicklistener;
   
    public void setOnButtonClickListener(View.OnClickListener listener) {
         this.buttonClicklistener = listener;
    }


    public View getView(final int position, View convertView, ViewGroup parent) {
        ...
       
       Button btn = (Button)convertView.findViewById(R.id.btn01);
        btn.setOnClickListener(buttonClicklistener);
     }
}

MainActivity

private void showFreeLine() {
    // Intent의 첫번재 인자로 MainActivity.this를 사용. => 요부분을 확인해 보세요.
    Intent intent = new Intent(MainActivity.this, FreeLine.class);
    mContext.startActivity(intent);
}


한가지 정말 궁금한게 있는데, 왜 아직도 ListView를 사용하시나요? 퍼포먼스 등 여러가지 이유로 ListView는 사용을 권장하지 않습니다. RecyclerView 사용하시는게 좋습니다.

1개의 답변

0 추천

아직 학생이라 배우고 있습니다ㅠㅠ.... 일단 class들을 분리시켜서 다시해보는데 역시나 intent가 잘 안되네요ㅠ

package com.example.mygames2;

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;

public class GameAdapter extends BaseAdapter implements View.OnClickListener {
    private Game mGame;
    private Context mContext;

    private ImageView gameImg;
    private TextView gameTitle;
    private TextView gameDesc;
    private Button startBtn;

    private ArrayList<Game> mGameData;

    public GameAdapter(Context context) {
        super();
        mContext = context;
        mGameData = new ArrayList<Game>();
    }

    @Override
    public int getCount() {
        return mGameData.size();
    }

    @Override
    public Game getItem(int position) {
        return mGameData.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(final int position, final View convertView, ViewGroup parent) {
        View v = convertView;
        if (v == null) {
            v = ((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listitemlayout, null);
        }
        gameImg = (ImageView)v.findViewById(R.id.img);
        gameTitle = (TextView)v.findViewById(R.id.title);
        gameDesc = (TextView)v.findViewById(R.id.desc);
        startBtn = (Button)v.findViewById(R.id.btn);

        mGame = getItem(position);

        startBtn.setTag(mGame);
        String ID = String.valueOf(mGame);

        if(mGame != null) {
            if(mGame.getGameImg() != null) {
                gameImg.setImageDrawable(mGame.getGameImg());
            }
            gameTitle.setText(mGame.getGameName());
            gameDesc.setText(mGame.getGameDesc());
            startBtn.setOnClickListener(this);
        }
        return v;
    }

    public void add(Game game) {
        mGameData.add(game);
    }

    @Override
    public void onClick(View v) {
        Game clickItem = (Game)v.getTag();

        switch (v.getId()) {
            case R.id.btn:
                Intent intent = new Intent(v.getContext(), FreeLine.class);
                mContext.startActivity(intent);
                Toast.makeText(mContext, clickItem.getmToast(), Toast.LENGTH_SHORT).show();
                break;
        }
    }
}

이렇게 intent를 추가하기는 했는데 버튼을 누르면 바로 앱이 크래쉬 됩니다...ㅠ

또 리스트에 2개를 넣어서 intent를 2개를 해야하는데 switch문을 tag1 tag2로 분리시킬수 있는 방법이 있을까요? intent빼고 toast메세지는 2개의 메세지가 따로따로 잘 나옵니다..

익명사용자 님이 2020년 10월 25일 답변
제가 public void onClick(View v)  부분에서 Intent를 생성하는 부분을 잘 체크하라고 말씀드렸는데, 코드가 변경사항이 없네요. Intent의 첫번째 인자는 Activity나  Application의 context가 들어와야 되는 걸로 압니다. 님의 Adapter에서 mContext가 Activity를 가리키는 것 같아 보이네요.
view.getContext()는 Activity의 context와는 다른 녀석일 겁니다. 이게 맞다면 onClick은 Adapter에서 Activity 쪽으로 옮겨져야 합니다. Activity를 띄우는 것은 Adapter의 책임이 아니예요. 그건 Activity에서 하는 일이죠. OOP에서 자기 책임을 남에게 전가하면 안좋은 코드가 될 확률이 매우 매우 높아요.
GameAdapter에서
@Override
    public long getItemId(int position) {
        return 0;
    }

잘못 되었습니다. 적절한 item의 유니크한 id를 리턴하셔야 해요. 나두시면 버그의 원인이 됩니다.

@Override
    public long getItemId(int position) {
        return getItem(position).id;
         //id 항목이 없으면 getItem(position).hashCode();
    }
...