我的编程空间,编程开发者的网络收藏夹
学习永远不晚

android Activity启动流程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

android Activity启动流程

Activity的启动过程,我们可以从Context的startActivity说起,其实现是ContextImpl的startActivity,然后内部会通过Instrumentation来尝试启动Activity,这是一个跨进程过程,它会调用ams的startActivity方法,当AMS校验完activity的合法性后,会通过ApplicationThread回调到我们的进程,这也是一次跨进程过程,而applicationThread就是一个binder,回调逻辑是在binder线程池中完成的,所以需要通过Handler H将其切换到ui线程,第一个消息是LAUNCH_ACTIVITY,它对应handleLaunchActivity,在这个方法里完成了Activity的创建和启动,接着,在activity的onResume中,activity的内容将开始渲染到window上,然后开始绘制直到我们看见(摘自网友的总结)

当在app内通过startActiviy启动一个新的Activity的时候,主要会调用以下几个函数

MyActivity.startActivity() 
Activity.startActivity() 
Activity.startActivityForResult 
Instrumentation.execStartActivty 
ActivityManagerNative.getDefault().startActivityAsUser() 

首选我们看一下startActivity方法

 @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

startAcitity最终会执行startActivityForResult方法,如果调用startActivity方法传入了-1,表示会有返回值返回。

继续向下看startActivityForResult方法

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                mStartedActivity = true;
            }
            cancelInputsAndStartExitTransition(options);
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

在上面的代码中,mParent进行了一个判Null操作,可以发现由于我们是第一次启动Activity,所以这里的mParent为空,所以会执行if分之,然后调用mInstrumentation.execStartActivity方法,

重点看下以下代码

nstrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);

mInstrumentation.execStartActivity中传递了几个参数,第二个参数mMainThread就是程序的主线程,它在app启动的时候创建的,即UI线程,mMainThread.getApplication()获取到binder对象,代表了app的主线程;mToken也是一个Binder对象,代表了上一个Activity也通过Instumentation传递给AMS,此时AMS就知道谁向自己发送的消息了。

mInstrumentation的execStartActivity方法

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        Uri referrer = target != null ? target.onProvideReferrer() : null;
        if (referrer != null) {
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

execStartActivity主要有以下几个参数

who:启动Activity对象

contextThread:Binder对象,为主进程的context对象

token:Binder对象,

target:为启动的目标Activity

intent:启动的Intent对象

requestCode:请求吗

options:参数

通过,execStartActivity方法可以发现,该方法主要调用ActivityManager.getService()方法

public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }
//继续看
    private static final Singleton IActivityManagerSingleton =
            new Singleton() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

变量IActivityManagerSingleton是个Singleton对象,下面看下Singleton源码

package android.util;

public abstract class Singleton {
    private T mInstance;
    protected abstract T create();
    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

 Singleton是一个抽象类,有一个抽象方法create()。有一个get()方法,内部通过单例模式创建T对象,调用create方法创建T对象,且只会创建一次T对象。

继续查看create方法的具体实现,IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE)获取一个关联了系统服务ActivityManagerService的Binder对象;IActivityManager.Stub.asInterface(b)返回一个IActivityManager的代理对象,基于Binder机制,通过调用代理对象的方法,使得系统服务ActivityManagerService对应的方法被调用。可以猜测ActivityManagerService肯定继承了IActivityManager.Stub,事实也确实如此。
       ActivityManagerService源码如下:

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	//...code
    }

回到Instrumentation.execStartActivity方法的ActivityManager.getService().startActivity(...),就是IActivityManager的代理对象调用了startActivity方法,通过Binder机制,它会使系统服务ActivityManagerService的startActivity方法被调用。因此,启动Activity的操作就交给了系统服务ActivityManagerService来处理了。

ApplicationThread继承了IApplicationThread.Stub,并提出ApplicationThread重写接口IApplicationThread的抽象方法在哪里被调用。有意思的是,app.thread调用scheduleLaunchActivity方法,通过Binder机制,会使ApplicationThread$scheduleLaunchActivity方法被调用。
       于是,基于Binder机制,实现了一次进程间的通信,将启动Activity的操作交给了ApplicationThread类。

 

ApplicationThread是ActivityThread的内部类,因此ApplicationThread可以调用外部类ActivityThread的方法,也可以这样理解,启动Activity的操作交给了ActivityThread来处理。

查看ActivityThread 的 scheduleLaunchActivity方法

@Override
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List pendingResults, List pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
            updateProcessState(procState, false);
            ActivityClientRecord r = new ActivityClientRecord();
            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            r.voiceInteractor = voiceInteractor;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            r.state = state;
            r.persistentState = persistentState;
            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;
            r.startsNotResumed = notResumed;
            r.isForward = isForward;
            r.profilerInfo = profilerInfo;
            r.overrideConfig = overrideConfig;
            updatePendingConfiguration(curConfig);
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

