launcher

安卓系统桌面启动器

  Launcher是安卓系统中的桌面启动器,安卓系统的桌面UI统称为Launcher。Launcher是安卓系统中的主要程序组件之一,安卓系统中如果没有Launcher就无法启动安卓桌面,Launcher出错的时候,安卓系统会出现“进程 com.android.launcher 意外停止”的提示窗口。这时需要重新启动Launcher。

安卓系统Launcher的开发

主要文件和类

 

launcher

launcher  1.Launcher.java:launcher中主要的activity。

 

 2.DragLayer.java:launcher layout的rootview。DragLayer实际上也是一个抽象的界面,用来处理拖动和对事件进行初步处理然后按情况分发下去,角色是一个controller。它首先用onInterceptTouchEvent(MotionEvent)来拦截所有的touch事件,如果是长按item拖动的话不把事件传下去,直接交由onTouchEvent()处理,这样就可以实现item的移动了,如果不是拖动item的话就把事件传到目标view,交有目标view的事件处理函数做相应处理。如果有要对事件的特殊需求的话可以修改onInterceptTouchEvent(MotionEvent)来实现所需要的功能。

 3. DragController.java:为Drag定义的一个接口。包含一个接口,两个方法和两个静态常量。接口为DragListener(包含onDragStart(),onDragEnd()两个函数),onDragStart()是在刚开始拖动的时候被调用,onDragEnd()是在拖动完成时被调用。在launcher中典型的应用是DeleteZone,在长按拖动item时调用onDragStart()显示,在拖动结束的时候onDragEnd()隐藏。两个函数包括startDrag()和setDragItemInfo().startDrag()用于在拖动是传递要拖动的item的信息以及拖动的方式,setDragItemInfo()用于传递item的参数信息(包括位置以及大小)。两个常量为DRAG_ACTION_MOVE,DRAG_ACTION_COPY来标识拖动的方式,DRAG_ACTION_MOVE为移动,表示在拖动的时候需要删除原来的item,DRAG_ACTION_COPY为复制型的拖动,表示保留被拖动的item。

  4.LauncherModel.java:辅助的文件。里面有许多封装的对数据库的操作。包含几个线程,其中最主要的是ApplicationsLoader和DesktopItemsLoader。ApplicationsLoader在加载所有应用程序时使用,DesktopItemsLoader在加载workspace的时候使用。其他的函数就是对数据库的封装,比如在删除,替换,添加程序的时候做更新数据库和UI的工作。

  5.Workspace.java:抽象的桌面。由N个celllaout组成,从cellLayout更高一级的层面上对事件的处理。

  6.LauncherProvider.java:launcher的数据库,里面存储了桌面的item的信息。在创建数据库的时候会loadFavorites(db)方法,loadFavorites()会解析xml目录下的default_workspace.xml文件,把其中的内容读出来写到数据库中,这样就做到了桌面的预制。

  7.CellLayout.java:组成workspace的view,继承自viewgroup,既是一个dragSource,又是一个dropTarget,可以将它里面的item拖出去,也可以容纳拖动过来的item。在workspace_screen里面定了一些它的view参数。

  8.ItemInfo.java:对item的抽象,所有类型item的父类,item包含的属性有id(标识item的id),cellX(在横向位置上的位置,从0开始),cellY(在纵向位置上的位置,从0开始),spanX(在横向位置上所占的单位格),spanY(在纵向位置上所占的单位格),screen(在workspace的第几屏,从0开始),itemType(item的类型,有widget,search,application等),container(item所在的)。

  9.UserFolder.java:用户创建的文件夹。可以将item拖进文件夹,单击时打开文件夹,长按文件夹上面标题处可以重命名文件夹。

  10.LiveFolder.java:系统自带的文件夹。从系统中创建出的如联系人的文件夹等。

  11.DeleteZone:删除框。在平时是出于隐藏状态,在将item长按拖动的时候会显示出来,如果将item拖动到删除框位置时会删除item。DeleteZone实现了DropTarget和DragListener两个接口。

  12.LauncherSettings.java:字符串的定义。数据库项的字符串定义,另外在这里定义了container的类型,还有itemType的定义,除此还有一些特殊的widget(如search,clock的定义等)的类型定义。

  补充Launcher工程中的类:

主要模块

 

