在适配器中获取Android上下文

58

我在互联网上找到的许多代码示例中,context 是在适配器的构造函数中获取的。

这个上下文用于获取一个 inflater,以便在 getView 方法中填充视图。

我的问题是,既然可以这样轻松地获取它,为什么要在构造函数中获取上下文呢?

        LayoutInflater inflater;
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if(inflater == null){
            Context context = parent.getContext();
            inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            }
            ...
            ...

            return convertView;
        }

还有没有理由不使用上述方法,因为迄今为止我在使用它时没有遇到任何问题。


1
您可以通过 Activity 的 getLayoutInflater() 直接使用 LayoutInflater - Mohammed Azharuddin Shaikh
6个回答

41

在构造函数中获取上下文至少有以下三个优点:

  1. 你只需要一次获取上下文,而不是每次调用 getView() 时都需要获取。
  2. 当需要时,你也可以将其用于其他目的。
  3. 它也适用于 parentnull 的情况。

然而,如果你对自己的解决方案没有任何问题,那么也可以继续使用它。


3
每次调用getView时我并不会获得上下文(context)对象,只有当inflater为空(null)的时候才会有上下文对象。就我个人而言,除了在getView方法内部,我从来没在其它地方需要过上下文对象。虽然父视图(parent)为空(null)似乎很罕见,但这确实是一个有效的观点。 - Gautam

4

这里有一个例子:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = convertView;
    Holder holder;
    if (view == null) {
        view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_job, parent, false);
        holder = new Holder(view, this);
        view.setTag(holder);
    } else {
        holder = (Holder) view.getTag();
    }

    holder.parse(getItem(position), position);
    return view;
}

public class Holder {

    @Bind(R.id.type)
    TextView type;
    @Bind(R.id.date_time)
    TextView dateTime;
    @Bind(R.id.grade)
    TextView grade;

    public Holder(View view) {
        ButterKnife.bind(this, view);
    }

    public void parse(final GetGradeHistoryResponse.GradeHistory item) {
        if (item.grade < 0) {
            grade.setTextColor(App.getInstance()
                    .getResources().getColor(R.color.withdraw_status));
            grade.setText(String.valueOf(item.grade));
        } else {
            grade.setTextColor(App.getInstance()
                    .getResources().getColor(R.color.primary));
            grade.setText("+" + String.valueOf(item.grade));
        }

        type.setText(item.type);
        dateTime.setText(item.datetime);
    }
}

您可以通过在Holder中使用view.getContext()获取上下文。


1
在 Holder 中,view.getContext() 对我来说是关键。 - Tejas Pandya

3

就这么简单!!

class RecentlyAdapter(var data: List<String>) : Adapter<RecentlyAdapter.HomeViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeViewHolder {
    val inflater = LayoutInflater.from(parent.context)
    val view = inflater.inflate(R.layout.card_recently_played, parent, false)
    return HomeViewHolder(view)
}

override fun getItemCount(): Int {
    return data.size
}

override fun onBindViewHolder(holder: HomeViewHolder, position: Int) {

}

class HomeViewHolder(itemView: View): ViewHolder(itemView) {
    init {
        itemView.setOnClickListener {
            val intent = Intent(itemView.context, MusicPlayerActivity::class.java)
            var context = itemView.context
            context.startActivity(intent)
        }
    }
}

}

要获取上下文,请使用itemView.context


2

如果有人创建了一个类,使用BaseAdapter来存储视图(可能稍后会将它们附加到父视图中),那么parent可能为null

这不是什么大问题,你可以自行决定哪种方式更好。

例如:

public class MockWithAdapter{

    private BaseAdapter mAdapter;

    public MockWithAdapter(BaseAdapter adapter){
        mAdapter = adapter;
    }

    public List<View> mock(){
        int size = mAdapter.getCount();
        List<View> views = new ArrayList(size);
        for(int i=0; i<size; i++)
            views.add(mAdapter.getView(i, null, null));

        return views;
    }
}

然后你可以随意处理这些视图:

MockWithAdapter m = new MockWithAdapter(adapter);
ListView lv = new ListView(context);
for(View v : m.mock)
    lv.addView(v);

这实际上是一个有趣的观点,但您能否用一些代码详细说明,以便我可以完全理解? - Gautam
1
Romain GuyAdam Powell的演示中,他们建议不要使用本地视图缓存。http://dl.google.com/googleio/2010/android-world-of-listview-android.pdf - Gautam
2
@GautamK 这只是一个例子。MockWithAdapter 是无意义的。但是,正如您所看到的,parent 为空的情况是可能的。如果您想要更多真实的例子 - 在这里:假设您将每个视图绘制到单独的位图中(而不是将它们添加到 ListView 中)。 - Dmitry Zaytsev

0

2023 年更新 - Kotlin

这是我在 onCreateViewHolder 中实现的方式:

class MyAwesomeAdapter constructor(
    private var awesomeList: List<Awesome>,
) :
    RecyclerView.Adapter<MyAwesomeAdapter.AwesomeViewHolder>() {

    class AwesomeViewHolder(var view: View) : RecyclerView.ViewHolder(view)

    private lateinit var context: Context

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AwesomeViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val view = inflater.inflate(R.layout.layout_awesome, parent, false)

        // SET CONTEXT //
        context = parent.context
        return AwesomeViewHolder(view)
    }

    @RequiresApi(Build.VERSION_CODES.O)
    override fun onBindViewHolder(holder: AwesomeViewHolder, position: Int) {
        val awesome = awesomeList[position]

        holder.apply {

            // Update the UI here or whatever
        }
    }

    override fun getItemCount(): Int = awesomeList.size

    fun update(newAwesomeList: List<Awesome>) {
        awesomeList = newAwesomeList
        notifyDataSetChanged()
    }
}

-1

是的,但如果您需要任何活动参考,例如对话框警报,您不能使用上下文引用,因此构造函数应从调用的Activity/Fragment接收活动引用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接