2017-12-26 2 views
0

Kotlin Android Extensions는 활동/조각/어댑터에서 직접 ID를 사용하는 방법을 제공합니다. 그래서 내가 원하는 것은 어댑터에 대한 일반적인 방법이며 어댑터 자체가 아닌 어댑터 사용자에게 바인드 뷰 책임을 남겨 둡니다. 예를 들어 : 나는 모든 단일 레이아웃과 파일 어댑터에 대한 동일한 코드를 다시 작성하지 않고도 원하는대로 그냥 어댑터를 결합하는 레이아웃 파일 및 바인드 기능을 전달할 수Kotlin Android Extension을 사용하여 어댑터에서 뷰 바인딩을 연기 할 수 있습니까?

class GenericAdapter<T>(
    @LayoutRes private val layoutId: Int, 
    private var list: List<T>, 
    inline private val bind: (View, T, Int) -> Unit) : RecyclerView.Adapter<InnerHolder>() { 
    override fun onBindViewHolder(holder: InnerHolder?, position: Int) { 
     holder?.containerView?.let { 
      bind(holder.containerView, list[position], position) 
     } 
    } 

    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): InnerHolder = 
     InnerHolder(LayoutInflater.from(parent?.context).inflate(layoutId, 
      parent, 
      false)) 

    override fun getItemCount(): Int = list.size 

    class InnerHolder(
     val containerView: View?) : RecyclerView.ViewHolder(containerView) 

} 

.

여기에 문제가 있습니다. ViewHolder 패턴은 ChildView가 부풀려 질 때마다 "findViewById"호출을 제거하려고합니다. 하지만 내 어댑터의 구현. 어댑터가 뷰를 바인드 할 때마다 "findViewById"를 호출해야합니다.

편집 : "캐시"문제에 대한 세부 정보입니다.

활동 내에서 GenericAdapter 사용

override fun onCreated(savedInstanceState: Bundle?){ 
    list.adapter = GenericAdapter<Item>(items){ view,item,position -> 
     view.textview.text = item.text 
    } 
} 

처럼이이에 디 컴파일됩니다

 TextView var2 = (TextView)var10000.findViewById(id.textview); 
    Intrinsics.checkExpressionValueIsNotNull(var2, "itemView.tv_text"); 
    var2.setText((CharSequence)String.valueOf(var1)); 

그러나 그들은 예를 들어 LayoutContainer 안드로이드 확장과 실험 도구가 있습니다

class InnerHolder(
    override val containerView: View?) : RecyclerView.ViewHolder(containerView), LayoutContainer { 
    fun bind(int: Int) { 
     textview.text = int.toString() 
    } 
} 

을 그리고 이것은 완벽하게 캐시를 사용합니다 조회수 :

 TextView var10000 = (TextView)this._$_findCachedViewById(id.tv_text); 

그러나 문제는 캐시 된 뷰가 LayoutContainer의 범위 안에 있어야한다는 것입니다. 예를 들어이 구현 작동 실 거예요 :

TextView var10000 = (TextView)$receiver.getContainerView().findViewById(id.tv_text); 

그래서 제 질문은 어떤 방법으로 캐시를 유지하는 방법이 아직 안드로이드를 사용 :

class InnerHolder(
    override val containerView: View?) : RecyclerView.ViewHolder(containerView), LayoutContainer { 
    fun bind(int: Int) { 
     this.bindInt(int) 
    } 

} 
// some extension function outside the ViewHolder Scope. 
fun LayoutContainer.bindInt(int: Int) { 
    tv_text.text = int.toString() 

} 

이 여전히보기를 찾기 위해 findViewById를 사용합니다 확장 기능은 어댑터가 있지만 뷰 소유자의 범위 밖에 있습니까?

+0

홀더 클래스 안에 모든'View' 참조를 넣고'init' 블록에서만'findViewById'를 호출 할 수 있습니다. – Ircover

+0

주어진 모호성을 반영하여 질문을 업데이트하십시오. 또한 어댑터를 인스턴스화하는 유스 케이스를 추가하십시오. 어쩌면 내가 나중에 대답을 찾을거야 ... – tynn

+0

@ tynn 예. 업데이트를 확인하십시오. 시간 내 줘서 고마워! –

답변

1

당신은 다음과 같이 사용할 수 있습니다

innerHolder.apply { 
    tv_text.text = "test" 
} 

는이에 디 컴파일됩니다 @linx

에서 영감을

TextView var10000 = (TextView)innerHolder._$_findCachedViewById(id.tv_text); 
var10000.setText((CharSequence)"test"); 
0

을 그냥 InnerHolder에 확장 함수를 만드는 대신 LayoutContainer 경우 . 컨텍스트는 Android Extension에 캐시 된 뷰를 가져올 수있는 충분한 정보를 제공합니다.

class InnerHolder(
    override val containerView: View?) : RecyclerView.ViewHolder(containerView), LayoutContainer { 
    fun bind(int: Int) { 
     this.bindInt(int) 
    } 

} 
// some extension function outside the ViewHolder Scope. 
fun InnerHolder.bindInt(int: Int) { 
    tv_text.text = int.toString() 

} 

이 내가 원하는 정확히 어떤

TextView var10000 = (TextView)$receiver._$_findCachedViewById(id.tv_text); 

로 컴파일됩니다.

관련 문제