创建了一个ActivityClientRecord对象,用于封装启动Activity需要的一些参数值。

最后一行调用ActivityThread$sendMessage方法,查看其源码如下:

private void sendMessage(int what, Object obj) {
        sendMessage(what, obj, 0, 0, false);
}
//继续查看
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
}

第19行,mH是一个H对象,类H是ActivityThread的内部类,并继承了Handler。于是,启动Activity的操作放在处理消息的方法H$handleMessage中。

private class H extends Handler {
    //...code
	public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
	//...code
}

  第9行,取出Message对象中的obj字段,它是一个ActivityClientRecord对象;
       第10行,调用ActivityThread$getPackageInfoNoCheck方法,返回一个LoadedApk对象,并将该对象封装到ActivityClientRecord的packgeInfo字段中。
       第11行,调用ActivityThread$handleLaunchActivity方法启动Activity;

  查看ActivityThread$handleLaunchActivity源码如下:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    //...
    Activity a = performLaunchActivity(r, customIntent);
    //...
    if (a != null) {
        //...
        handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
        //...
    } else {
        // If there was an error, for any reason, tell the activity manager to stop us.
        try {
             ActivityManager.getService()
                    .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
    }
}

第4行,调用performLaunchActivity方法启动Activity;
       第11行,若a不为空,则调用handleResumeActivity方法,内部会调用Activity$onResume方法。具体的代码流程还是比较好跟的,由于不是本篇的重点,有兴趣的哥们可以自己去研究。
       第16行,当a为空,也就是创建Activity的实例出错了,走else语句。ActivityManager.getService()前面已经分析过了,返回IActivityManager的代理对象,调用该代理对象的方法,会向系统服务ActivityManagerService发送请求,基于Binder机制,最终会调用ActivityManagerService$finishActivity方法。
       也就是说,当创建Activity实例出错后,停止启动Activity的具体操作交给ActivityManagerService来处理。

 回到启动Activity的流程,查看ActivityThread$performLaunchActivity源码如下:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
        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);
        }
ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
	    //...code
            java.lang.ClassLoader cl = appContext.getClassLoader();
            if (appContext.getApplicationContext() instanceof Application) {
                activity = ((Application) appContext.getApplicationContext())
                        .instantiateActivity(cl, component.getClassName(), r.intent);
            }
            if (activity == null) {
                activity = mInstrumentation.newActivity(
                        cl, component.getClassName(), r.intent);
            }
	    //...code
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            //...code
            if (activity != null) {
		//...code
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);
                //...code
                mInstrumentation.callActivityOnCreate(activity, r.state);
		//...code
	     }
        return activity;
}

ActivityThread$performLaunchActivity方法的操作:
       1,获取要启动的Activity的ComponentName对象:里面包含了包名,类名相关的信息;
       2,创建Activity的上下文环境:即创建了ContextImpl对象;
       3,创建Activity的实例:调用Instrumentation$newActivity方法,并使用类加载器创建Activity对象;
       4,创建Application对象;
       5,调用Activity$attach方法:初始化Activity类里的一些数据;
       6,启动Activity:调用Instrumentation$callActivityOnCreate方法;

 分析ActivityThread$performLaunchActivity方法:


       步骤2,创建了Activity的上下文环境,ContextImpl是抽象类Context的实现类,有关Context的操作的具体实现,大多数由ContextImpl完成。
       查看ActivityThread$createBaseContextForActivity源码如下:

private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
	//...code
	ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
	//...code
	return appContext;
}

继续查看ContextImpl$createActivityContext源码如下:

static ContextImpl createActivityContext(ActivityThread mainThread,
            LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
            Configuration overrideConfiguration) {
	    //...code
	    ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
                activityToken, null, 0, classLoader);
	   //...code 
}

很显然,最终创建了一个ContextImpl对象。

 

 步骤3,创建了一个Activity的实例。

        查看Instrumentation$newActivity源码如下:

public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
    }

通过ClassLoader创建Activity的实例。

 

       步骤4,创建了Application对象

       查看LoadedApk$makeApplication方法源码如下:

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }
	Application app = null;
	//...
	app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
	//...
	mApplication = app;
	instrumentation.callApplicationOnCreate(app);
	//...
	return app;
}

 第3行,当mApplication不为null时,也就是Application对象已经存在时,直接返回mApplication。很显然Application是一个单例对象,一个应用程序中只存在一个Application对象。
       第11行,当应用程序内存中没有Application对象时,创建一个Application对象。跟Activity一样,都是通过类加载器ClassLoader来创建实例。具体代码就不再展示,有兴趣哥们可以去验证。
       第16行,将Application对象app赋给字段mApplication。
       第18行,调用Application的onCreate方法。
       查看Instrumentation$callApplicationOnCreate方法源码

    public void callApplicationOnCreate(Application app) {
        app.onCreate();
    }

 