1.界面模型:

  Launcher的界面的rootview是DragLayer,它是一个FrameLayout,在它上面workspace(应该说是celllayout)占了绝大部分的空间,celllayout的参数文件是workspace_screen.xml。workspace既是一个DropTarget又是一个DragSource,可以从AllAppGridView中拖出应用程序放在它上面,也可以把它里面的item拖走删除或者拖到bottombar里面去。

  (对于想修改launcher的同学,可以自定义DragLay.java,比如改为AbsoluteLayout等,再修改launcher.xml布局文件,就可以实现各种样式的launcher界面。)

  2.Drop&Drag模型:

  ⒉1 DragSource:可以拖动的对象来源的容器,在launcher中主要有AllAppGridView,workspace等。

  void onDropCompleted(View target,boolean success,int x,int y);

  ⒉2 DropTarget:可以放置被拖动的对象的容器。在launcher中有folder,workspace,bottombar等,一个View既可以是Dragsource也可以是DropTarget。主要包含以下几个接口:

  1) boolean acceptDrop(DragSource source,int x,int y,int xOffset,int yOffset,Object dragInfo);

  acceptDrop 函数用来判断dropTarget是否可以接受item放置在自己里面。

  2) void onDragEnter(DragSource source,int x,int y,int xOffset,int yOffset,Object dragInfo);

  onDragEnter是item被拖动进入到一个dropTarget的时候的回调。

  3) void onDragOver(DragSource source,int x,int y,int xOffset,int yOffset,Object dragInfo);

  onDragOver是item在上一次位置和这一次位置所处的dropTarget相同的时候的回调。

  4) void onDragExit(DragSource source,int x,int y,int xOffset,int yOffset,Object dragInfo);

  onDragExit是item被拖出dropTarget时的回调。

  5) boolean onDrop(DragSource source,int x,int y,int xOffset,int yOffset,Object dragInfo);

  onDrop是item被放置到dropTarget时的回调。

  函数的调用模式为:

  DropTarget dropTarget = findDropTarget((int) x,(int) y,coordinates);

  if(dropTarget !=null) {

  /**

  * 当这一次的 target 跟上一次相同时,根据坐标来移动item

  */

  if(mLastDropTarget == dropTarget) {

  dropTarget.onDragOver(mDragSource,coordinates[0],coordinates[1],

  (int) mTouchOffsetX,(int) mTouchOffsetY,mDragInfo);

  }else{

  /**

  * 当上一次的位置跟这一次不同而且上一次的位置不为空,说明item移 *动出了,将上次的 View 根据上次的坐标重新排列,并根据当前坐标重排*当前的*/

  if(mLastDropTarget !=null) {

  mLastDropTarget.onDragExit(mDragSource,coordinates[0],coordinates[1],

  (int) mTouchOffsetX,(int) mTouchOffsetY,mDragInfo);

  }

  dropTarget.onDragEnter(mDragSource,coordinates[0],coordinates[1],

  (int) mTouchOffsetX,(int) mTouchOffsetY,mDragInfo);

  }

  }else{//如果这一次为 null,上一次不为 null,那么把上一次坐标位置的 cell 去掉

  if(mLastDropTarget !=null) {

  mLastDropTarget.onDragExit(mDragSource,coordinates[0],coordinates[1],

  (int) mTouchOffsetX,(int) mTouchOffsetY,mDragInfo);

  }

  }

  //记录上次的droptarget

  mLastDropTarget = dropTarget;

  3.Touch event总结:

  由于launcher的事件比较多比较复杂,所以在事件处理的时候一般采用rootview先用onInterceptTouchEvent(MotionEvent)拦截所有的touch事件,经过判断后分发给childview。

  判断的规则如下:

  a.down事件首先会传递到onInterceptTouchEvent()方法

  b.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move,up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。

  c.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move,up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。

  d.如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。

  e.如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。

几种问题的解决方式

 

