导航:首页 > 操作系统 > android栈模式

android栈模式

发布时间:2022-11-06 15:41:44

android开发时,怎么使项目中所有的activity都是栈内单例模式

android:launchMode="singleInstance"

② Android 多返回栈技术详解

用户通过系统返回按钮导航回去的一组页面,在开发中被称为返回栈 (back stack)。多返回栈即一堆 "返回栈",对多返回栈的支持是在 Navigation 2.4.0-alpha01 和 Fragment 1.4.0-alpha01 中开始的。本文将为您展开多返回栈的技术详解。

无论您在使用 Android 全新的 手势导航 还是传统的导航栏,用户的 "返回" 操作是 Android 用户体验中关键的一环,把握好返回功能的设计可以使应用更加贴近整个生态系统。

在最简单的应用场景中,系统返回按钮仅仅 finish 您的 Activity。在过去您可能需要覆写 Activity 的 onBackPressed() 方法来自定义返回操作,而在 2021 年您无需再这样操作。我们已经在 OnBackPressedDispatcher 中提供了 针对自定义返回导航的 API。实际上这与 FragmentManager 和 NavController 中 已经 添加的 API 相同。

这意味着当您使用 Fragments 或 Navigation 时,它们会通过 OnBackPressedDispatcher 来确保您调用了它们返回栈的 API,系统的返回按钮会将您推入返回栈的页面逐层返回。

多返回栈不会改变这个基本逻辑。系统的返回按钮仍然是一个单向指令 —— "返回"。这对多返回栈 API 的实现机制有深远影响。

在 surface 层级,对于 多返回栈的支持 貌似很直接,但其实需要额外解释一下 "Fragment 返回栈" 到底是什么。FragmentManager 的返回栈其实包含的不是 Fragment,而是由 Fragment 事务组成的。更准确地说,是由那些调用了 addToBackStack(String name) API 的事务组成的。

这就意味着当您调用 commit() 提交了一个调用过 addToBackStack() 方法的 Fragment 事务时, FragmentManager 会执行所有您在事务中所指定的操作 (比如 替换操作 ),从而将每个 Fragment 转换为预期的状态。然后 FragmentManager 会将该事务作为它返回栈的一部分。

当您调用 popBackStack() 方法时 (无论是直接调用,还是通过系统返回键以 FragmentManager 内部机制调用),Fragment 返回栈的最上层事务会从栈中弹出 -- 比如新添加的 Fragment 会被移除,隐藏的 Fragment 会显示。这会使得 FragmentManager 恢复到最初提交 Fragment 事务之前的状态。

也就是说 popBackStack() 变成了销毁操作: 任何已添加的 Fragment 在事务被弹出的时候都会丢失它的状态。换言之,您会失去视图的状态,任何所保存的实例状态 (Saved Instance State),并且任何绑定到该 Fragment 的 ViewModel 实例都会被清除。这也是该 API 和新的 saveBackStack() 方法之间的主要区别。 saveBackStack() 可以实现弹出事务所实现的返回效果,此外它还可以确保视图状态、已保存的实例状态,以及 ViewModel 实例能够在销毁时被保存。这使得 restoreBackStack() API 后续可以通过已保存的状态重建这些事务和它们的 Fragment,并且高效 "重现" 已保存的全部细节。太神奇了!

而实现这个目的必须要解决大量技术上的问题。

虽然 Fragment 总是会保存 Fragment 的视图状态,但是 Fragment 的 onSaveInstanceState() 方法只有在 Activity 的 onSaveInstanceState() 被调用时才会被调用。为了能够保证调用 saveBackStack() 时 SavedInstanceState 会被保存,我们 需要在 Fragment 生命周期切换 的正确时机注入对 onSaveInstanceState() 的调用。我们不能调用得太早 (您的 Fragment 不应该在 STARTED 状态下保存状态),也不能调用得太晚 (您需要在 Fragment 被销毁之前保存状态)。

这样的前提条件就开启了需要 解决 FragmentManager 转换到对应状态的问题,以此来保障有一个地方能够将 Fragment 转换为所需状态,并且处理可重入行为和 Fragment 内部的状态转换。

