activity生命周期分析

对于Android开发者来说activity的生命周期是再熟悉不过的东西了,对于下面这张图也是再熟悉不过了;
activity.png

从activity的创建到销毁,会走onCreate()、onStart()、onResume()、onPause()、onStop()、onDestory()等生命周期,对于开发者来说充分理解activity的生命周期可以在适当的回调方法中进行业务逻辑处理;不过这要说的并不是onCreate()、onStart()、onResume()、onPause()、onStop()、onDestory()等生命周期,而是从点击一个app图标这些生命周期是如何走的,界面是如何展示给用户的;说到这些,肯定会提到ActivityThread类。
ActivityThread:它是一个管理应用程序进程中主线程的执行、调度和执行活动,根据活动管理器的请求在其上广播和其他操作。
在用户点击app Launcher 图标时,会去调用ActivityThread类中的main方法,这也是应用程序的主入口;

public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        EventLogger.setReporter(new EventLoggingReporter());

        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");
 //实例化准备一个Looper
        Looper.prepareMainLooper();
//实例化一个ActivityThread对象
        ActivityThread thread = new ActivityThread();
//调用attach方法
        thread.attach(false);
//实例化handler对象
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//调用loop()进行消息轮询
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

在main方法中会实例化一个ActivityThread对象,在ActivityThread类中有一个mH成员变量,其实就是一个handler,在handler的handlerMessage回调中发现activity生命周期的方法在那里被调用,其实activity的生命周期都是通过handler消息来管理的,根据handler消息的类型会去调用handleLaunchActivity方法;


handleLaunchActivity.png

从流程图中知道会在handleLaunchActivity方法中调用performLaunchActivity方法,并返回一个Activity实例;

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        ......
        // Make sure we are running with the most recent config.
//配置参数
        handleConfigurationChanged(null, null);
        if (localLOGV) Slog.v(
            TAG, "Handling launch of " + r);
        // Initialize before creating the activity
//初始化WindowManagerGlobal
        WindowManagerGlobal.initialize();

        Activity a = performLaunchActivity(r, customIntent);
        ......
    }

跟着流程图和源码看看activity在performLaunchActivity方法中是如何创建的,

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
        ActivityInfo aInfo = r.activityInfo;
//获取apk包信息
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
//通过ComponentName和intent也可以启动一个activity
//Intent intent=new Intent();
//ComponentName componentName=ComponentName.createRelative(MainActivity.this,SecondActivity.class);
// intent.setComponent(componentName);
//startActivity(intent);
        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }
        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }
//为activity创建一个上下文
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
//通过反射实例化一个activity对象
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }
        try {
           ......
            if (activity != null) {
                .......
                appContext.setOuterContext(activity);
//调用activity中的attach方法,这个方法比较重要,这里暂时不说
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
               ......
                activity.mCalled = false;
//调用Instrumentation中的callActivityOnCreate方法,
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ......
                r.activity = activity;
                r.stopped = true;
                if (!r.activity.mFinished) {
//判断当前activity是否finish,如果没有finish就会调用activity中的performStart方法
                    activity.performStart();
                    r.stopped = false;
                }
               ......
//r.token就是一个IBinder对象,将IBinder为key,ActivityClientRecord对象为value缓存在map集合中
                mActivities.put(r.token, r);
              ......
        return activity;
    }

通过调用Instrumentation中的newActivity就实例化好了一个activity,看下activity在里面是如何被实例化的;

public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
//获取到应用程序的包名
        String pkg = intent != null && intent.getComponent() != null
                ? intent.getComponent().getPackageName() : null;
        return getFactory(pkg).instantiateActivity(cl, className, intent);
    }
public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
            @Nullable Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Activity) cl.loadClass(className).newInstance();
    }

通过传入的ClassLoader和应用程序包名实例化一个activity,这样子通过反射就实例化好一个activity,就会去调用attch方法,在attch方法中会绑定activity的上下文,初始化PhoneWindow、获取当前线程、setWindowManager等各种操作,而在Instrumentation的callActivityOnCreate方法中会根据实例化好的activity去调用它里面的performCreate方法;

public void callActivityOnCreate(Activity activity, Bundle icicle) {
        prePerformCreate(activity);
        activity.performCreate(icicle);
        postPerformCreate(activity);
    }

在activity的performCreate方法中就会看到调用了onCreate方法;

final void performCreate(Bundle icicle) {
        restoreHasCurrentPermissionRequest(icicle);
        onCreate(icicle);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
    }

调用完onCreate方法后,接着会根据实例化好的activity,并且当前activity没有finish,就会去调用自己的performStart()方法;

final void performStart() {
        ......
//通过传入当前的activity在Instrumentation的callActivityOnStart方法中调用activity自己的onStart方法
        mInstrumentation.callActivityOnStart(this);
        ......
        mActivityTransitionState.enterReady(this);
    }
