为什么此BindingAdapter在Kotlin中不起作用?

时间:2018-10-04 21:45:20

标签: android kotlin android-binding-adapter

我有一个ViewModel:

val imageUrl = ObservableField<String>()

我的布局XML具有:

<ImageView
    ...
    app:url="@{viewModel.imageUrl}"
    .../>

我有一个具有顶级功能的BindingAdapters文件:

@BindingAdapter("url")
fun loadImage(view: ImageView, url: String?) {
    ...
}

我遇到以下错误:

data binding error msg:Cannot find the setter for attribute 'app:url' with parameter type android.databinding.ObservableField<java.lang.String> on android.widget.ImageView.

有人知道为什么会这样吗?这与我在Java中设置绑定适配器的方式几乎相同,只不过是静态函数。

3 个答案:

答案 0 :(得分:11)

此问题是由应用程序的build.gradle中缺少kapt引起的。将以下内容添加到build.gradle中,并将所有“ annotationProcessor”依赖项替换为“ kapt”即可解决此问题。

'public class DinnerFragment extends Fragment {

public DinnerFragment() {
    // Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.list_view, container, false);

    final TextView address = (TextView) rootView.findViewById(R.id.address);
    //Create a list for locations
    ArrayList<List> locations = new ArrayList<List>();

    locations.add(new List("Coconuts", "Chill, beachy hangout on the Intracoastal dishing seafood & Sunday brunch while yachts cruise by.", "429 Seabreeze Blvd, Fort Lauderdale, FL 33316" , R.drawable.coconuts));
    locations.add(new List("Trulucks","Upscale seafood & steak chain featuring half-price happy hours, a deep wine list & swanky surrounds", "2584A E Sunrise Blvd, Fort Lauderdale, FL 33304", R.drawable.trulucks ));
    locations.add(new List("Pirate Republic", "Lively riverfront spot with a Caribbean-Mediterranean menu, live music & weeknight happy hour.", "400 SW 3rd Ave, Fort Lauderdale, FL 33315", R.drawable.pirate_republic ));
    locations.add(new List("15th Street Fisheries", "Veteran marina eatery dishing upscale & casual fare with live music & tarpon feeding from the dock.", "1900 SE 15th St, Fort Lauderdale, FL 33316", R.drawable.fifthteenthst_fisheries));
    locations.add(new List("Shooters Waterfront","Laid-back spot on the Intracoastal Waterway offering food, drinks, live music & water views.","3033 NE 32nd Ave, Fort Lauderdale, FL 33308",R.drawable.shooterswaterfront ));
    locations.add(new List("OCEAN2000", "Ocean views from the veranda & menu of American dishes with Latin flair are highlights at this spot.", "2000 N Ocean Blvd, Fort Lauderdale, FL 33305", R.drawable.oceans2000));
    locations.add(new List("Blue Moon Fish Co.","Foodies flock to this upmarket fish house with a romantic vibe, outdoor deck & Sunday buffet brunch.","4405 W E Tradewinds Ave, Lauderdale-By-The-Sea, FL 33308",R.drawable.bluemoonfish));
    locations.add(new List("Two Georges","Lively, multiroomed dockside spot offering seafood, cocktails, live music & Intracoastal views.","1754 SE 3rd Ct, Deerfield Beach, FL 33441",R.drawable.twogeorges));
    locations.add(new List("The Whale's Rib","Seafood & \"whale\" fries are hot items at this bustling beach cafe/bar with old-time Florida flavor. Was featured on the Food Network","2031 NE 2nd St, Deerfield Beach, FL 33441",R.drawable.whalesrib));
    locations.add(new List("Ruth's Chris Steak House", "Outpost of upmarket steakhouse chain known for sizzling, butter-topped beef in an elegant setting", "2525 N Federal Hwy, Fort Lauderdale, FL 33305" ,R.drawable.ruthschrissteak));
    locations.add(new List("The Capital Grille", "Outpost of the upscale steakhouse chain offers classic American fare & a clubby, refined setting.", "2430 E Sunrise Blvd, Fort Lauderdale, FL 33304", R.drawable.capitalgrille ));
    locations.add(new List("Chima Steakhouse", "Posh, stylish venue for meats carved tableside, ample salad bar, outdoor bar & weeknight happy hour.", "2400 E Las Olas Blvd, Fort Lauderdale, FL 33301", R.drawable.chimasteak));
    locations.add(new List("Morton's The Steakhouse", "Upscale chain for aged prime beef, seafood & other traditional steakhouse fare in a clubby space.", "500 E W Broward Blvd #127, Fort Lauderdale, FL 33394" ,R.drawable.mortonssteak));
    locations.add(new List("Pampa Gaucho Steakhouse","Known as the best Brazilian Steakhouse in all of South Florida", "4490 N Federal Hwy, Lighthouse Point, FL 33064", R.drawable.truluckssteak ));
    // Create a ArrayAdapter from the made ListAdapter (custom ArrayAdapter) The adapter will set to display the
    // contents of the locations list
    ListAdapter adapter =
            new ListAdapter(getActivity(), locations);

    // Find the ListView object (in xml list_view) named list.
    ListView listView = (ListView) rootView.findViewById(R.id.list);

    //Make the ListView use the ArrayAdapter(adapter) we created above, so the
    //ListView will display list items for each location in the list of locations.
    listView.setAdapter(adapter);


    address.setOnClickListener(new Intent() {

        @Override
        public void onClick(View v) {
            Intent geoIntent = new Intent(Intent.ACTION_VIEW,Uri.parse(("geo:0,0?q=" + address.getText().toString())));
            startActivity(geoIntent);
        }
    });


    return rootView;
}

