Android Jetpack 应用指南(四) - Lifecycle

Lifecycle诞生的背景

在 Android 应用程序的开发过程,我们会经常遇到这样一个需求,一个第三方或系统组件需要在Activity/Fragment的onCreate()方法中初始化,在onPause()方法中停止组件,在onDestroy()中对组件进行资源回收。这样的工作非常繁琐,会让组件与页面的耦合度增高,但是这些繁琐的工作却又不得不做,否则可能会造成内存泄露。
我们希望我们对自定义的组件的管理,不依赖与页面的生命周期的回调方法,同时,在页面的生命周期发生变化时,也能及时收到通知。为此Google提供了Lifecycle作为解决方案。

什么是Lifecycle

Lifecycle 可以用于构建生命周期感知型组件,这些组件可以根据 Activity 或 Fragment 的当前生命周期状态调整行为。

Lifecycle的作用与意义

Lifecycle可以帮助开发者创建可感知生命周期的组件。这样,组件就可以在其内部管理自己的生命周期,从而降低模块间的耦合度,并降低内存泄露的发生
需要注意的是,LifeCycle不仅只对Activity/Fragment有用,在Service和Application中同样可以使用。

Lifecycle使用示例

使用Lifecycle监听Activity/Fragment的生命周期

接下来我们以一个案例来演示Lifecycle是如何使用的。
假设有这样一个常见的需求:在用户打开某个页面时,获取用户当前的地理位置。用户离开该页面后,则停止获取用户地理位置。面对这样的需求,我们通常会这么写

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 初始化任务管理器
        initLocationManager();
    }

    @Override
    protected void onStart() {
        super.onStart();
        // 获取用户位置
        getUserLocation();
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 停止获取用户位置
        stopGetLocation();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 释放任务管理器
        releaseLocationManager();
    }
}

从上述代码可以看出,获取地理位置这个需求的实现,和页面的生命周期息息相关。如果我们希望将获得地理位置这一功能独立成一个组件,那么我们不得不在页面生命周期各个回调方法中,对组件进行通知,只有这样组件才能感知到页面的生命周期变化(有经验的开发一定会注意到,这就是早期MVP架构中Presenter感知页面生命周期的做法)。
面对这个问题,接下来我们就来看看,LifeCycle是如何处理的。
在使用 Lifecycle 之前我们需要在应用或模块的build.gradle中添加lifecycle的依赖项

lifecycle-extensions 目前已经弃用。Google为我们提供了,可供自由选择的lifecycle组件

dependencies {
    def lifecycle_version = "2.3.1"
  
    // Lifecycles only (without ViewModel or LiveData)
    implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
  
}

我们为位置管理器定义一个类LocationObserver的类,LocationObserver需要实现LifecycleObserver接口。如果我们需要得知页面的生命周期,只需要定义一个@OnLifecycleEvent(Lifecycle.Event.ON_XXX)标签即可,当页面的生命周期发生变化时,这些被标识的方法会自定被调用。如下所示:

//1. 自定义的LifecycleObserver观察者,用注解声明每个方法观察的宿主的状态
class LocationObserver extends LifecycleObserver{
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void onStart(@NotNull LifecycleOwner owner){
      //开启定位
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void onStop(@NotNull LifecycleOwner owner){
       //停止定位
    }
}

在Activity/Fragment中引用LocationObserver,并同过getLifecycle().addObserver(observer)方法将观察者与被观察者绑定起来,这样LocationObserver就能感知到Activity/Fragment的生命周期变化。如下所示:

//2. 注册观察者,观察宿主生命周期状态变化
class MyActivity extends AppCompactActivity{
  public void onCreate(Bundle bundle){
    
    MyLifecycleObserver observer =new MyLifecycleObserver();
    getLifecycle().addObserver(observer);
    
  }
}

//2. 注册观察者,观察宿主生命周期状态变化
class MyFragment extends Fragment{
  public void onCreate(Bundle bundle){
    
    MyLifecycleObserver observer =new MyLifecycleObserver();
    getLifecycle().addObserver(observer);
    
  }
}

除了继承LifecycleObserver运用注解的形式来实现宿主生命周期的监听,Lifecycle组件中还提供了LifecycleEventObserver来监听宿主的生命周期。

  public class LocationObserver implements LifecycleEventObserver {

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
                               @NonNull Lifecycle.Event event) {
        //需要自行判断event是onstart, 还是onstop
    }
}