在 Fragment 的重构工作进行了 6 个月,进行了 35 次修改时,发现 Postponed Fragment 功能已经严重损坏,这一问题使得被推迟的事务处于一个中间状态 —— 既没有被提交也并不是未被提交。之后的 65 个修改和 5 个月的时间里,我们几乎重写了 FragmentManager 管理状态、延迟状态切换和动画的内部代码,具体请参见我们之前的文章《全新的 Fragment: 使用新的状态管理器》。

随着技术问题的逐步解决,包括更加可靠和更易理解的 FragmentManager ,我们新增加了两个 API: saveBackStack() 和 restoreBackStack() 。

如果您不使用这些新增 API,则一切照旧: 单个 FragmentManager 返回栈和之前的功能相同。现有的 addToBackStack() 保持不变 —— 您可以将 name 赋值为 null 或者任意 name 。然而,当您使用多返回栈时, name 的作用就非常重要了: 在您调用 saveBackStack() 和之后的 restoreBackStack() 方法时,它将作为 Fragment 事务的唯一的 key。

举个例子,会更容易理解。比如您已经添加了一个初始的 Fragment 到 Activity,然后提交了两个事务,每个事务中包含一个单独的 replace 操作:

也就是说我们的 FragmentManager 会变成这样:

比如说我们希望将 profile 页换出返回栈,然后切换到通知 Fragment。这就需要调用 saveBackStack() 并且紧跟一个新的事务:

现在我们添加 ProfileFragment 的事务和添加 EditProfileFragment 的事务都保存在 "profile" 关键字下。这些 Fragment 已经完全将状态保存,并且 FragmentManager 会随同事务状态一起保持它们的状态。很重要的一点: 这些 Fragment 的实例并不在内存中或者在 FragmentManager 中 —— 存在的仅仅只有状态 (以及任何以 ViewModel 实例形式存在的非配置状态)。

替换回来非常简单: 我们可以在 "notifications" 事务中同样调用 saveBackStack() 操作,然后调用 restoreBackStack() :

这两个堆栈项高效地交换了位置:

维持一个单独且活跃的返回栈并且将事务在其中交换,这保证了当返回按钮被点击时, FragmentManager 和系统的其他部分可以保持一致的响应。实际上,整个逻辑并未改变,同之前一样,仍然弹出 Fragment 返回栈的最后一个事务。

这些 API 都特意按照最小化设计,尽管它们会产生潜在的影响。这使得开发者可以基于这些接口设计自己的结构,而无需通过任何非常规的方式保存 Fragment 的视图状态、已保存的实例状态、非配置的状态。

当然了,如果您不希望在这些 API 之上构建您的框架,那么可以使用我们所提供的框架进行开发。

Navigation Component 最初 是作为通用运行时组件进行开发的,其中不涉及 View、Fragment、Composable 或者其他屏幕显示相关类型及您可能会在 Activity 中实现的 "目的地界面"。然而,NavHost 接口 的实现中需要考虑这些内容,通过它添加一个或者多个 Navigator 实例时,这些实例 确实 清楚如何与特定类型的目的地进行交互。

这也就意味着与 Fragment 的交互逻辑全部封装在了 navigation-fragment 开发库和它其中的 FragmentNavigator 与 DialogFragmentNavigator 中。类似的,与 Composable 的交互逻辑被封装在完全独立的 navigation-compose 开发库和它的 ComposeNavigator 中。这里的抽象设计意味着如果您希望仅仅通过 Composable 构建您的应用,那么当您使用 Navigation Compose 时无需任何涉及到 Fragment 的依赖。

该级别的分离意味着 Navigation 中有两个层次来实现多返回栈:

仍需特别注意那些 尚未 更新的 Navigator ,它们无法支持保存自身状态。底层的 Navigator API 已经整体重写来支持状态保存 (您需要覆写新增的 navigate() 和 popBackStack() API 的重载方法,而不是覆写之前的版本),即使 Navigator 并未更新, NavController 仍会保存 NavBackStackEntry 的状态 (在 Jetpack 世界中向后兼容是非常重要的)。

如果您仅仅在应用中使用 Navigation,那么 Navigator 这个层面更多的是实现细节,而不是您需要直接与之交互的内容。可以这么说,我们已经完成了将 FragmentNavigator 和 ComposeNavigator 迁移到新的 Navigator API 的工作,使其能够正确地保存和恢复它们的状态,在这个层面上您无需再做任何额外工作。