public void callActivityOnStart(Activity activity) {
        activity.onStart();
    }

这样子activity的onCreate、onStart方法就走了;接着看onResume,先去看handleResumeActivity

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
//根据activity创建时缓存的IBinder获取对应的ActivityClientRecord对象
        ActivityClientRecord r = mActivities.get(token);
//检查和更新生命周期
        if (!checkAndUpdateLifecycleSeq(seq, r, "resumeActivity")) {
            return;
        }

        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        // TODO Push resumeArgs into the activity for consideration
//需要注意performResumeActivity方法的调用
        r = performResumeActivity(token, clearHide, reason);
        if (r != null) {
//这里的ActivityClientRecord对象不为null
//获取缓存中的activity实例
            final Activity a = r.activity;
            if (localLOGV) Slog.v(
                TAG, "Resume " + r + " started activity: " +
                a.mStartedActivity + ", hideForNow: " + r.hideForNow
                + ", finished: " + a.mFinished);

            final int forwardBit = isForward ?
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

            // If the window hasn't yet been added to the window manager,
            // and this guy didn't finish itself or start another activity,
            // then go ahead and add the window.
            boolean willBeVisible = !a.mStartedActivity;
            if (!willBeVisible) {
                try {
                    willBeVisible = ActivityManager.getService().willActivityBeVisible(
                            a.getActivityToken());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            if (r.window == null && !a.mFinished && willBeVisible) {
//获取activity attch初始化时的window对象
                r.window = r.activity.getWindow();
//获取window对象中的DecorView
                View decor = r.window.getDecorView();
//设置DecorView为不可见
                decor.setVisibility(View.INVISIBLE);
//获取activity中对应的ViewManager
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
//给window设置参数
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (r.mPreserveWindow) {
                    a.mWindowAdded = true;
                    r.mPreserveWindow = false;
                    // Normally the ViewRoot sets up callbacks with the Activity
                    // in addView->ViewRootImpl#setView. If we are instead reusing
                    // the decor view we have to notify the view root that the
                    // callbacks may have changed.
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if (impl != null) {
                        impl.notifyChildRebuilt();
                    }
                }
                if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        a.mWindowAdded = true;
//将设置好的DecorView通过ViewManager添加到布局中
                        wm.addView(decor, l);
                    } else {
                        // The activity will get a callback for this {@link LayoutParams} change
                        // earlier. However, at that time the decor will not be set (this is set
                        // in this method), so no action will be taken. This call ensures the
                        // callback occurs with the decor set.
                        a.onWindowAttributesChanged(l);
                    }
                }

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
            } else if (!willBeVisible) {
                if (localLOGV) Slog.v(
                    TAG, "Launch " + r + " mStartedActivity set");
                r.hideForNow = true;
            }

            // Get rid of anything left hanging around.
            cleanUpPendingRemoveWindows(r, false /* force */);

            // The window is now visible if it has been added, we are not
            // simply finishing, and we are not starting another activity.
            if (!r.activity.mFinished && willBeVisible
                    && r.activity.mDecor != null && !r.hideForNow) {
                if (r.newConfig != null) {
                    performConfigurationChangedForActivity(r, r.newConfig);
                    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity "
                            + r.activityInfo.name + " with newConfig " + r.activity.mCurrentConfig);
                    r.newConfig = null;
                }
                if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward="
                        + isForward);
                WindowManager.LayoutParams l = r.window.getAttributes();
                if ((l.softInputMode
                        & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
                        != forwardBit) {
                    l.softInputMode = (l.softInputMode
                            & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
                            | forwardBit;
                    if (r.activity.mVisibleFromClient) {
                        ViewManager wm = a.getWindowManager();
                        View decor = r.window.getDecorView();
//通过ViewManager更新布局的摆放
                        wm.updateViewLayout(decor, l);
                    }
                }

                r.activity.mVisibleFromServer = true;
                mNumVisibleActivities++;
                if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
                }
            }

            if (!r.onlyLocalRequest) {
                r.nextIdle = mNewActivities;
                mNewActivities = r;
                if (localLOGV) Slog.v(
                    TAG, "Scheduling idle handler for " + r);
                Looper.myQueue().addIdleHandler(new Idler());
            }
            r.onlyLocalRequest = false;

            // Tell the activity manager we have resumed.
            if (reallyResume) {
                try {
                    ActivityManager.getService().activityResumed(token);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }

        } else {
            // If an exception was thrown when trying to resume, then
            // just end this activity.
            try {
                ActivityManager.getService()
                    .finishActivity(token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }

一进入handleResumeActivity方法就去调用了performResumeActivity方法,

public final ActivityClientRecord performResumeActivity(IBinder token,
            boolean clearHide, String reason) {
//通过缓存的IBinder获取ActivityClientRecord对象
        ActivityClientRecord r = mActivities.get(token);
        if (localLOGV) Slog.v(TAG, "Performing resume of " + r
                + " finished=" + r.activity.mFinished);
        if (r != null && !r.activity.mFinished) {
//这里的ActivityClientRecord 对象不为空且当前activity也没有finish掉
            ......
//调用performResume
                r.activity.performResume();
            ......
        }
        return r;
    }
final void performResume() {
//这里也会先调用performRestart方法,
        performRestart();
      ......
        mInstrumentation.callActivityOnResume(this);
       ......
    }

和onStart的流程一样,在performResume方法中还是通过Instrumentation中的callActivityOnResume方法利用传入的当前activity,去调用自己的onResume方法;

public void callActivityOnResume(Activity activity) {
        activity.mResumed = true;
        activity.onResume();
        
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    am.match(activity, activity, activity.getIntent());
                }
            }
        }
    }