1.将所有的应用都排列在桌面

  将所有的应用都排列在桌面是通过首先创建一个三维的boolean型全局数组来记录item的排列情况,第一维是屏数,第二维是纵向上的排列情况,第三维是横向的排列情况,如果那个位置被item所占用就标记为1,否则标记为0.在启动时把全局数组初始化为0,然后在添加的时候把相应的位置置1.凡是涉及到workspace上item的变化,比如移动、添加、删除操作时都需要维护数组,保持数组的正确性,因为在安装新程序时依据数组的状态去判断把item加到什么位置。

  2.动态增加屏幕

  动态增加屏幕是通过worksapce .addchild(view)的方式实现。基本思路是:首先预先规定所允许的最大的屏幕数,然后在需要增加屏幕而且当前屏幕数没有超过最大屏幕数的时候通过(CellLayout)mInflater.inflate(R.layout.workspace_screen,null)创建一个celllayout实例出来,然后通过addchild把它加入进去。在屏幕上的item被删除时通过从最后一屏起判断屏幕上是否有item,如果有的话保留,没有的话则删除最后一屏,以此类推。

  3.预制桌面

  a.添加普通的应用程序快捷方式

  在../res/xml下的default_workspace.xml文件中加入默认要放置的普通的应用程序。加入的格式为:

  <favorite

  launcher:packageName="..."//应用的packageName

  launcher:className="..."//应用启动时的第一个activity

  launcher:screen="..."//放置在第几屏(放在workspace的时候需要,从0开始,0为第一屏,1为第二屏,以此类推...)

  launcher:x="..."//放置x方向的位置(在列中的位置)

  launcher:y="..."/>//放置y方向的位置(在行中的位置)

  packageName和className可以通过点击程序,然后在打印出的log中找到comp={...},例如如下信息:

  comp={com.estrongs.android.taskmanager/com.estrongs.android.taskmanager.TaskManager}。其中com.estrongs.android.taskmanager为packageName,com.estrongs.android.taskmanager.TaskManager为className。

  workspace的布局如下:

  (0,0)

  (1,0)

  (2,0)

  (3,0)

  (4,0)

  (0,1)

  (1,1)

  (2,1)

  (3,1)

  (4,1)

  (0,2)

  (1,2)

  (2,2)

  (3,2)

  (4,2)

  b.添加widget:

  在../package/apps/VLauncher/res/xml下的default_workspace.xml文件中加入默认要放置的普通的应用程序。加入的格式为:

  <widget

  launcher:packageName="..."//widget的packageName

  launcher:className="..."//实现 widget的 receiver 类的名称.

  launcher:container="..."//放置的位置(只能为desktop)

  launcher:screen="..."//放置在第几屏上

  launcher:x="..."//放置的x位置

  launcher:y="..."//放置的y位置

  launcher:spanx="..."//在x方向上所占格数

  launcher:spany="..."/>//在y方向上所占格数

  例如,要在第3屏的第一行第二列放置开始放置一个x方向上占两个单位格,y方向上占两个单位格的时钟,可以加入以下代码:

  <appwidget

  launcher:packageName="com.android.alarmclock"launcher:className="com.android.alarmclock.AnalogAppWidgetProvider"

  launcher:container="desktop"

  launcher:screen="2"

  launcher:x="1"

  launcher:y="0"

  launcher:spanx="2"

  launcher:spany="2"/>

  4.改变主界面的排列方式

  要修改桌面的排列方式,如下,先根据横竖屏设置修改workspace_screen.xml里shortAxisCells和longAxisCells的参数,然后在Launcher.java中修改NUMBER_CELLS_X和NUMBER_CELLS_Y的值,在2.3版本中刚开始往数据库中添加item的时候会去判断,如果不修改NUMBER_CELLS_X和NUMBER_CELLS_Y的话会导致一部分的item显示不出来,导致预制apk的失败。

  5.增加worksapce上的屏数

  要增加屏数,首先在根据横竖屏在launcher.xml中的<com.android.launcher.Workspace 中删除或增加<include android:id="@+id/cellN"layout="@layout/workspace_screen"/>;,然后在Launcher.java中修改SCREEN_COUNT的值即可。

xml文件

  1.workspace_screen.xml

  launcher:cellWidth="95dip"cell(即item)的宽

  launcher:cellHeight="93dip"cell(即item)的宽

  launcher:longAxisStartPadding="25dip"

  较长(屏幕的宽和高中较大的那一方向,根据横竖屏方向有所不同)方向上距离起点的像素数

  launcher:longAxisEndPadding="55dip"

  较长(屏幕的宽和高中较大的那一方向,根据横竖屏方向有所不同)方向上距离终点的像素数

  launcher:shortAxisStartPadding="20dip"

  较短(屏幕的宽和高中较大的那一方向,根据横竖屏方向有所不同)方向上距离起点的像素数

  launcher:shortAxisEndPadding="120dip"

  较短(屏幕的宽和高中较大的那一方向,根据横竖屏方向有所不同)方向上距离起点的像素数

  launcher:shortAxisCells="3"

  较短的方向上可以容纳的cell的数量

  launcher:longAxisCells="5"

  较长的方向上可以容纳的cell的数量

  shortAxisCells和longAxisCells决定一个workspace(即CellLayout)上可以容纳的item的个数为shortAxisCells*longAxisCells.

  2. application_boxed.xml

  所有应用程序和系统文件夹中item的定义。

  3.application.xml

  Workspace的item的layout定义。[1]

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值