如果您正在使用 NavigationUI,它是用于连接您的 NavController 到 Material 视图组件的一系列专用助手,您会发现对于菜单项、 BottomNavigationView (现在叫 NavigationRailView ) 和 NavigationView ,多返回栈是 默认启用 的。这就意味着结合 navigation-fragment 和 navigation-ui 使用就可以。

NavigationUI API 是基于 Navigation 的其他公共 API 构建的,确保您可以准确地为自定义组件构建您自己的版本。保证您可以构建所需的自定义组件。启用保存和恢复返回栈的 API 也不例外,在 Navigation XML 中通过 NavOptions 上的新 API,也就是 navOptions Kotlin DSL,以及 popBackStack() 的重载方法可以帮助您指定 pop 操作保存状态或者指定 navigate 操作来恢复之前已保存的状态。

比如,在 Compose 中,任何全局的导航模式 (无论是底部导航栏、导航边栏、抽屉式导航栏或者任何您能想到的形式) 都可以使用我们在与 底部导航栏集成 所介绍的相同的技术,并且结合 saveState 和 restoreState 属性一起调用 navigate() :

对用户来说,最令人沮丧的事情之一便是丢失之前的状态。这也是为什么 Fragment 用一整页来讲解 保存与 Fragment 相关的状态,而且也是我非常乐于更新每个层级来支持多返回栈的原因之一:

如果您希望了解 更多使用该 API 的示例,请参考 NavigationAdvancedSample (它是最新更新的,且不包含任何用于支持多返回栈的 NavigationExtensions 代码)。

对于 Navigation Compose 的示例,请参考 Tivi。

如果您遇到任何问题,请使用官方的问题追踪页面提交关于 Fragment 或者 Navigation 的 bug,我们会尽快处理。

③ android新手 singleTask

在多Activity开发中,有可能是自己应用之间的Activity跳转,或者夹带其他应用的可复用Activity。可能会希望跳转到原来某个Activity实例,而不是产生大量重复的Activity。

这需要为Activity配置特定的加载模式,而不是使用默认的加载模式。

加载模式分类及在哪里配置

Activity有四种加载模式:

standard

singleTop

singleTask

singleInstance

设置的位置在AndroidManifest.xml文件中activity元素的android:launchMode属性:

<activity
android:name="ActB"android:launchMode="singleTask"></activity>

也可以在Eclipse
ADT中图形界面中编辑:

另外,可以看到两个Activity的taskId是不同的。

④ android中的任务栈,是一个任务栈包含前台任务栈和后台任务栈,还是任务栈分为前台的任务栈

任务栈分为前台的任务栈,当前activity活动所在的栈称为前台任务栈。

⑤ Android有多少栈空间和堆

我的理解是堆栈就是后进先出,那么稍微想象一下,你打开的Activity是一层一层往上盖的,当你退出当前这个Activity的时候,使用堆栈机制才会显示你底下那一层的Activity,提高Activity复用率吧。如果你觉得这个Activity可以不用再保留那么也给你提供了相应的打开另一个Activity之后就清理掉自己的方法。这样做的用户体验会比较好吧;那么反过来讲如果没有采用堆栈机制,在这么有限的显示区域里应该怎么去分配多个Activity呢?

⑥ 由从服务中启动activity——谈谈安卓的任务与栈

在安卓的服务中这样启动活动:

你会得到这样的错误:

你知道我对安卓的什么地方最为痴迷?是它应用之间的协作。怎么协作?依靠activity之间的协作。

这种协作是可以跨越应用的。我们从task谈起。
task最直观的是安卓第三个虚拟键所列出的那些就是任务。

以上这种功能的实现,要从task谈起,developer上,这样定义task:

翻译过来,大体意识就是task是一个具有栈结构的容器,用以执行一定特定的工作,它可以放置多个Activity实例。

启动一个应用,系统就会为之创建一个task,来放置根Activity。默认情况下,一个Activity启动另一个Activity时,两个Activity是放置在同一个task中的,后者被压入前者所在的task栈,当用户按下后退键,后者从task被弹出,前者又显示在幕前,特别是启动其他应用中的Activity时,两个Activity对用户来说就好像是属于同一个应用。

task可以分为系统task和task。这两者之间是互相独立的。