不过不同的是,在调用onResume的同时会接着在handleResumeActivity方法中根据activity创建时缓存的对象获取Window、DecorView、ViewManager等实例,并进行参数设置,将设置好参数的view通过ViewManager添加到布局中,也是在onResume生命周中,将布局和view绘制渲染完毕,添加到布局中展示给用户;onResume走完就是onPause,在handlePauseActivity方法中和handleResumeActivity一样,也是根据缓存获取对应的实例对象,判断检查和更新生命周期,调用performPauseActivity方法;

private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport, int seq) {
        ActivityClientRecord r = mActivities.get(token);
        if (DEBUG_ORDER) Slog.d(TAG, "handlePauseActivity " + r + ", seq: " + seq);
        if (!checkAndUpdateLifecycleSeq(seq, r, "pauseActivity")) {
            return;
        }
        if (r != null) {
            //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
            if (userLeaving) {
                performUserLeavingActivity(r);
            }
            r.activity.mConfigChangeFlags |= configChanges;
//注意performPauseActivity的调用
            performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
            // Make sure any pending writes are now committed.
            if (r.isPreHoneycomb()) {
                QueuedWork.waitToFinish();
            }
            // Tell the activity manager we have paused.
            if (!dontReport) {
                try {
                    ActivityManager.getService().activityPaused(token);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }
            mSomeActivitiesChanged = true;
        }
    }

在performPauseActivity中利用重载调用的是多一个参数的performPauseActivity方法;

final Bundle performPauseActivity(IBinder token, boolean finished,
            boolean saveState, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        return r != null ? performPauseActivity(r, finished, saveState, reason) : null;
    }

这样就只能去看多一个参数的performPauseActivity方法逻辑了;

final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
            boolean saveState, String reason) {
//finished这个参数上面传入的是tr
        if (r.paused) {
//走到这里activity还没有finish
            if (r.activity.mFinished) {
                // If we are finishing, we won't call onResume() in certain cases.
                // So here we likewise don't want to call onPause() if the activity
                // isn't resumed.
                return null;
            }
            RuntimeException e = new RuntimeException(
                    "Performing pause of activity that is not resumed: "
                    + r.intent.getComponent().toShortString());
            Slog.e(TAG, e.getMessage(), e);
        }
        if (finished) {
//改变activity finish的状态 
            r.activity.mFinished = true;
        }

        // Next have the activity save its current state and managed dialogs...
        if (!r.activity.mFinished && saveState) {
            callCallActivityOnSaveInstanceState(r);
        }
//在该方法中会调用Instrumentation中的callActivityOnPause方法
        performPauseActivityIfNeeded(r, reason);

        // Notify any outstanding on paused listeners
//定义一个OnActivityPausedListener 集合
        ArrayList<OnActivityPausedListener> listeners;
        synchronized (mOnPauseListeners) {
//将当前onPause的activity中mOnPauseListeners中移除并将移除返回的数据赋值给listeners
            listeners = mOnPauseListeners.remove(r.activity);
        }
        int size = (listeners != null ? listeners.size() : 0);
        for (int i = 0; i < size; i++) {
//遍历listeners集合
            listeners.get(i).onPaused(r.activity);
        }

        return !r.activity.mFinished && saveState ? r.state : null;
    }

剩下的就会onCreate的调用走向差不多了;

public void callActivityOnPause(Activity activity) {
        activity.performPause();
    }

handleStopActivity和handlePauseActivity差不多,这里就不写了,自己可以在ActivityThread类中慢慢看,就接着看handleDestroyActivity方法;handleDestroyActivity在调用onDestory的逻辑走向和之前那些一样的,这里就只说下当activity调用onDestory后页面、页面上的view、activity实例的处理;

