original source : https://stackoverflow.com/a/58663143/3151712

There are two different lifecycles because the Fragment itself lives longer than the Fragment’s view.

There are a number of events that can cause the Fragment’s view to be destroyed, but currently keep the Fragment itself alive:

  1. Putting the Fragment on the back stack (i.e., when you navigate() to another Fragment)
  2. Calling detach() on a Fragment
  3. Calling setMaxLifecycle(Lifecycle.State.CREATED) on a Fragment

In these cases, the Fragment’s view is destroyed, moving the Fragment view lifecycle to DESTROYED. However, the lifecycle of Fragment itself is not destroyed – it generally stays as CREATED. This means that the Fragment can go through multiple cycles of onCreateView() -> onViewCreated() -> onDestroyView() while only going through onCreate() once.

Where this becomes a problem is when it comes to how LiveData works. When you observe a LiveData, LiveData automatically unregisters the observer when the lifecycle reaches DESTROYED. But if you use the Fragment’s lifecycle to observe in onCreateView(), etc., that registered observer will still exist after onDestroyView(), despite the view being destroyed. This means that the second time your Fragment goes through onCreateView(), you’ll actually create a second active Observer, with both running simultaneously. Then three Observers the next time and on and on.

By using the view LifecycleOwner in onCreateView()/onViewCreated(), you ensure that you’ll only have one active Observer running at a time and that Observers tied to previous view instances are correctly destroyed along with the view. Therefore, yes, you should always use getViewLifecycleOwner() as the LifecycleOwner when in onCreateView() or onViewCreated(), including when using Data Binding.

Of course, if you’re registering an Observer in onCreate(), then the view LifecycleOwner does not exist yet (it is created right before onCreateView()) and you don’t have the multiple registration problem, which is why the Lint check specifically does not apply to any registrations done at onCreate() time. In those cases, using the Fragment’s lifecycle itself is absolutely correct.

As per the Fragments: Past, Present, and Future talk, one future improvements for Fragments is going to be combining the two lifecycles together, always destroying the Fragment whenever the Fragment’s view is destroyed. This is not yet available in any shipped version of Fragments, alpha or otherwise.

original source : https://medium.com/@cs.ibrahimyilmaz/viewlifecycleowner-vs-this-a8259800367b

ViewModel은 아래와 같이 onCreate() 후에 생성되어서 activity에 연결된 ViewModel의 경우 onDestory() 후에 사라지게 된다. fragment에 연결된 ViewModel의 경우는 onDestroy()바로 이전에 사라지게 된다. 거칠게 이야기 하면 activity, fragment의 수명과 그에 연결된 ViewModel의 수명이 비슷하다고 할수 있다. 그렇다면 그안에서 생성된 LiveData 도 같은 수명을 가지게 된다. 다만 LiveData에 observe 에 전달되는  viewlifecycleowner나 this는 언제 값을 들여다 볼지를 결정한다.(여기서는 LiveData의 값이 변할때를 말하는 것이 아니다.) activity나 fragment의 주기에 따라 언제 값을 들여다볼지를 결정하는 것이다. this의 경우 onCreate() 될때 마다 들여다 본다. viewlifecycleowner의 경우는 onCreateView() 될때 마다 들여다 본다.

결과적으로 viewlifecycleowner를 사용하면 좀더 자주 확인한다는 이야기이다. 한 fragment에서 다른 fragment로 전환된 사이에 변경되었을수 있는 값을 가져와야 하는 경우 viewlifecycleowner를 사용한다.

참조) https://stackoverflow.com/a/59521748/3151712

image

As we can see from the diagram onCreate and onDestroy called once. These are Fragment mainly life cycle methods. onCreateView and onDestroyView are called according to state of Fragment because they are mainly life cycle methods of the View in Fragment.

So If we use onCreate method for binding our LiveData. Yes we register once and it seems very good and lean:

liveData.observe(this, observer)

But what will happen when we navigate to another fragment and change the value of LiveData there and get back our previous fragment

In going back to the Fragment, we cannot get recent data in LiveData and we should request it.

So it seems that using Views’s LifeCycle methods are much more useful. But in that condition. Common mistake that we do is to use Fragment as a LifeCycle owner.

//in onViewCreated, onCreateView,onActivityCreatedliveData.observe(this, observer) // Mistake!!! It can cause double observation or other problems.

we should use viewLifecycleOwner.

//in onViewCreated, onCreateView,onActivityCreatedliveData.observe(viewLifecycleOwner, observer) 

Difference between getContext() , getApplicationContext() , getBaseContext() and “this”

Using “this” with class name