当我们运行一个应用时,按下Home键回到主屏,启动另一个应用,这个过程中,之前的task被转移到后台,新的task被转移到前台,其根Activity也会显示到幕前,过了一会之后,在此按下Home键回到主屏,再选择之前的应用,之前的task会被转移到前台,系统仍然保留着task内的所有Activity实例,而那个新的task会被转移到后台,如果这时用户再做后退等动作,就是针对该task内部进行操作了。

一个Activity当然要表面自己身在哪个task,所以每个Activity都有taskAffinity属性。这个属性指出了它希望进入的Task。

如果一个Activity指明自己的taskaffinity,那么它的这个属性就等于Application指明的taskAffinity,如果Application也没有指明,那么该taskAffinity的值就等于包名。

而Task也有自己的affinity属性,它的值等于它的根Activity的taskAffinity的值。

显示的声明activiy的属性
这很简单,在AndroidManifest.xml中声明

有了上面的基础,请记住这两种文档说明的情况:

1. 如果该Activity的allowTaskReparenting设置为true,它进入后台,当一个和它有相同affinity的Task进入前台时,它会重新宿主,进入到该前台的task中。
**2. 如果加载某个Activity的intent,Flag被设置成FLAG_ACTIVITY_NEW_TASK时,它会首先检查是否存在与自己taskAffinity相同的Task,如果存在,那么它会直接宿主到该Task中,如果不存在则重新创建Task。 **

activity有四种启动模式,分别为 standard,singleTop,singleTask,singleInstance。

这四种模式我不细说,我们只从名字上分析分析。

第一种,标准模式,想想就知道是平常的模式,这里的标准意思是每生成一个activity的实例,就当一个实例的放在栈里。

第二种,singleTop,在于那个top。要是activity不在栈顶,它和standard模式没什么区别,要是在top,就不创建一个新的,用栈顶原来那个。

第三种,不那么容易,尤其是 官网的说法好像有问题。

singleTask模式的Activity只允许在系统中有一个实例。 如果系统中已经有了一个实例,持有这个实例的任务将移动到顶部,同时intent将被通过onNewIntent()发送。如果没有,则会创建一个新的Activity并置放在合适的任务中。
这话的意思,我们分两种情况讨论,一是在同一个应用,二是不同。
在同一个应用中,如果系统中还没有singleTask的Activity,会新创建一个,并放在同一任务的栈顶。但是如果已经存在,singleTask Activity上面的所有Activity将以合适的方式自动销毁,让我们想要显示的Activity处于栈顶。
在非同一个应用中,intent是从另外的应用发送过来。系统中没有任何Activity的实例的化,会创建一个新的任务,并且新的Activity被作为根Activity创建;如果系统中拥有这个singleTask的应用存在,新建的Activity会置于这个任务的上面。

第四种,和第三种很像,关键在于singleInstance,就是只能有这一个单例存在在栈中。

回到开头,我们还没解决开始的错误。最简单粗暴的方法是:

这可以解决问题,不过也还存在一个小问题,留待读者发现:)
Flag的字面意思很好理解,如果你读懂了上述的任务与活动启动模式的化,再提供几个intent Flags:

至于意思,还是字面理解就好了。

⑦ android启动模式设置为single task任务栈为什么

在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作。在Android中Activity的启动模式决定了Activity的启动运行方式。 Android总Activity的启动模式分为四种: Activity启动模式设置: <activity android:name=".MainActivity" android:launchMode="standard" /> Activity的四种启动模式: 1. standard 模式启动模式,每次激活Activity时都会创建Activity,并放入任务栈中。 2. singleTop 如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。 3. singleTask 如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。 4. singleInstance 在一个新栈中创建该Activity实例,并让多个应用共享改栈中的该Activity实例。一旦改模式的Activity的实例存在于某个栈中,任何应用再激活改Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中。 其中standard是系统默认的启动模式。 下面通过实例来演示standard的运行机制: 1 private TextView text_show; 2 private Button btn_mode; 3 4 @Override 5 public void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.activity_main); 8 9 text_show = (TextView) this.findViewById(R.id.text_show); 10 11 text_show.setText(this.toString()); 12 13 btn_mode = (Button) this.findViewById(R.id.btn_mode); 14 15 } 16 //按钮单击事件 17 public void LaunchStandard(View v){ 18 startActivity(new Intent(this,MainActivity.class)); 19 20 text_show.setText(this.toString()); 21 }

