RELATEED CONSULTING
相关咨询
选择下列产品马上在线沟通
服务时间:8:30-17:00
你可能遇到了下面的问题
关闭右侧工具栏

新闻中心

这里有您想知道的互联网营销解决方案
预加载android,预加载群成员

【Android】Android中的类加载

前文: 【Java】ClassLoader与双亲委派机制

耀州网站制作公司哪家好,找创新互联建站!从网页设计、网站建设、微信开发、APP开发、响应式网站开发等网站项目制作,到程序开发,运营维护。创新互联建站从2013年开始到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选创新互联建站

Android中的类加载器有三种, DexClassLoader 、 PathClassLoader 、 BootClassLoader 。

其中 BootClassLoader 是系统启动时预加载常用类的,一般使用不到。 DexClassLoader 、 PathClassLoader 都是继承自 BaseDexClassLoader 。

但 DexClassLoader 和 PathClassLoader 并没有重写 BaseDexClassLoader 中的任何方法,所以源码只需要看 BaseDexClassLoader 即可。

由于Android SDK并没有包含 BaseDexClassLoader ,所以需要到源码查询网站查询源码,如下:

复制这个java文件到对应源码文件夹下就可以在Android Studio中查看了。

通过调试可以看到,Android中普通类的加载器其实是 PathClassLoader 。追踪 PathClassLoader.findClass 方法,即可获取Android的类加载过程:

PathClassLoader.findClass -- 继承自 -- BaseDexClassLoader.findClass()

- BaseDexClassLoader.pathList.findClass()

- DexPathList.dexElements.foreach { element.findClass() }

- Element.findClass()

- Element.dexFile.loadClassBinaryName()

- DexFile.defineClass()

即类加载过程通过 BaseDexClassLoader.findClass 、 DexPathList.findClass 、 Element.findClass 、 DexFile.loadClassBinaryName ,最终会落到 DexFile.defineClass 方法中,然后就交给native层了。

其中需要注意的是,在 BaseDexClassLoader.findClass 的开头有这么一段:

这段是在Android 10新加入的,据称是为了实现 shared library 功能的,在之前的版本中没有这一段。

在上一节中知道了,类加载的流程如下:

BaseDexClassLoader.findClass() -

BaseDexClassLoader.pathList.findClass() -

DexPathList.dexElements.foreach { element.findClass() } -

Element.findClass() - ...

看 DexPathList.findClass 方法:

可以发现, DexPathList 加载类的方法是遍历 dexElements 数组依次加载,知道获取到值为止。所以可以通过修改这个数组,把新的dex文件放在数组的前面,使其加载修改后的类,从而实现热修复。

根据以上原理,写下这个工具类,有效性待验证:

安卓应用启动详解:从Zygote到你的Activity.onCreate()

翻译自:

这篇文章讲解当用户点击应用图标时,安卓如何启动你的应用。安卓系统做了很多幕后工作,来使得你的launch activity对用户可见。本文通过重要阶段的讲解和调用序列详细讲解这一过程。

安卓应用在这两个方面是独特的:

多个入口点 :Android应用程序由不同的组件组成,它们可以调用其他应用程序拥有的组件。这些组件大致对应于任何应用程序的多个入口点。因此,它们不同于具有像main()方法那样的单个入口点的传统应用程序。

拥有自己的小世界 :每个Android应用程序都生活在自己的世界中,它在单独的进程中运行,拥有自己的Dalvik VM实例,并分配有唯一的用户ID。

必要时会启动Android进程。

每当用户或其他系统组件请求执行属于您应用程序的组件(可能是服务,活动或意图接收器)时,Android系统都会为您的应用程序启动一个新进程(如果尚未运行)。通常,进程一直运行直到被系统杀死。应用程序流程是按需创建的,在您看到应用程序的启动活动启动并运行之前,发生了许多事情。

每个应用程序都在其自己的进程中运行 :默认情况下,每个Android应用程序都在其自己的Android进程中运行,而这个进程只不过是一个Linux进程,而该进程首先需要一个执行线程。例如,当您单击电子邮件中的超链接时,网页将在浏览器窗口中打开。您的邮件客户端和浏览器是两个单独的应用程序,它们分别在两个单独的进程中运行。click事件使Android平台启动新进程,以便它可以在其自身进程的上下文中实例化浏览器活动。这对于应用程序中的任何其他组件同样适用。

让我们退后一会儿,快速浏览一下系统启动过程。与大多数基于Linux的系统一样,启动加载程序在启动时将加载内核并启动init进程。然后,init会生成称为“守护程序”的低级Linux进程,例如android debug守护程序,USB守护程序等。这些守护程序通常处理低级硬件接口,包括无线电接口。

然后,初始化过程会启动一个非常有趣的过程,称为“zygote'。

顾名思义,这是其余Android应用程序的开始。这是初始化Dalvik虚拟机的第一个实例的过程。它还预加载Android应用程序框架和系统上安装的各种应用程序使用的所有常见类。因此,它准备进行复制。它统计侦听套接字接口上的将来请求,以产生新的虚拟机(VM)来管理新的应用程序进程。收到新请求后,它会分叉以创建一个新进程,该进程将获取预先初始化的VM实例。

zygote之后,init启动运行时过程。

然后zygote分叉以启动一个名为System server的托管良好的进程。系统服务器在其自己的上下文中启动所有核心平台服务,例如活动管理器服务和硬件服务。

此时,完整的堆栈已准备就绪,可以启动第一个应用程序流程-主页应用程序,该应用程序显示主屏幕(也称为启动器应用程序)。

click事件被转换为 startActivity(intent), 并通过Binder IPC路由到 ActivityManagerService 。ActvityManagerService执行多个步骤