如果你的项目使用了Java8,那么你还可以使用DefaultLifecycleObserver来监听宿主的生命周期。
使用DefaultLifecycleObserver之前,你还需要在build.gradle中额外引入以下依赖

dependencies {
    def lifecycle_version = "2.3.1"
  ...//省略其它依赖
  implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
}

然后实现DefaultLifecycleObserver接口,根据需要实现里面的方法即可。

public class LocationObserver implements DefaultLifecycleObserver {

    @Override
    public void onCreate(@NonNull LifecycleOwner owner) {

    }

    @Override
    public void onStart(@NonNull LifecycleOwner owner) {

    }

    @Override
    public void onResume(@NonNull LifecycleOwner owner) {

    }

    @Override
    public void onPause(@NonNull LifecycleOwner owner) {

    }

    @Override
    public void onStop(@NonNull LifecycleOwner owner) {

    }

    @Override
    public void onDestroy(@NonNull LifecycleOwner owner) {

    }
}

需要额外注意的是,如果你正在使用Java8,那么首先应该考虑的选择是使用DefaultLifecycleObserver而不是LifecycleObserver

  • 如果业务类同时实现DefaultLifecycleObserverLifecycleEventoServer,则将首先调用DefaultLifecycleObserver的方法,然后再调用LifecycleEventoServer.onStateChanged(LifecycleOwner,Lifecycle.Event)
  • 如果一个类实现了DefaultLifecycleObserver,又同时使用了OnLifecycleEvent注解,那么注解方法将被忽略。

使用Lifecycle监听Service的生命周期

在上面我们介绍了如何在组件中监听Activity/Fragment的生命周期,在Android中Service同样是一个拥有生命周期的重要组件。

为了便于对Service生命周期的监听,达到解耦Service与组件的目的,Google提供了一个LifecycleService的类。该类继承自Service,并实现了LifeCycleOwner接口,与Activity/Fragment类似,它也提供了一个名为getLifeCycle()的方法供我们使用,除此以外,它与普通的Service使用起来并无差别。LifecycleService的源码如下:

public class LifecycleService extends Service implements LifecycleOwner {

    private final ServiceLifecycleDispatcher mDispatcher = new ServiceLifecycleDispatcher(this);

    @CallSuper
    @Override
    public void onCreate() {
        mDispatcher.onServicePreSuperOnCreate();
        super.onCreate();
    }

    @CallSuper
    @Nullable
    @Override
    public IBinder onBind(@NonNull Intent intent) {
        mDispatcher.onServicePreSuperOnBind();
        return null;
    }

    @SuppressWarnings("deprecation")
    @CallSuper
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        mDispatcher.onServicePreSuperOnStart();
        super.onStart(intent, startId);
    }

    // this method is added only to annotate it with @CallSuper.
    // In usual service super.onStartCommand is no-op, but in LifecycleService
    // it results in mDispatcher.onServicePreSuperOnStart() call, because
    // super.onStartCommand calls onStart().
    @CallSuper
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @CallSuper
    @Override
    public void onDestroy() {
        mDispatcher.onServicePreSuperOnDestroy();
        super.onDestroy();
    }

    @Override
    @NonNull
    public Lifecycle getLifecycle() {
        return mDispatcher.getLifecycle();
    }
}

Android原生的Service因为并未实现LifecycleOwner接口,所以LiveData等需要感知生命周期组件,就无法在Service中使用。为了解决这个问题,Android中提供了一个支持Lifecycle功能的LifecycleService
1.在 Service 中使用 Lifecycle 首先需要在build.gradle中添加相关依赖

dependencies {
    def lifecycle_version = "2.3.1"
    
    // optional - helpers for implementing LifecycleOwner in a Service
    implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"

}

2.添加相应的依赖之后,我们在创建Service时需要让它继承LifecycleService,LifecycleService是Service的子类,它在Service的基础上实现了LifecyclerOwner接口,并提供getLifecycle()方法以便我们使用。除此以外,它与普通的Service使用起来并无差别。

public class MainService extends LifecycleService {

    public MyLifecycleObserver observer;
    
    public MainService() {
        observer = new MyLifecycleObserver();
        getLifecycle().addObserver(observer);
    }
}

使用Lifecycle监听Application的生命周期

具有生命周期的系统组件,除了Activity、Fragment和Service外,还有Application。很多时候,我们会遇到这样的需求:我们想知道应用程序当前是前台还是后台,或者当应用程序从后台回到前台时,我们能够得到通知。以前也有不少方案能实现,但是大多比较繁琐,现在利用Lifecycle组件中的ProcessLifecycleOwner,可以非常轻松的监控整个应用程序的生命周期。
1.监听 Application 的生命周期,首先需要在build.gradle中添加相关依赖