⑧ Android中的activity的堆栈有什么作用

我的理解是堆栈就是后进先出,那么稍微想象一下,你打开的Activity是一层一层往上盖的,当你退出当前这个Activity的时候,使用堆栈机制才会显示你底下那一层的Activity,提高Activity复用率吧。如果你觉得这个Activity可以不用再保留那么也给你提供了相应的打开另一个Activity之后就清理掉自己的方法。这样做的用户体验会比较好吧;那么反过来讲如果没有采用堆栈机制,在这么有限的显示区域里应该怎么去分配多个Activity呢?

⑨ android怎样将activity放入全局栈

Activity是Android程序的表现层。程序的每一个显示屏幕就是一个Activity。正在运行的Activity处在栈的最顶端,它是运行状态的。

当有新的Activity进入屏幕最上端时,原来的Activity就会被压入第二层。如果他的屏幕没有被完 全遮盖,那么他处于Paused状态,如果他被遮盖那么处于Stop状态。
不管处于任何一层,都可能在系统觉得资源不足时被强行关闭,当然关闭时栈底的程序最先被关闭。
譬如:当你在程序中调用 Activity.finish()方法时,结果和用户按下 BACK 键一样:他告诉 Activity Manager该Activity实例可以被“回收”。随后 Activity Manager 激活处于栈第二层的 Activity 并重 新入栈,把原 Activity 压入到栈的第二层,从 Running 状态转到 Paused 状态。

在BlackBerry中,提供了一个管理Screen的栈,用来从任何地方来关闭位于最上一层的Screen,使用UiApplication.getUiApplication().getActiveScreen()来得到位于最上一层的Screen的实例,并且使用UiApplication.getUiApplication().popScreen()来关闭一个Screen或关闭当前最上一层的Screen,但是Android却未提供相应的功能,只能在一个Activity的对象里面调用finish来关闭自己,不能关闭其他的Activity。比如我们想实现一个功能从屏幕A—>屏幕B—>屏幕C—>屏幕D,然后在在转到屏幕D之前将屏幕B和C关闭,在屏幕B和屏幕C界面点击会退按钮都可以回退到上一个屏幕,但是在屏幕D上点击会退按钮让其回退到A,此外在一些循环跳转的界面上如果不在合适的地方将一些不需要的屏幕关闭,那么经过多次跳转后回导致内存溢出。对此我们可以设计一个全局的Activity栈,使用这个栈来管理Activity。管理Activity的类的定义如下:

import java.util.Stack;

import android.app.Activity;