步骤5,调用Activity$attach方法初始化数据。

       查看Activity$attach方法源码:

final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window) {
        attachBaseContext(context);
        mFragments.attachHost(null );
        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
        mUiThread = Thread.currentThread();
        mMainThread = aThread;
        mInstrumentation = instr;
        mToken = token;
        mIdent = ident;
        mApplication = application;
        mIntent = intent;
        mReferrer = referrer;
        mComponent = intent.getComponent();
        mActivityInfo = info;
        mTitle = title;
        mParent = parent;
        mEmbeddedID = id;
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
        if (voiceInteractor != null) {
            if (lastNonConfigurationInstances != null) {
                mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
            } else {
                mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                        Looper.myLooper());
            }
        }
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    }

 第8行,参数context:步骤2中创建的ContextImpl对象传入的。attachBaseContext方法:给ContextWrapper的成员变量mBase设置值为ContextImpl对象。ContextWrapper是Context的一个子类,具体的代码流程感兴趣的哥们可以去验证~
       第12行,创建了窗口对象PhoneWindow;
       第13~15行,给窗口对象注册监听接口;
       第23~37行,初始化一些变量的值;
       第47行,通过窗口Window创建WindowManagerImpl的实例;
       第54行,将47行创建的WindowManagerImpl的实例,设置给变量mWindowManager;

 

步骤6,调用Instrumentation$callActivityOnCreate方法启动Activity。

       查看Instrumentation$callActivityOnCreate源码:

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

 第3行,调用了Activity$performCreate方法。

       查看Activity$performCreate源码如下

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

第3行,调用了Activity的onCreate方法启动Activity,分析完成


作者:清甘茶


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

android Activity启动流程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

android Activity启动流程

Activity的启动过程,我们可以从Context的startActivity说起,其实现是ContextImpl的startActivity,然后内部会通过Instrumentation来尝试启动Activity,这是一个跨进程过程,它
2022-06-06

Android Activity启动流程刨析

Activity作为Android四大组件之一,他的启动绝对没有那么简单。这里涉及到了系统服务进程,启动过程细节很多,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
2022-11-13

android activity启动流程是什么

Android Activity的启动流程如下:1. 调用`startActivity()`方法或者`startActivityForResult()`方法启动目标Activity。2. 系统会检查启动目标Activity是否存在,并且是否
2023-08-08

activity启动流程是什么

Activity启动流程是指在Android应用中启动Activity的一系列操作。它包括以下步骤:1. 调用startActivity()方法:通过调用startActivity()方法,向系统发出启动Activity的请求。2. 系统检
2023-09-11

Android中 Activity的启动过程有哪些

Android中 Activity的启动过程有哪些,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。分析Android Activity的启动过程
2023-05-30

Android中activity的启动模式

activity的启动模式一共有四种:standard、singleTop、singleTask和singleInstance,可以在AndroidMannifest.xml中通过给标签指定android:launchM
2022-06-06

Android组件Activity的启动过程是什么

这篇文章主要介绍了Android组件Activity的启动过程是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Android组件Activity的启动过程是什么文章都会有所收获,下面我们一起来看看吧。在分析
2023-07-06

Android编程中Activity的四种启动模式

本文实例讲述了Android编程中Activity的四种启动模式。分享给大家供大家参考,具体如下: Activity启动方式有四种,分别是: standard singleTop singleTask singleInstance 可以根据
2022-06-06

android启动流程是什么

Android启动流程是指从手机开机到系统完全启动的过程。具体的流程如下:1. 电源按下:当用户按下电源键时,电源管理芯片会向处理器发送一个启动信号。2. 启动引导加载程序(Bootloader):处理器接收到启动信号后,会从内存中的固定地
2023-10-11

Android Service启动流程刨析

这几天分析了一下的启动过程,于是乎,今天写一下Service是如何启动的; 给我的感觉是这些启动过程并不复杂,千万不要被一坨一坨的代码吓住了,虽然弯弯绕绕不少,重载函数一个接着一个,就向走迷宫一样,但只要抓住主线阅读,很快就能找到出口
2022-11-13

[图解]Android源码分析——Activity的启动过程

Activity的启动过程一.Launcher进程请求AMSLauncher.java的startActivitySafely方法的执行过程:Activity.java中startActivity方法的执行过程:startActivityF
2022-06-06

Android组件Activity的启动过程深入分析

这篇文章主要介绍了Android组件Activity的启动过程,Activity作为Android四大组件之一,他的启动没有那么简单。这里涉及到了系统服务进程,启动过程细节很多,这里我只展示主体流程。activity的启动流程随着版本的更替,代码细节一直在进行更改,每次都会有很大的修改
2023-05-15

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录