dependencies {
    def lifecycle_version = "2.3.1"
    
    // optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
    implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"

}

2.然后,定义一个AppLifecycle的类,该类实现LifecycleObserver接口,负责监控整个应用程序的生命周期。

public class AppLifecycle implements LifecycleObserver {

        @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
        public void onAppCreate() {
            // 在应用的生命周期内,只会被回调一次
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        public void onAppStart() {
            // 当应用在前台出现时被回调
        }
        
        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        public void onAppResume() {
           // 当应用在前台出现时被回调
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        public void onAppPause() {
           // 当应用退出到后台时被回调
        }
        
        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        public void onAppStop() {
           // 当应用退出到后台时被回调
        }
        
        @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        public void onAppDestroy() {
           // 永远不会被调用,系统不会分发ON_DESTROY事件
        }
    }

需要注意的是,监控应用程序生命周期的时候,Lifecycle.Event.ON_CREATE只会被回调一次,Lifecycle.Event.ON_DESTROY则永远不会被回调。
3.接下来在Application中使用ProcessLifecycleOwner.get().getLifecycle().addObserver()方法添加观察者,示例如下:

public class AbsApplication extends Application {

    @Override
    public void onCreate() {
        ProcessLifecycleOwner.get().getLifecycle().addObserver(new AppLifecycle());
        super.onCreate();
    }
}

实际上监听整个应用生命周期并不需要在Application中添加观察者,我们可以在任意合适的地方调用 ProcessLifecycleOwner.get().getLifecycle().addObserver(new AppLifecycle()),但是,如果你需要监听Lifecycle.Event.ON_CREATE事件,就必须在Application生命周期进入OnCreate()之前完成观察者的添加。

Lifecycle原理解析

Fragment是如何实现Lifecycle的

Fragemnt中关于Lifecycle的核心代码如下

public class Fragment implements LifecycleOwner {
LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
  @Override
  public Lifecycle getLifecycle() {  
      return mLifecycleRegistry;
  }
  
 void performCreate(){
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
  }
  
 void performStart(){
     mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
  }
  .....
 void performResume(){
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
  }  
}

Fragment中主要就是实现LifecycleOwner接口,然后通过LifecycleRegistry来分发各个生命周期的事件。LifecycleRegistry是整个Lifecycle组件最核心的功能。LifecycleRegistry的工作原理非常复杂,我们在之后的章节中再做介绍。

Activity是如何实现Lifecycle的

Activity在实现上并不类似Fragment,而是额外在Activity中加入了一个ReportFragment来实现对生命周期的分发,主要目的是为了兼容一些不继承自AppComponentActivity的Activity也可以使用Lifecycle的特性。核心源码如下:

public class ComponentActivity extends Activity implements LifecycleOwner{
  private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
   @NonNull
   @Override
   public Lifecycle getLifecycle() {
      return mLifecycleRegistry;
   }
  
  protected void onCreate(Bundle bundle) {
      super.onCreate(savedInstanceState);
      ReportFragment.injectIfNeededIn(this); 
}

接下来我们继续分析ReportFragmentReportFragment中没有加载布局,所以他在Activity中实际是是一个不可见Fragment。它的源码也很简单,本质上就是通过FragmentManager将Fragment加载到Activity中,然后Fragment的生命周期发生变化时,获取Activity中的LifecycleRegistry对象,将事件分发出去。

public class ReportFragment extends Fragment{
  public static void injectIfNeededIn(Activity activity) {
        android.app.FragmentManager manager = activity.getFragmentManager();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
            manager.executePendingTransactions();
        }
  }

    @Override
    public void onStart() {
        super.onStart();
        dispatch(Lifecycle.Event.ON_START);
    }

    @Override
    public void onResume() {
        super.onResume();
        dispatch(Lifecycle.Event.ON_RESUME);
    }

    @Override
    public void onPause() {
        super.onPause();
        dispatch(Lifecycle.Event.ON_PAUSE);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        dispatch(Lifecycle.Event.ON_DESTROY);
    }

    private void dispatch(Lifecycle.Event event) {
         Lifecycle lifecycle = activity.getLifecycle();
         if (lifecycle instanceof LifecycleRegistry) {
             ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
         }
}  

Lifecycle是如何分发宿主状态的

观察者与宿主生命周期的对齐

通过查看Fragment/Activity的源代码,我们发现LifecycleRegistry才是负责分发生命周期事件的核心,在分析LifecycleRegistry是如何进行事件分发之前,我们先来看看我们在Activity/Fragmnent中调用的addObserver()方法干了些什么。

 @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        ...
        // 初始化一个State状态值
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        // 将宿主状态的初始值,和传递进来的`LifecycleObserver`封装成一个`ObserverWithState`对象
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
                ...
                // `calculateTargetState(observer)`计算得出当前宿主的状态
        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        // 循环比对宿主状态与观察者的状态,如果不同步,将`ObserverWithState`的状态前进到和宿主相同的状态
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            // 根据观察者当前状态,得到它的下一步状态。需要注意,状态的前进是步进的,它并不会跳过事件,而是依次前进,多次分发。
            final Event event = Event.upFrom(statefulObserver.mState);
            ...
            // 分发状态
            statefulObserver.dispatchEvent(lifecycleOwner, event);
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }
      ...
    }

addObserver()的逻辑大致可以分为以下流程