private void handleDestroyActivity(IBinder token, boolean finishing,
            int configChanges, boolean getNonConfigInstance) {
//一样调用performDestroyActivity 在performDestroyActivity方法中会调用Instrumentation的
//callActivityOnDestroy方法,接着调用activity中的onDestory方法
        ActivityClientRecord r = performDestroyActivity(token, finishing,
                configChanges, getNonConfigInstance);
        if (r != null) {
//移除activity中的window对象,在cleanUpPendingRemoveWindows方法中,会将window移除调用将window对象置为null
            cleanUpPendingRemoveWindows(r, finishing);
//获取对应的windowManager实例
            WindowManager wm = r.activity.getWindowManager();
//获取DecorView
            View v = r.activity.mDecor;
            if (v != null) {
                if (r.activity.mVisibleFromServer) {
                    mNumVisibleActivities--;
                }
                IBinder wtoken = v.getWindowToken();
                if (r.activity.mWindowAdded) {
                    if (r.mPreserveWindow) {
                        // Hold off on removing this until the new activity's
                        // window is being added.
                        r.mPendingRemoveWindow = r.window;
                        r.mPendingRemoveWindowManager = wm;
                        // We can only keep the part of the view hierarchy that we control,
                        // everything else must be removed, because it might not be able to
                        // behave properly when activity is relaunching.
//将window上的view清除掉
                        r.window.clearContentView();
                    } else {
//移除window上的view
                        wm.removeViewImmediate(v);
                    }
                }
                if (wtoken != null && r.mPendingRemoveWindow == null) {
                    WindowManagerGlobal.getInstance().closeAll(wtoken,
                            r.activity.getClass().getName(), "Activity");
                } else if (r.mPendingRemoveWindow != null) {
                    // We're preserving only one window, others should be closed so app views
                    // will be detached before the final tear down. It should be done now because
                    // some components (e.g. WebView) rely on detach callbacks to perform receiver
                    // unregister and other cleanup.
                    WindowManagerGlobal.getInstance().closeAllExceptView(token, v,
                            r.activity.getClass().getName(), "Activity");
                }
//移除完view后将DecorView置为null
                r.activity.mDecor = null;
            }
            if (r.mPendingRemoveWindow == null) {
                // If we are delaying the removal of the activity window, then
                // we can't clean up all windows here.  Note that we can't do
                // so later either, which means any windows that aren't closed
                // by the app will leak.  Well we try to warning them a lot
                // about leaking windows, because that is a bug, so if they are
                // using this recreate facility then they get to live with leaks.
                WindowManagerGlobal.getInstance().closeAll(token,
                        r.activity.getClass().getName(), "Activity");
            }

            // Mocked out contexts won't be participating in the normal
            // process lifecycle, but if we're running with a proper
            // ApplicationContext we need to have it tear down things
            // cleanly.
            Context c = r.activity.getBaseContext();
            if (c instanceof ContextImpl) {
                ((ContextImpl) c).scheduleFinalCleanup(
                        r.activity.getClass().getName(), "Activity");
            }
        }
        if (finishing) {
            try {
                ActivityManager.getService().activityDestroyed(token);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
        mSomeActivitiesChanged = true;
    }

通过上面知道activity调用onDestory后,只是将window上的view进行移除,并将DecorView置为null,并没有将当前的activity实例置为null,所以activity调用onDestory后,页面销毁了,但是activity实例一直在内存中,等待gc的回收,如果内存中的activity实例还被持有,就会造成内存泄露,这是开发中需要注意的。

总结:
1.activity的生命周期是通过handler消息来控制的;
2.activity的实例创建是通过反射来实现的;
3.在activity onResume生命周期后,才将布局view绘制添加到系统布局中并显示给用户;
4.在activity onDestory生命周期后,只是将window、window中的view,DecorView移除并置为null,并没有将activity实例置为null,activity实例仍然在内存中,如果在gc时还有持有该activity的引用就会造成内存泄露,也就是说activity onDestory后只是页面的销毁,并不代表当前activity实例的销毁。

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

推荐阅读更多精彩内容

  • 1 概述 在上述的多种状态中,只有三个状态是持久的,其余都是瞬时状态:resumed,paused,stopped...
    lee_3do阅读 903评论 0 1
  • 【Android Activity】 什么是 Activity? 四大组件之一,通常一个用户交互界面对应一个 ac...
    Rtia阅读 3,796评论 3 18
  • onCreate():表示Activity正在创建,可以做初始化操作,setContentView(),初始化Ac...
    西鳳梨阅读 359评论 0 0
  • Activity生命周期分析 标准情况下 onCreate():表示Activity正在创建中,初始化工作,比如调...
    myserendipit阅读 489评论 1 7
  • 走夜路总是觉得有人在后面跟踪,紧张地一回头,看见身后一片漆黑,又觉得鬼跑到身前了;不自觉加快步伐,快跑,不然就被杀...
    AOS加贝阅读 395评论 0 3