代码之家  ›  专栏  ›  技术社区  ›  fermoga

从视图模型类获取活动的上下文

  •  4
  • fermoga  · 技术社区  · 6 年前

    class PostListAdapter : RecyclerView.Adapter<PostListAdapter.ViewHolder>() {
        private lateinit var posts: List<Post>
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostListAdapter.ViewHolder {
            val binding: ItemPostBinding = DataBindingUtil.inflate(
                LayoutInflater.from(parent.context),
                R.layout.item_post,
                parent, false
            )
    
            return ViewHolder(binding)
        }
    
        override fun onBindViewHolder(holder: PostListAdapter.ViewHolder, position: Int) {
            holder.bind(posts[position])
        }
    
        override fun getItemCount(): Int {
            return if (::posts.isInitialized) posts.size else 0
        }
    
        fun updatePostList(posts: List<Post>) {
            this.posts = posts
            notifyDataSetChanged()
        }
    
        inner class ViewHolder(private val binding: ItemPostBinding) : RecyclerView.ViewHolder(binding.root) {
            private val viewModel = PostViewModel()
    
            fun bind(post: Post) {
                viewModel.bind(post)
                binding.viewModel = viewModel
            }
        }
    }
    

    bind 方法来自视图模型类:

    class PostViewModel : BaseViewModel() {
        private val image = MutableLiveData<String>()
        private val title = MutableLiveData<String>()
        private val body = MutableLiveData<String>()
    
        fun bind(post: Post) {
            image.value = post.image
            title.value = post.title
            body.value = post.body
        }
    
        fun getImage(): MutableLiveData<String> {
            return image
        }
    
        fun getTitle(): MutableLiveData<String> {
            return title
        }
    
        fun getBody(): MutableLiveData<String> {
            return body
        }
    
        fun onClickPost() {
            // Initialize new activity from here, perhaps?
        }
    }
    

    在布局XML中,设置 onClick 属性

    安卓:onClick=“@{()->viewModel.onClickPost()}"

    指着这个 onClickPost 方法确实有效,但无法初始化 Intent 从那里开始。我尝试了很多方法来获得 MainActivitiy 的上下文中,没有成功,例如

    但它会准时显示错误。

    3 回复  |  直到 6 年前
        1
  •  3
  •   Jackey    6 年前

    尝试: android:onClick="@{(view) -> viewModel.onClickPost(view)}"

    也会改变 onClickPost 看风景。然后你可以用 view.getContext() 方法来访问存储在该视图中的上下文。

    就我个人而言,对于我的代码,如果它是一个简单的startActivity而没有任何额外的负担,我将创建一个单独的类来保存一个静态方法。通过数据绑定,我将导入该类并在onClick中使用它,以使用上面提到的方法启动一个新活动。

    public class ActivityHandler{        
        public static void showNextActivity(View view, ViewModel viewModel){
            Intent intent = new Intent(); //Create your intent and add extras if needed
            view.getContext().startActivity(intent);
        }
    }
    
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
        <data>
            <import type="whatever.you.want.ActivityHandler" />
            <variable name="viewmodel" type="whatever.you.want.here.too.ViewModel" />
        </data>
    
        <Button
            //Regular layout properties
            android:onClick="@{(view) -> ActivityHandler.showNextActivity(view, viewmodel)}"
            />
    </layout>
    

    请看此处的侦听器绑定: https://developer.android.com/topic/libraries/data-binding/expressions#listener_bindings

    不过,根据所需的数据量,您可能希望将startActivity代码放在最适合应用程序设计的其他类中。

        2
  •  3
  •   MidasLefko Drakosha    6 年前

    SingleLiveEvent

    这是它的代码 Googles architecture samples repo

    import android.arch.lifecycle.LifecycleOwner;
    import android.arch.lifecycle.MutableLiveData;
    import android.arch.lifecycle.Observer;
    import android.support.annotation.MainThread;
    import android.support.annotation.Nullable;
    import android.util.Log;
    
    import java.util.concurrent.atomic.AtomicBoolean;
    
    /**
     * A lifecycle-aware observable that sends only new updates after subscription, used for events like
     * navigation and Snackbar messages.
     * <p>
     * This avoids a common problem with events: on configuration change (like rotation) an update
     * can be emitted if the observer is active. This LiveData only calls the observable if there's an
     * explicit call to setValue() or call().
     * <p>
     * Note that only one observer is going to be notified of changes.
     */
    public class SingleLiveEvent<T> extends MutableLiveData<T> {
    
        private static final String TAG = "SingleLiveEvent";
    
        private final AtomicBoolean mPending = new AtomicBoolean(false);
    
        @MainThread
        public void observe(LifecycleOwner owner, final Observer<T> observer) {
    
            if (hasActiveObservers()) {
                Log.w(TAG, "Multiple observers registered but only one will be notified of changes.");
            }
    
            // Observe the internal MutableLiveData
            super.observe(owner, new Observer<T>() {
                @Override
                public void onChanged(@Nullable T t) {
                    if (mPending.compareAndSet(true, false)) {
                        observer.onChanged(t);
                    }
                }
            });
        }
    
        @MainThread
        public void setValue(@Nullable T t) {
            mPending.set(true);
            super.setValue(t);
        }
    
        /**
         * Used for cases where T is Void, to make calls cleaner.
         */
        @MainThread
        public void call() {
            setValue(null);
        }
    }
    
        3
  •  3
  •   Khemraj Open To Work    6 年前

    您甚至可以将活动实例传递给模型或布局,但我不喜欢这样。

    在布局数据中声明变量

    <variable
        name="onClickListener"
        type="android.view.View.OnClickListener"/>
    

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="@{onClickListener::onClick}"
        >
    

     binding.viewModel = viewModel
     binding.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                context.startActivity(new Intent(context, MainActivity.class));
            }
        });