  • 1.初始化一个State状态值
  • 2.将宿主状态的初始值,和传递进来的LifecycleObserver封装成一个ObserverWithState对象
  • 3.将ObserverWithState对象存入一个Map中
  • 4.calculateTargetState(observer)计算得出当前宿主的状态
  • 5.将ObserverWithState的状态前进到和宿主相同的状态
    • 5.1 分发状态变化,内部会调用onStateChanged()方法
            void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = event.getTargetState();
            mState = min(mState, newState);
            // 分发状态
            mLifecycleObserver.onStateChanged(owner, event);
            // 观察者,内部状态更新
            mState = newState;
        }

通过上述分析,可以看出,addObserver方法主要就完成两个任务,1.将宿主和观察者关联起来;2.将观察者的生命周期与宿主对齐。
但是我们有两点需要注意:

  • 第一:宿主的状态并不等同于宿主的生命周期,他们的关系如下图。


    宿主状态与生命周期.jpg
  • 第二:观察者在同步宿主状态时,是依次步进的。即使宿主状态与观察者的状态存在多个间距,也不会从INITIALIZED直接跳到STARTED
    反应在开发中,我们就会观察到,如果在Activity的OnStop中注册了一个观察者,那么注册完毕后,该观察者实际上会立即收到OnCreateOnStartOnResumeOnPause的回调,并最终收到OnStop的回调。

宿主分发生命周期状态

handleLifecycleEvent()是宿主在生命周期发生变化时,主动调用的方法,由他负责完成观察者的状态变化和事件分发,接下来我们就来看一下它的实现逻辑:

    public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
        ...
        moveToState(event.getTargetState());
    }
        ...Lifecycle
        // 根据Event推导出下一步的状态
        public State getTargetState() {
            switch (this) {
                case ON_CREATE:
                case ON_STOP:
                    return State.CREATED;
                case ON_START:
                case ON_PAUSE:
                    return State.STARTED;
                case ON_RESUME:
                    return State.RESUMED;
                case ON_DESTROY:
                    return State.DESTROYED;
                case ON_ANY:
                    break;
            }
            throw new IllegalArgumentException(this + " has no target state");
        }
    ...    
    private void moveToState(State next) {
        ...
        // 更新宿主的状态
        mState = next;
        // 同步观察者的状态
        sync();
        ...
    }

    private void sync() {
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        ...
       // isSynced():判断宿主的状态与观察者状态是否已经同步
        while (!isSynced()) {
            mNewEventOccurred = false;
            // 当宿主状态发生倒退时,同步观察者的状态,并分发相应的事件
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass(lifecycleOwner);
            }
            Map.Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            //当宿主状态发生前进时,同步观察者的状态,并分发相应的事件
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
            }
        }
        mNewEventOccurred = false;
    }

相关逻辑在代码里已经有相应的注释,这里就不再赘述。到此为止我们就分析完了LifecycleRegistry是如何分发宿主生命周期事件了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • Lifecycle 简介 Lifecycle 是一个可以感知宿主生命周期变化的组件。常见的宿主包括 Activit...
    wuchao226阅读 1,377评论 0 0
  • 介绍 Lifecycle 它是 Jetpack 组件库的的核心基础 ,具备宿主生命周期感知能力的组件。它能持有组件...
    明朗__阅读 481评论 0 1
  • 提纲 什么是Lifecycle; 如何使用Lifecycle观察宿主状态; Fragment是如何实现Lifecy...
    rivenlee阅读 991评论 2 0
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 123,988评论 2 7
  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 6,030评论 0 4