public class ScreenManager {
private static Stack activityStack;
private static ScreenManager instance;
private ScreenManager(){
}
public static ScreenManager getScreenManager(){
if(instance==null){

⑩ Android中的Activity详解--启动模式与任务栈

目录

activity的简单介绍就不写了,作为最常用的四大组件之一,肯定都很熟悉其基本用法了。

首先,是都很熟悉的一张图,即官方介绍的Activity生命周期图.

情景:打开某个应用的的FirstActivity调用方法如下:
由于之前已经很熟悉了,这里就简单贴一些图。

按下返回键:

重新打开并按下home键:

再重新打开:

在其中打开一个DialogActivity(SecondActivity)

按下返回:

修改SecondAcitvity为普通Activity,依旧是上述操作:

这里强调一下 onSaveInstanceState(Bundle outState) 方法的调用时机:
当Activity有可能被系统杀掉时调用,注意,一定是被系统杀掉,自己调用finish是不行的。
测试如下:FirstActivity启动SecondActivity:

一个App会包含很多个Activity,多个Activity之间通过intent进行跳转,那么原始的Activity就是使用栈这个数据结构来保存的。
Task
A task is a collection of activities that users interact with when performing a certain job. The activities are arranged in a stack (the back stack ), in the order in which each activity is opened.
即若干个Activity的集合的栈表示一个Task。
当App启动时如果不存在当前App的任务栈就会自动创建一个,默认情况下一个App中的所有Activity都是放在一个Task中的,但是如果指定了特殊的启动模式,那么就会出现同一个App的Activity出现在不同的任务栈中的情况,即会有任务栈中包含来自于不同App的Activity。

标准模式,在不指定启动模式的情况下都是以此种方式启动的。每次启动都会创建一个新的Activity实例,覆盖在原有的Activity上,原有的Activity入栈。
测试如下:在FirstActivity中启动FirstActivity:

当只有一个FirstActivity时堆栈情况:

此种模式下,Activity在启动时会进行判断,如果当前的App的栈顶的Activity即正在活动的Activity就是将要启动的Activity,那么就不会创建新的实例,直接使用栈顶的实例。
测试,设置FirstActivity为此启动模式,多次点击FirstActivity中的启动FirstActivity的按钮查看堆栈情况:
(其实点击按钮没有启动新Activity的动画就可以看出并没有启动新Activity)

大意就是:
对于使用singleTop启动或Intent.FLAG_ACTIVITY_SINGLE_TOP启动的Activity,当该Activity被重复启动(注意一定是re-launched,第一次启动时不会调用)时就会调用此方法。
且调用此方法之前会先暂停Activity也就是先调用onPause方法。
而且,即使是在新的调用产生后此方法被调用,但是通过getIntent方法获取到的依旧是以前的Intent,可以通过setIntent方法设置新的Intent。
方法参数就是新传递的Intent.

1.如果是同一个App中启动某个设置了此模式的Activity的话,如果栈中已经存在该Activity的实例,那么就会将该Activity上面的Activity清空,并将此实例放在栈顶。
测试:SecondActivity启动模式设为singleTask,启动三个Activity:

这个模式就很好记,以此模式启动的Activity会存放在一个单独的任务栈中,且只会有一个实例。
测试:SecondActivity启动模式设为singleInstance

结果:

显然,启动了两次ThirdActivity任务栈中就有两个实例,而SecondActivity在另外一个任务栈中,且只有一个。

在使用Intent启动一个Activity时可以设置启动该Activity的启动模式:
这个属性有很多,大致列出几个:

每个启动的Activity都在一个新的任务栈中

singleTop

singleTask

用此种方式启动的Activity,在它启动了其他Activity后,会自动finish.

官方文档介绍如下:

这样看来的话,通俗易懂的讲,就是给每一个任务栈起个名,给每个Activity也起个名,在Activity以singleTask模式启动时,就检查有没有跟此Activity的名相同的任务栈,有的话就将其加入其中。没有的话就按照这个Activity的名创建一个任务栈。
测试:在App1中设置SecondActivity的taskAffinity为“gsq.test”,App2中的ActivityX的taskAffinity也设为“gsq.test”

任务栈信息如下:

结果很显然了。
测试:在上述基础上,在ActivityX中进行跳转到ActivityY,ActivityY不指定启动模式和taskAffinity。结果如下:

这样就没问题了,ActivityY在一个新的任务栈中,名称为包名。
这时从ActivityY跳转到SecondActivity,那应该是gsq.test任务栈只有SecondActivity,ActivityX已经没有了。因为其启动模式是singleTask,在启动它时发现已经有一个实例存在,就把它所在的任务栈上面的Activity都清空了并将其置于栈顶。

还有一点需要提一下,在上面,FirstActivity是App1的lunch Activity,但是由于SecondActivity并没有指定MAIN和LAUNCHER过滤器,故在FirstActivity跳转到SecondActivity时,按下home键,再点开App1,回到的是FirstActivity。

大致就先写这么多吧,好像有点长,废话有点多,估计也有错别字,不要太在意~~~

阅读全文

与android栈模式相关的资料

热点内容
dvd光盘存储汉子算法 浏览:758
苹果邮件无法连接服务器地址 浏览:963
phpffmpeg转码 浏览:672
长沙好玩的解压项目 浏览:145
专属学情分析报告是什么app 浏览:564
php工程部署 浏览:833
android全屏透明 浏览:737
阿里云服务器已开通怎么办 浏览:803
光遇为什么登录时服务器已满 浏览:302
PDF分析 浏览:486
h3c光纤全工半全工设置命令 浏览:143
公司法pdf下载 浏览:383
linuxmarkdown 浏览:350
华为手机怎么多选文件夹 浏览:683
如何取消命令方块指令 浏览:350
风翼app为什么进不去了 浏览:779
im4java压缩图片 浏览:362
数据查询网站源码 浏览:151
伊克塞尔文档怎么进行加密 浏览:893
app转账是什么 浏览:163