如您所见,当用户单击图标并启动新应用程序时,许多事情发生在幕后。这是全图:

流程创建:

ActivityManagerService 通过调用 startProcessLocked() 方法创建一个新进程,该方法通过套接字连接将参数发送到Zygote进程。Zygote派生自己并调用 ZygoteInit.main() ,然后实例化 ActivityThread 对象并返回新创建的进程的进程ID。

默认情况下,每个进程都有一个线程。主线程有一个 Looper 实例来处理来自消息队列的消息,并且它在 run() 方法的每次迭代中都调用 Looper.loop() 。 Looper 的工作是从消息队列中弹出消息并调用相应的方法来处理它们。然后,ActivityThread通过随后调用 Looper.prepareLoop() 和 Looper.loop()来 启动消息循环。

以下序列详细捕获了调用序列:

figcaption class="jv jw di dg dh jx jy bo b fc cp ga" data-selectable-paragraph="" style="box-sizing: inherit; font-weight: 400; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 20px; margin-left: auto; margin-right: auto; max-width: 728px; font-size: 14px; color: rgb(117, 117, 117); margin-top: 10px; text-align: center;"Android应用启动:单击事件以执行Looper调用顺序/figcaption

应用程序绑定:

下一步是将此新创建的过程附加到特定应用程序。这是通过在线程对象上调用 bindApplication() 来完成的。此方法将 BIND_APPLICATION 消息发送到消息队列。该消息由 Handler 对象检索,该对象随后调用 handleMessage() 方法以触发特定于消息的操作 -handleBindApplication() 。此方法调用 makeApplication() 方法,该方法将应用程序特定的类加载到内存中。

下图描述了该调用序列。

figcaption class="jv jw di dg dh jx jy bo b fc cp ga" data-selectable-paragraph="" style="box-sizing: inherit; font-weight: 400; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 20px; margin-left: auto; margin-right: auto; max-width: 728px; font-size: 14px; color: rgb(117, 117, 117); margin-top: 10px; text-align: center;"Android应用启动:BIND_APPLICATION消息处理/figcaption

启动活动:

在上一步之后,系统包含负责应用程序的进程,并将应用程序类加载到进程的私有内存中。在新创建的流程和现有流程之间,启动活动的调用顺序很常见。

实际的启动过程从 realStartActivity() 方法开始, 该 方法在应用程序线程对象上调用 sheduleLaunchActivity() 。此方法将 LAUNCH_ACTIVITY 消息发送到消息队列。该消息由 handleLaunchActivity() 方法处理,如下所示。

假设用户单击“视频浏览器”应用程序。启动该活动的调用顺序如图所示。

figcaption class="jv jw di dg dh jx jy bo b fc cp ga" data-selectable-paragraph="" style="box-sizing: inherit; font-weight: 400; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 20px; margin-left: auto; margin-right: auto; max-width: 728px; font-size: 14px; color: rgb(117, 117, 117); margin-top: 10px; text-align: center;"Android应用启动: LAUNCH_ACTIVITY消息处理 /figcaption

该活动通过 onCreate() 方法调用开始其托管生命周期。该活动通过 onRestart() 调用进入前台,并通过 onStart() 调用开始与用户进行交互。

如何预加载文件或DB到android应用程序

我做一个项目,里面是要把DB文件打包到APK中让用户安装时自动安装到机器中,具体做法是把文件放到res\raw目录下,代码为

/*存取卡路径*/

sdcardDir = Environment.getExternalStorageDirectory();

DBPath = sdcardDir.getPath()+sdcardDir.separator+"Weather";

File tempDir = new File(DBPath);

if(!tempDir.exists()){

tempDir.mkdir();

}

DBFile = new File(DBPath+"/"+DBName);

if(!DBFile.exists()){

//数据库文件不存在则拷贝数据到指定路径下

//CityDB = new CityDBOperation(DBPath+"/"+DBName);

//CityDB.CreateCityTB();

try{

dbFile = new FileOutputStream(DBPath+"/"+DBName);

in = getResources().openRawResource(R.raw.weather);

out = new BufferedOutputStream(dbFile);

while((pos=in.read(read))!= -1){

out.write(read);

out.flush();

}

}catch (FileNotFoundException e){

Log.e("Weather", e.getMessage());

} catch (IOException e) {

// TODO Auto-generated catch block

Log.e("Weather", e.getMessage());

}catch(Exception e){

Log.e("Weather", e.getMessage());

}

finally{

try{

if(in != null) in.close();

if(out != null) out.close();

if(dbFile != null) dbFile.close();

}catch (IOException e){

Log.e("Weather", e.getMessage());

}catch(Exception e){

Log.e("Weather", e.getMessage());

}

}

}

我是这样做的代码

android 预加载页面 是什么 csdn

在用fragment+viewpage的时候发现viewpage会预加载下一个fragment,我的fragment是获取网络数据带加载进度条的,但是当前一个页面加载的时候,我发现他就执行了于是找办法解决,起初设置setOffscreenPageLimit(0),发现不管用,官方解释为它最小为1,于是继续寻找,发现fragment有一个方法为setUserVisibleHint,此方法意思为fragment是否可见,于是加入之后完美解决,但是需要在每个fragment中复写下边的方法:

@Override

public void setUserVisibleHint(boolean isVisibleToUser) {

// TODO Auto-generated method stub

if (isVisibleToUser) {

//fragment可见时加载数据

} else {

//不可见时不执行操作

}

super.setUserVisibleHint(isVisibleToUser);

}


网站标题:预加载android,预加载群成员
URL网址:http://sczitong.cn/article/dsdoiig.html