答案 1 :(得分:0)

我们对图像的处理不多,但这是我们的代码

模型

class Habit(val title:String,val description:String,val image:Bitmap) {

和适配器

class HabitsAdapter(val habits:List<Habit>): RecyclerView.Adapter<HabitsAdapter.HabitViewHolder>() {

class HabitViewHolder(val card:View):RecyclerView.ViewHolder(card)

override fun onBindViewHolder(holder: HabitViewHolder, index: Int) {

    if(holder != null){
        val habit = habits[index]
        holder.card.tvTitle.text = habit.title
        holder.card.tvDescription.text = habit.description
        holder.card.ivINsingle_card.setImageBitmap(habit.image)
    }
}
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HabitViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.single_card, parent,false)
        return HabitViewHolder(view)
    }

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

答案 2 :(得分:0)

我遇到了另一个问题。这可能不是解决您问题的方法,但其他人可能会从中受益。我所做的就是在我的加载图像函数中添加一个占位符和一个可绘制的错误,如下所示:

@JvmStatic
@BindingAdapter("imageUrl", "error", "placeholder")
fun ImageView.setImageFromUrl(imageUrl: String, error: Drawable?, placeholder: Drawable?) {
    Picasso.get()
            .load(imageUrl)
            .placeholder(placeholder
                    ?: ContextCompat.getDrawable(context, R.drawable.ic_general_placeholder)!!)
            .error(error
                    ?: ContextCompat.getDrawable(context, R.drawable.ic_general_error)!!)
            .into(this)
}

我坚信将?放在Drawables的末尾就足够了,并且在布局中,如果我不想提供任何特定的错误,我只能为图像URL提供app:imageUrl。和占位符图像。但是我错了,我一直遇到与您相同的错误,找不到设置器...清除缓存几个小时,删除每个构建文件夹,重新启动android studio几次后,我在google提供的指南中找到了解决方案。您需要在@BindingAdapter内指定是否需要所有属性。所以我像这样修改了我的代码,它起作用了:

@JvmStatic
@BindingAdapter(value = ["imageUrl", "error", "placeholder"], requireAll = false)
fun ImageView.setImageFromUrl(imageUrl: String, error: Drawable?, placeholder: Drawable?) {
    Picasso.get()
            .load(imageUrl)
            .placeholder(placeholder
                    ?: ContextCompat.getDrawable(context, R.drawable.ic_general_placeholder)!!)
            .error(error
                    ?: ContextCompat.getDrawable(context, R.drawable.ic_general_error)!!)
            .into(this)
}