https://bugs.php.net/bug.php?id=46246 에서 참조



Description: ------------ There is a difference in behavior of call_user_func(array($this, $method)) and $this->$method() while class B inherits from class A and both declares the same method. The call_user_func() function seems to work as expected, but using $this->$method() seems to invoke parent method implementation instead of the overridden one. Reproduce code: --------------- class A { protected function Test() { echo 'Hello from '.get_class($this); } public function call($method, $args = array()) { return $this->$method(); //return call_user_func(array($this, $method)); } } class B extends A { protected function Test() { echo 'Overridden hello from '.get_class($this); } } $a = new A; $b = new B; $a->call('Test'); $b->call('Test'); Expected result: ---------------- Hello from A Overridden hello from B Actual result: -------------- Hello from A Hello from B

이번에는 조금 복잡한 이야기를 해볼까요?

  자바스크립트 this 키워드에 대한 설명은 함수 파트에서 함께 진행하려고 하였습니다만 this를 통해 곤란해 하는 분들이 많아 앞당겨 진행하겠습니다. 이번에 드리는 설명을 올바르게 이해하기 위해서는 자바스크립트의 함수, 그리고 객체에 대한 정확한 이해가 밑받침 되어야합니다.

  자바스크립트는 가볍게 쓰는 경향이 있기 때문에 메커니즘을 착각하기도 쉽습니다. 자바스크립트에서 this의 본질은 여타언어 C++, Java등과 다르지 않습니다. this는 메서드를 호출한 호출객체를 가르킵니다. 이를테면

  // 자바스크립트의 객체 생성방법 중 하나
var people = new Object();
  people.name = “thinkberry”;
  people.displayName = function() { alert(this.name); }

  peolpe.displayName();
  

  위의 코드를 실행하게 되면 thinkberry가 뜨게 되죠. this는 곧 메서드를 호출한 객체 즉 자신을 가리키게 됩니다. 이것은 어느 언어나 마찬가지입니다. 하지만 자바스크립트는 함수호출객체, 데이터 타입으로서의 함수, 중첩함수, 어휘적 유효범위, HTML의 엘리먼트속에서 this가 사용되는 과정에 사용자로 하여금 혼란에 빠트리게 됩니다. 여러분이 this를 완벽하게 이해하려면 아래의 코드에서 출력결과를 예측해보시기 바랍니다.


var scope = “global”;


function scopeCheck() { 

var scope = “outterLocal”;

alert(“(1) ”+this.scope); // 출력결과 예상


var object = new Object();

object.scope = “field”;

object.scopeCheck = function() { alert(“(2) ”+this.scope); } 

object.scopeCheck(); // 출력결과 예상

function inner() { 

var scope = “innerLocal”;

alert(“(3) ”+this.scope); 

}

inner(); // 출력결과 예상

var anotherObject = new Object();

anotherObject.scope = "anotherField";

anotherObject.scopeCheck = function() { alert(“(4) ”+this.scope); } 

object.scopeCheck = anotherObject.scopeCheck;

object.scopeCheck(); // 출력결과 예상
}

scopeCheck();


  제가 자바스크립트 과목의 교수였다면 위와 같은 문제를 냈을 겁니다. 자바스크립트를 가리키는 강의가 있기나 할진 모르겟지만.. 위 코드를 올바르게 이해한다면 this 키워드를 거의 완벽하게 이해했다고 말할 수 있습니다.

  정답은 (1) global   (2) field   (3) global   (4) field 입니다.

  그럼 해설을 해볼까요?
  

(1)

        var scope = "global";


function scopeCheck() { 

var scope = "outterLocal";

alert(“(1) ”+this.scope); // global


  자 바스크립트는 자신을 호출한 객체를 가르킬 때 this 키워드를 사용합니다. 하지만 호출한 (명시적)객체가 없다면 호출스택을 거슬러 올라가며 가장 가까운 (명시적)객체를 찾습니다. 계속 거슬러 올라가도 (명시적)객체가 없다면 this키워드는 결국 최상단의 전역 객체를 가르키게 됩니다. 브라우저 측 자바스크립트에서는 보통 window 객체인데 이는 곧 전역을 의미합니다. 때문에 전역 변수 scope의 값인 global을 가르키게 되죠. 쉽게 이해하자면 this 키워드가 참조할 객체가 없다면 전역범위를 가리킨다고 생각하시면 되겠습니다.

  자바스크립트는 모든 호출이 객체를 통해 이루어지는 메커니즘입니다. 이를 잘 몰라도 자바스크립트를 작성하는데 문제는 없으니 시간낭비라고 생각되시면 이 설명을 건너뛰어도 좋습니다. scopeCheck라는 함수를 호출하면 사실은 묵시적 객체가 생성됩니다. 이 객체의 목적은 오직 해당 함수를 호출하기 위한 묵시적 객체입니다. 함수 내에 선언된 지역변수들은 묵시적 객체의 지역변수가 되고 호출된 함수 그 자체는 묵시적 객체의 멤버 함수로 할당되면서 함수가 시작되게 됩니다. 안타깝게도 묵시적 객체는 코드 상에서 접근할 수 있는 방법이 없는 메커니즘 상의 객체 입니다. 이와 반대로 사용자가 직접 new 키워드를 사용하여 생성한 객체가 있습니다. 이를 명시적 객체라고 하겠습니다. 명시적 객체는 얼마든지 코드 상에서 접근할 수 있습니다. 자바스크립트에서 this 키워드는 기본적으로 묵시적 객체를 참조하지 않습니다. 사용자가 new 키워드를 통해 생성한 명시적 객체만 참조하죠. 하지만 아무리 거슬러 올라가도 명시적 객체가 없다면 결국 최상단의 객체인 컨텍스트 객체(브라우저상에서는 Window 객체)를 참조하게 됩니다.

(2)

        var object = new Object();

object.scope = "field";

object.scopeCheck = function() { alert(“(2) ”+this.scope); } 

object.scopeCheck(); // 출력결과 예상

  이것은 전형적인 멤버함수의 호출입니다. 따라서 자연스럽게 객체의 멤버변수 scope의 값인 field를 출력하게 됩니다. 명시적 객체를 this가 바로 찾을 수 있기 때문에 global을 출력할 일이 없겠죠?

(3)
var scope = "global";

function scopeCheck() { 

var scope = "outterLocal";

function inner() { 

var scope = "innerLocal";

alert(“(3) ”+this.scope); 

}

}

inner(); // 출력결과 예상

  이 것은 전형적인 중첩함수 nested function 입니다. 자바스크립트에서 중첩함수를 쓸 일은 생각보다 많은데, 대부분 어휘적 유효범위를 구현하기 위해서 그렇습니다. 자바스크립트 1.5는 올바른 객체지향을 지원하지 않기 때문에 클로져가 아주 유용하게 사용되죠. 어휘적 유효범위와 클로져는함수 파트에서 알아볼 것입니다. 중첩함수내의 this키워드는 명시적 객체를 찾아 거슬러 올라갑니다. inner()를 호출한 객체는… 묵시적이군 패스, scopeCheck()를 호출한 객체는… 묵시적이군 패스, 아 더이상 거슬러 올라갈 수 없구나 전역객체를 참조해야겠군. 결국 global을 출력하게 되는 것이죠. 이런 중첩함수를 만나더라도 this 키워드는 명시적 ‘객체’만을 참조한다는 것을 기억하면 헤깔릴 일은 없을 것입니다. 혹시 innerLocal이나 outterLocal이 출력된다고 생각했다면 다시 생각해보세요!

(4)

  

var object = new Object();

object.scope = "field";

object.scopeCheck = function() { alert(“(2) ”+this.scope); } 

var anotherObject = new Object();

anotherObject.scope = "anotherField";

anotherObject.scopeCheck = function() { alert(“(4) ”+this.scope); } 

object.scopeCheck = anotherObject.scopeCheck;

object.scopeCheck(); // 출력결과 예상

  이것은 데이터 타입으로서의 함수가 관건입니다. 

object.scopeCheck = anotherObject.scopeCheck; 

이 부분에서 anotherObject의 멤버 함수가 object의 멤버함수로 할당되고 있습니다. anotherObject의 scopeCheck함수는 사실 무명함수에 대한 참조를 가지고 있을 뿐입니다. 따라서자바스크립트에서 함수는 호출 객체와 독립적으로 존재하고 있는 것입니다! 그저 둥둥 떠있을 뿐이죠!  anotherObject.scopeCheck의 함수 참조가 object.scopeCheck에 할당되었습니다. object에서 호출된 함수는 object의 것처럼 작동합니다. 따라서 최초에는 anotherObject에 할당된 함수 였지만 scopeCheck 함수상의 this키워드는 object를 가리켜 ‘another field’가 아닌 ‘field’를 출력하게 됩니다.

위의 예제를 통해 this로 발생되는 의문을 거의 모두 해결하셨으리라 생각되는군요. 이런 딱딱한 어체는 당분간 안쓰려고 했는데 오늘만큼은 봐주세요.

http://thinkberry.co.kr/728   에서 참조