Android应用程序窗口(Activity)的视图对象(View)的创建过程分析
从前文可知道,每一个Activity组件都有一个关联的Window对象,用来描述一个应用程序窗口。每一个应用程序窗口内部又包含有一个View对象,用来描述应用程序窗口的视图。应用程序窗口视图是真正用来实现UI内容和布局的,也就是说,每一个Activity组件的UI 内容和布局都是通过与其所关联的一个Window对象的内部的一个View对象来实现的。在本文中,我们就详细分析应用程序窗口视图的创建过程。
在前面一文中提到,应用程序窗口内部所包含的视图对象的实际类型为DecorView。DecorView类继承了View类,是作为容器(ViewGroup)来使用的,它的实现如图1所示:
这个图的具体描述可以参考一文中的图5,这里不再详述。
从前面一文还可以知道,每一个应用程序窗口的视图对象都有一个关联的ViewRoot对象,这些关联关系是由窗口管理器来维护的,如图2所示:
这个图的具体描述可以参考一文中的图6,这里不再详述。
简单来说,ViewRoot相当于是MVC模型中的Controller,它有以下职责:
1. 负责为应用程序窗口视图创建Surface。
2. 配合WindowManagerService来管理系统的应用程序窗口。
3. 负责管理、布局和渲染应用程序窗口视图的UI。
那么,应用程序窗口的视图对象及其所关联的ViewRoot对象是什么时候开始创建的呢?从前面一文可以知道,Activity组件在启动的时候,系统会为它创建窗口对象(Window),同时,系统也会为这个窗口对象创建视图对象。另一方面,当Activity组件被激活的时候,系统如果发现与它的应用程序窗口视图对象所关联的ViewRoot对象还没有创建,那么就会先创建这个ViewRoot对象,以便接下来可以将它的UI渲染出来。
从前面一文可以知道,Activity组件在启动的过程中,会调用ActivityThread类的成员函数handleLaunchActivity,用来创建以及首次激活Activity组件,因此,接下来我们就从这个函数开始,具体分析应用程序窗口的视图对象及其所关联的ViewRoot对象的创建过程,如图3所示:
这个过程一共可以分为13个步骤,接下来我们就详细分析每一个步骤。
Step 1. ActivityThread.handleLaunchActivity
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public final class ActivityThread {
......
private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { ......
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
......
handleResumeActivity(r.token, false, r.isForward);
......
}
......
}
......
}
这个函数定义在文件frameworks/base/core/java/android/app/ActivityThread.java文件中。
函数首先调用ActivityThread类的成员函数performLaunchActivity来创建要启动的Activity组件。在创建Activity组件的过程中,还会为该Activity组件创建窗口对象和视图对象。Activity组件创建完成之后,就可以将它激活起来了,这是通过调用ActivityThread 类的成员函数handleResumeActivity来执行的。
接下来,我们首先分析ActivityThread类的成员函数performLaunchActivity的实现,以便可以了解应用程序窗口视图对象的创建过程,接着再回过头来继续分析ActivityThread 类的成员函数handleResumeActivity的实现,以便可以了解与应用程序窗口视图对象所关联的ViewRoot对象的创建过程。
Step 2. ActivityThread.performLaunchActivity
这个函数定义在文件frameworks/base/core/Java/Android/app/ActivityThread.java文件中。
这一步可以参考一文的Step 1,它主要就是创建一个Activity组件实例,并且调用这个Activity组件实例的成员函数onCreate来让其执行一些自定义的初始化工作。
Step 3. Activity.onCreate
这个函数定义在文件frameworks/base/core/java/android/app/Activity.java中。
这一步可以参考一文的Step 10。我们在实现一个Activity组件的时候,也就是在实现一个Activity子类的时候,一般都会重写成员函数onCreate,以便可以执行一些自定义的初始化工作,其中就包含初始化UI的工作。例如,在前面一文中,我们实现了一个名称为Hello的Activity组件,用来测试硬件服务,它的成员函数onCreate的样子长得大概如下所示:
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public class Hello extends Activity implements OnClickListener {
......
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(https://www.wendangku.net/doc/1d8844972.html,yout.main);
......
}
......
}
其中,调用从父类Activity继承下来的成员函数setContentView就是用来创建应用程序窗口视图对象的。
接下来,我们就继续分析Activity类的成员函数setContentView的实现。
Step 4. Activity.setContentView
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks {
......
private Window mWindow;
......
public Window getWindow() {
return mWindow;
}
......
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
}
......
}
这个函数定义在文件frameworks/base/core/java/android/app/Activity.java中。
Activity类的成员函数setContentView首先调用另外一个成员函数getWindow来获得成员变量mWindow所描述的一个窗口对象,接着再调用这个窗口对象的成员函数setContentView来执行创建应用程序窗口视图对象的工作。
从前面一文可以知道,Activity类的成员变量mWindow指向的是一个PhoneWindow 对象,因此,接下来我们就继续分析PhoneWindow类的成员函数setContentView的实现。
Step 5. PhoneWindow.setContentView
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public class PhoneWindow extends Window implements MenuBuilder.Callback { ......
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
private ViewGroup mContentParent;
......
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}
......
}
这个函数定义在文件frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java中。
PhoneWindow类的成员变量mContentParent用来描述一个类型为DecorView的视图对象,或者这个类型为DecorView的视图对象的一个子视图对象,用作UI容器。当它的值等于null的时候,就说明正在处理的应用程序窗口的视图对象还没有创建。在这种情况下,就会调用成员函数installDecor来创建应用程序窗口视图对象。否则的话,就说明是要重新设置应用程序窗口的视图。在重新设置之前,首先调用成员变量mContentParent所描述的一个ViewGroup对象来移除原来的UI内空。
由于我们是在Activity组件启动的过程中创建应用程序窗口视图的,因此,我们就假设此时PhoneWindow类的成员变量mContentParent的值等于null。接下来,函数就会调用成员函数installDecor来创建应用程序窗口视图对象,接着再通过调用PhoneWindow类的成员变量mLayoutInflater所描述的一个LayoutInflater对象的成员函数inflate来将参数layoutResID所描述的一个UI布局设置到前面所创建的应用程序窗口视图中去,最后还会调用一个Callback接口的成员函数onContentChanged来通知对应的Activity组件,它的视图内容发生改变了。从前面一文可以知道,Activity组件自己实现了这个Callback接口,并且
将这个Callback接口设置到了与它所关联的应用程序窗口对象的内部去,因此,前面实际调用的是Activity类的成员函数onContentChanged来发出一个视图内容变化通知。
接下来,我们就继续分析PhoneWindow类的成员函数installDecor的实现,以便可以继续了解应用程序窗口视图对象的创建过程。
Step 6. PhoneWindow.installDecor
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public class PhoneWindow extends Window implements MenuBuilder.Callback { ......
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
......
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
private ViewGroup mContentParent;
......
private TextView mTitleView;
......
private CharSequence mTitle = null;
......
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
......
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
if (mTitleView != null) {
if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
View titleContainer = findViewById(com.android.internal.R.id.title_container);
if (titleContainer != null) {
titleContainer.setVisibility(View.GONE);
} else {
mTitleView.setVisibility(View.GONE);
}
if (mContentParent instanceof FrameLayout) {
((FrameLayout)mContentParent).setForeground(null);
}
} else {
mTitleView.setText(mTitle);
}
}
}
}
......
}
这个函数定义在文件frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java中。
由于我们是在Activity组件启动的过程中创建应用程序窗口视图的,因此,我们同时假设此时PhoneWindow类的成员变量mDecor的值等于null。这时候PhoneWindow类的成员函数installDecor就会调用另外一个成员函数generateDecor来创建一个DecorView对象,并且保存在PhoneWindow类的成员变量mDecor中。
PhoneWindow类的成员函数installDecor接着再调用另外一个成员函数generateLayout来根据当前应用程序窗口的Feature来加载对应的窗口布局文件。这些布局文件保存在frameworks/base/core/res/res/layout目录下,它们必须包含有一个id值为“content”的布局控件。这个布局控件必须要从ViewGroup类继承下来,用来作为窗口的UI容器。PhoneWindow类的成员函数generateLayout执行完成之后,就会这个id值为“content”的ViewGroup控件来给PhoneWindow类的成员函数installDecor,后者再将其保存在成员变量mContentParent中。
PhoneWindow类的成员函数installDecor还会检查前面加载的窗口布局文件是否包含有一个id值为“title”的TextView控件。如果包含有的话,就会将它保存在PhoneWindow 类的成员变量mTitleView中,用来描述当前应用程序窗口的标题栏。但是,如果当前应用程序窗口是没有标题栏的,即它的Feature位FEATURE_NO_TITLE的值等于1,那么PhoneWindow类的成员函数installDecor就需要将前面得到的标题栏隐藏起来。注意,PhoneWindow类的成员变量mTitleView所描述的标题栏有可能是包含在一个id值为“title_container”的容器里面的,在这种情况下,就需要隐藏该标题栏容器。另一方面,如果当前应用程序窗口是设置有标题栏的,那么PhoneWindow类的成员函数installDecor就会设置它的标题栏文字。应用程序窗口的标题栏文字保存在PhoneWindow类的成员变量mTitle 中,我们可以调用PhoneWindow类的成员函数setTitle来设置。
这一步执行完成之后,应用程序窗口视图就创建完成了,回到前面的Step 1中,即ActivityThread类的成员函数handleLaunchActivity中,接下来就会调用ActivityThread类的另外一个成员函数handleResumeActivity来激活正在启动的Activity组件。由于在是第一次激活该Activity组件,因此,在激活之前,还会为该Activity组件创建一个ViewRoot对象,
并且与前面所创建的应用程序窗口视图关联起来,以便后面可以通过该ViewRoot对象来控制应用程序窗口视图的UI展现。
接下来,我们就继续分析ActivityThread类的成员函数handleResumeActivity的实现。
Step 7. ActivityThread.handleResumeActivity
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public final class ActivityThread {
......
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) { ......
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
......
// 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 = ActivityManagerNative.getDefault().willActivityBeVisible(
a.getActivityToken());
} catch (RemoteException e) {
}
}
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
https://www.wendangku.net/doc/1d8844972.html,youtParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = https://www.wendangku.net/doc/1d8844972.html,youtParams.TYPE_BASE_APPLICATION;
......
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
}
......
}
......
}
......
}
这个函数定义在文件frameworks/base/core/java/android/app/ActivityThread.java中。
ActivityThread类的成员函数handleResumeActivity首先调用另外一个成员函数performResumeActivity来通知Activity组件,它要被激活了,即会导致Activity组件的成员函数onResume被调用。ActivityThread类的成员函数performResumeActivity的返回值是一个ActivityClientRecord对象r,这个ActivityClientRecord对象的成员变量activity描述的就是正在激活的Activity组件a。
ActivityThread类的成员函数handleResumeActivity接下来判断正在激活的Activity 组件接下来是否是可见的。如果是可见的,那么变量willBeVisible的值就会等于true。Activity 类的成员变量mStartedActivity用来描述一个Activity组件是否正在启动一个新的Activity组件,并且等待这个新的Activity组件的执行结果。如果是的话,那么这个Activity组件的成员变量mStartedActivity的值就会等于true,表示在新的Activity组件的执行结果返回来之前,当前Activity组件要保持不可见的状态。因此,当Activity组件a的成员变量mStartedActivity 的值等于true的时候,它接下来就是不可见的,否则的话,就是可见的。
虽然说在Activity组件a的成员变量mStartedActivity的值等于true的情况下,它接下来的状态要保持不可见的,但是有可能它所启动的Activity组件的UI不是全屏的。在这种情况下,Activity组件a的UI仍然是有部分可见的,这时候也要将变量willBeVisible 的值设置为true。因此,如果前面得到变量willBeVisible的值等于false,那么ActivityThread 类的成员函数handleResumeActivity接下来就会通过Binder进程间通信机制来调用ActivityManagerService服务的成员函数willActivityBeVisible来检查位于Activity组件a上面的其它Activity组件(包含了Activity组件a正在等待其执行结果的Activity组件)是否是全屏的。如果不是,那么ActivityManagerService服务的成员函数willActivityBeVisible的返回值就会等于true,表示接下来需要显示Activity组件a。
前面得到的ActivityClientRecord对象r的成员变量window用来描述当前正在激活的Activity组件a所关联的应用程序窗口对象。当它的值等于null的时候,就表示当前正在激活的Activity组件a所关联的应用程序窗口对象还没有关联一个ViewRoot对象。进一步地,如果这个正在激活的Activity组件a还活着,并且接下来是可见的,即ActivityClientRecord 对象r的成员变量mFinished的值等于false,并且前面得到的变量willBeVisible的值等于true,那么这时候就说明需要为与Activity组件a所关联的一个应用程序窗口视图对象关联的一个
ViewRoot对象。
将一个Activity组件的应用程序窗口视图对象与一个ViewRoot对象关联是通过该Activity组件所使用的窗口管理器来执行的。从前面一文可以知道,一个Activity组件所使用的本地窗口管理器保存它的成员变量mWindowManager中,这可以通过Activity类的成员函数getWindowManager来获得。在接下来的Step 10中,我们再分析Activity类的成员函数getWindowManager的实现。
由于我们现在要给Activity组件a的应用程序窗口视图对象关联一个ViewRoot对象,因此,我们就需要首先获得这个应用程序窗口视图对象。从前面的Step 6可以知道,一个Activity组件的应用程序窗口视图对象保存在与其所关联的一个应用程序窗口对象的内部,因此,我们又要首先获得这个应用程序窗口对象。与一个Activity组件所关联的应用程序窗口对象可以通过调用该Activity组件的成员函数getWindow来获得。一旦获得了这个应用程序窗口对象(类型为PhoneWindow)之后,我们就可以调用它的成员函数getDecorView来获得它内部的视图对象。在接下来的Step 8和Step 9中,我们再分别分析Activity类的成员函数Activity类的成员函数getWindow和PhoneWindow类的成员函数getDecorView的实现。
在关联应用程序窗口视图对象和ViewRoot对象的时候,还需要第三个参数,即应用程序窗口的布局参数,这是一个类型为https://www.wendangku.net/doc/1d8844972.html,youtParams的对象,可以通过调用应用程序窗口的成员函数getAttributes来获得。一切准备就绪之后,还要判断最后一个条件是否成立,即当前正在激活的Activity组件a在本地进程中是否是可见的,即它的成员变量mVisibleFromClient的值是否等于true。如果是可见的,那么最后就可以调用前面所获得的一个本地窗口管理器wm(类型为LocalWindowManager)的成员函数addView来执行关联应用程序窗口视图对象和ViewRoot对象的操作。
接下来,我们就分别分析Activity类的成员函数getWindow、PhoneWindow类的成员函数getDecorView、ctivity类的成员函数getWindowManager以及LocalWindowManager类的成员函数addView的实现。
Step 8. Activity.getWindow
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks {
......
private Window mWindow;
......
public Window getWindow() {
return mWindow;
}
......
}
这个函数定义在文件frameworks/base/core/java/android/app/Activity.java中。
从前面一文可以知道,Activity类的成员变量mWindow指向的是一个类型为PhoneWindow的窗口对象,因此,Activity类的成员函数getWindow返回给调用者的是一个PhoneWindow对象。
这一步执完成之后,返回到前面的Step 7中,即ActivityThread类的成员函数handleResumeActivity中,接下来就会继续调用前面所获得的一个PhoneWindow对象的成员函数getDecorView来获得当前正在激活的Activity组件所关联的一个应用程序窗口视图对象。
Step 9. PhoneWindow.getDecorView
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public class PhoneWindow extends Window implements MenuBuilder.Callback { ......
private DecorView mDecor;
......
@Override
public final View getDecorView() {
if (mDecor == null) {
installDecor();
}
return mDecor;
}
......
}
这个函数定义在文件frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java中。
PhoneWindow类的成员函数getDecorView首先判断成员变量mDecor的值是否等于null。如果是的话,那么就说明当前正在处理的应用程序窗口还没有创建视图对象。这时候就会调用另外一个成员函数installDecor来创建这个视图对象。从前面的调用过程可以知道,当前正在处理的应用程序窗口已经创建过视图对象,因此,这里的成员变量mDecor的值不等于null,PhoneWindow类的成员函数getDecorView直接将它返回给调用者。
这一步执完成之后,返回到前面的Step 7中,即ActivityThread类的成员函数handleResumeActivity中,接下来就会继续调用当前正在激活的Activity组件的成员函数getWindowManager来获得一个本地窗口管理器。
Step 10. Activity.getWindowManager
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks {
......
private WindowManager mWindowManager;
......
public WindowManager getWindowManager() {
return mWindowManager;
}
......
}
这个函数定义在文件frameworks/base/core/java/android/app/Activity.java中。
从前面一文可以知道,Activity类的成员变量mWindowManager指向的一是类型为LocalWindowManager的本地窗口管理器,Activity类的成员函数getWindowManager直接将它返回给调用者。
这一步执完成之后,返回到前面的Step 7中,即ActivityThread类的成员函数handleResumeActivity中,接下来就会继续调用前面所获得的一个LocalWindowManager对象的成员函数addView来为当前正在激活的Activity组件的应用程序窗口视图对象关联一个ViewRoot对象。
Step 11. LocalWindowManager.addView
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public abstract class Window {
......
private class LocalWindowManager implements WindowManager {
......
public final void addView(View view, https://www.wendangku.net/doc/1d8844972.html,youtParams params) {
......
mWindowManager.addView(view, params);
}
......
private final WindowManager mWindowManager;
......
}
......
}
这个函数定义在文件frameworks/base/core/java/android/view/Window.java中。
从前面一文可以知道,LocalWindowManager类的成员变量mWindowManager指向的是一个WindowManagerImpl对象,因此,LocalWindowManager类的成员函数addView接下来调用WindowManagerImpl类的成员函数addView来给参数view所描述的一个应用程序窗口视图对象关联一个ViewRoot对象。
Step 12. WindowManagerImpl.addView
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public class WindowManagerImpl implements WindowManager {
......
public void addView(View view, https://www.wendangku.net/doc/1d8844972.html,youtParams params)
{
addView(view, params, false);
}
......
private void addView(View view, https://www.wendangku.net/doc/1d8844972.html,youtParams params, boolean nest)
{
......
final https://www.wendangku.net/doc/1d8844972.html,youtParams wparams
= (https://www.wendangku.net/doc/1d8844972.html,youtParams)params;
ViewRoot root;
View panelParentView = null;
synchronized (this) {
// Here's an odd/questionable case: if someone tries to add a
// view multiple times, then we simply bump up a nesting count
// and they need to remove the view the corresponding number of
// times to have it actually removed from the window manager.
// This is useful specifically for the notification manager,
// which can continually add/remove the same view as a
// notification gets updated.
int index = findViewLocked(view, false);
if (index >= 0) {
if (!nest) {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
root = mRoots[index];
root.mAddNesting++;
// Update layout parameters.
view.setLayoutParams(wparams);
root.setLayoutParams(wparams, true);
return;
}
// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= https://www.wendangku.net/doc/1d8844972.html,youtParams.FIRST_SUB_WINDOW &&
wparams.type <= https://www.wendangku.net/doc/1d8844972.html,ST_SUB_WINDOW) {
final int count = mViews != null ? mViews.length : 0;
for (int i=0; i if (mRoots[i].mWindow.asBinder() == wparams.token) { panelParentView = mViews[i]; } } } root = new ViewRoot(view.getContext()); root.mAddNesting = 1; view.setLayoutParams(wparams); if (mViews == null) { index = 1; mViews = new View[1]; mRoots = new ViewRoot[1]; mParams = new https://www.wendangku.net/doc/1d8844972.html,youtParams[1]; } else { index = mViews.length + 1; Object[] old = mViews; mViews = new View[index]; System.arraycopy(old, 0, mViews, 0, index-1); old = mRoots; mRoots = new ViewRoot[index]; System.arraycopy(old, 0, mRoots, 0, index-1); old = https://www.wendangku.net/doc/1d8844972.html,ms; mParams = new https://www.wendangku.net/doc/1d8844972.html,youtParams[index]; System.arraycopy(old, 0, mParams, 0, index-1); } index--; mViews[index] = view; mRoots[index] = root; mParams[index] = wparams; } // do this last because it fires off messages to start doing things root.setView(view, wparams, panelParentView); } ...... private View[] mViews; private ViewRoot[] mRoots; private https://www.wendangku.net/doc/1d8844972.html,youtParams[] mParams; ...... } 这个函数定义在文件frameworks/base/core/java/android/view/WindowManagerImpl.java中。 在WindowManagerImpl类中,两个参数版本的成员函数addView是通过调用三个参数版本的成同函数addView来实现的,因此,我们接下来就主要分析三个参数版本的成员函数addView的实现。 在分析WindowManagerImpl类的三个参数版本的成员函数addView的实现之前,我们首先了解一下WindowManagerImpl类是如何关联一个应用程序窗口视图对象(View对象)和一个ViewRoot对象的。一个View对象在与一个ViewRoot对象关联的同时,还会关联一个https://www.wendangku.net/doc/1d8844972.html,youtParams对象,这个https://www.wendangku.net/doc/1d8844972.html,youtParams对象是用来描述应用程序窗口视图的布局属性的。 WindowManagerImpl类有三个成员变量mViews、mRoots和mParams,它们分别是类型为View、ViewRoot和https://www.wendangku.net/doc/1d8844972.html,youtParams的数组。这三个数组的大小是始终保持相等的。这样,有关联关系的View对象、ViewRoot对象和https://www.wendangku.net/doc/1d8844972.html,youtParams对象就会分别保存在数组mViews、mRoots和mParams的相同位置上,也就是说,mViews[i]、mRoots[i]和mParams[i]所描述的View对象、ViewRoot 对象和https://www.wendangku.net/doc/1d8844972.html,youtParams对象是具有关联关系的。因此,WindowManagerImpl 类的三个参数版本的成员函数addView在关联一个View对象、一个ViewRoot对象和一个 https://www.wendangku.net/doc/1d8844972.html,youtParams对象的时候,只要分别将它们放在数组mViews、mRoots和mParams的相同位置上就可以了。 理解了一个View对象、一个ViewRoot对象和一个https://www.wendangku.net/doc/1d8844972.html,youtParams 对象是如何关联之后,WindowManagerImpl类的三个参数版本的成员函数addView的实现就容易理解了。 参数view和参数params描述的就是要关联的View对象和https://www.wendangku.net/doc/1d8844972.html,youtParams对象。成员函数addView首先调用另外一个成员函数findViewLocked来检查参数view所描述的一个View对象是否已经存在于数组中mViews中了。如果已经存在的话,那么就说明该View对象已经关联过ViewRoot对象以及https://www.wendangku.net/doc/1d8844972.html,youtParams对象了。在这种情况下,如果参数nest的值等于false,那么成员函数addView是不允许重复对参数view所描述的一个View对象进行重新关联的。另一方面,如果参数nest的值等于true,那么成员函数addView只是重新修改参数view所描述的一个View对象及其所关联的一个ViewRoot对象内部使用的一个https://www.wendangku.net/doc/1d8844972.html,youtParams对象,即更新为参数params所描述的一个https://www.wendangku.net/doc/1d8844972.html,youtParams对象,这是通过调用它们的成员函数setLayoutParams来实现的。 如果参数view所描述的一个View对象还没有被关联过一个ViewRoot对象,那么成员函数addView就会创建一个ViewRoot对象,并且将它与参数view和params分别描述的一个View对象和一个https://www.wendangku.net/doc/1d8844972.html,youtParams对象保存在数组mViews、mRoots 和mParams的相同位置上。注意,如果数组mViews、mRoots和mParams尚未创建,那么成员函数addView就会首先分别为它们创建一个大小为1的数组,以便可以用来分别保存所要关联的View对象、ViewRoot对象和https://www.wendangku.net/doc/1d8844972.html,youtParams对象。另一方面,如果数组mViews、mRoots和mParams已经创建,那么成员函数addView就需要分别将它们的大小增加1,以便可以在它们的末尾位置上分别保存所要关联的View对象、ViewRoot对象和https://www.wendangku.net/doc/1d8844972.html,youtParams对象。 还有另外一个需要注意的地方是当参数view描述的是一个子应用程序窗口的视图对象时,即https://www.wendangku.net/doc/1d8844972.html,youtParams对象wparams的成员变量type的值大于等于https://www.wendangku.net/doc/1d8844972.html,youtParams.FIRST_SUB_WINDOW并且小于等于https://www.wendangku.net/doc/1d8844972.html,ST_SUB_WINDOW时,那么成员函数addView还需要找到这个子视图对象的父视图对象panelParentView,这是通过遍历数组mRoots来查找的。首先,https://www.wendangku.net/doc/1d8844972.html,youtParams对象wparams的成员变量token指向了一个类型为W的Binder本地对象的一个IBinder接口,用来描述参数view所描述的一个子应用程序窗口视图对象所属的父应用程序窗口视图对象。其次,每一个ViewRoot对象都通过其成员变量mWindow来保存一个类型为W的Binder本地对象,因此,如果在数组mRoots中,存在一个ViewRoot对象,它的成员变量mWindow所描述的一个W对象的一个IBinder接口等于https://www.wendangku.net/doc/1d8844972.html,youtParams对象wparams的成员变量token所描述的一个IBinder接口时,那么就说明与该ViewRoot对象所关联的View对象即为参数view的父应用程序窗口视图对象。 成员函数addView为参数view所描述的一个View对象和参数params所描述的一 个https://www.wendangku.net/doc/1d8844972.html,youtParams对象关联好一个ViewRoot对象root之后,最后还会将这个View对view象和这个https://www.wendangku.net/doc/1d8844972.html,youtParams对象,以及变量panelParentView所描述的一个父应用程序窗视图对象,保存在这个ViewRoot对象root的内部去,这是通过调用这个ViewRoot对象root的成员函数setView来实现的,因此,接下来我们就继续分析ViewRoot类的成员函数setView的实现。 Step 13. ViewRoot.setView [java] view plain copy 在CODE上查看代码片派生到我的代码片 public final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Callbacks { ...... final https://www.wendangku.net/doc/1d8844972.html,youtParams mWindowAttributes = new https://www.wendangku.net/doc/1d8844972.html,youtParams(); ...... View mView; ...... final View.AttachInfo mAttachInfo; ...... boolean mAdded; ...... public void setView(View view, https://www.wendangku.net/doc/1d8844972.html,youtParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { mView = view; mWindowAttributes.copyFrom(attrs); ...... mAttachInfo.mRootView = view; ....... if (panelParentView != null) { mAttachInfo.mPanelParentWindowToken = panelParentView.getApplicationWindowToken(); } mAdded = true; ...... requestLayout(); ...... try { res = sWindowSession.add(mWindow, mWindowAttributes, getHostVisibility(), mAttachInfo.mContentInsets, mInputChannel); } catch (RemoteException e) { mAdded = false; mView = null; ...... throw new RuntimeException("Adding window failed", e); } finally { if (restore) { attrs.restore(); } } ...... } ...... } } ...... } 这个函数定义在文件frameworks/base/core/java/android/view/ViewRoot.java中。 参数view所描述的一个View对象会分别被保存在ViewRoot类的成员变量mView 以及成员变量mAttachInfo所描述的一个AttachInfo的成员变量mRootView中,而参数attrs 所描述的一个https://www.wendangku.net/doc/1d8844972.html,youtParams对象的内容会被拷贝到ViewRoot类的成员变量mWindowAttributes中去。 当参数panelParentView的值不等于null的时候,就表示参数view描述的是一个子应用程序窗口视图对象。在这种情况下,参数panelParentView描述的就是一个父应用程序窗口视图对象。这时候我们就需要获得用来描述这个父应用程序窗口视图对象的一个类型为W的Binder本地对象的IBinder接口,以便可以保存在ViewRoot类的成员变量mAttachInfo 所描述的一个AttachInfo的成员变量mPanelParentWindowToken中去。这样以后就可以知道ViewRoot类的成员变量mView所描述的一个子应用程序窗口视图所属的父应用程序窗口视图是什么了。注意,通过调用参数panelParentView的所描述的一个View对象的成员函数getApplicationWindowToken即可以获得一个对应的W对象的IBinder接口。 上述操作执行完成之后,ViewRoot类的成员函数setView就可以将成员变量mAdded 的值设置为true了,表示当前正在处理的一个ViewRoot对象已经关联好一个View对象了。 接下来,ViewRoot类的成员函数setView还需要执行两个操作: 1. 调用ViewRoot类的另外一个成员函数requestLayout来请求对应用程序窗口视图的UI作第一次布局。 2. 调用ViewRoot类的静态成员变量sWindowSession所描述的一个类型为Session 的Binder代理对象的成员函数add来请求WindowManagerService增加一个WindowState对象,以便可以用来描述当前正在处理的一个ViewRoot所关联的一个应用程序窗口。 至此,我们就分析完成Android应用程序窗口视图对象的创建过程了。 课程代号:83308113 2014-2015学年第1学期《ISAS与项目训练(一)》 项目:Android 班级:网络2班 学号: 13734214 姓名:刘雨亭. 指导教师:温一军周洪斌 . 沙洲职业工学院 NIIT安艾艾迪 目录 一、系统简介 (3) 二、发展历程 (3) 三、发行版本 (4) 四、国内外手机应用状况 (4) 五、发展趋势 (5) 六、Android的相关技术介绍及分析 (6) 6.1、Android系统架构研究 (6) 6.2、应用程序框架 (7) 6.3、类库 (8) 七、Android的API (10) 八、Android活动的生命周期 (11) 一、系统简介 Android的Logo是由Ascender公司设计的,诞生于2010年,其设计灵感源于男女厕所门上的图形符号,于是布洛克绘制了一个简单的机器人,它的躯干就像锡罐的形状,头上还有两根天线,Android小机器人便诞生了。其中的文字使用了Ascender 公司专门制作的称之为“Droid ”的字体。Android是一个全身绿色的机器人,绿色也是Android的标志。颜色采用了PMS 376C和RGB中十六进制的#A4C639来绘制,这是Android操作系统的品牌象徵。有时候,它们还会使用纯文字的Logo。 二、发展历程 2003年10月,Andy Rubin等人创建Android公司,并组建Android团队。 2005年8月17日,Google低调收购了成立仅22个月的高科技企业Android及其团队。安迪鲁宾成为Google公司工程部副总裁,继续负责Android项目。 2007年11月5日,谷歌公司正式向外界展示了这款名为Android的操作系统,并且在这天谷歌宣布建立一个全球性的联盟组织,该组织由34家手机制造商、软件开发商、电信运营商以及芯片制造商共同组成,并与84家硬件制造商、软件开发 android 自定义圆角头像以及使用declare-styleable进行配置属性解析由于最新项目中正在检查UI是否与效果图匹配,结果关于联系人模块给的默认图片是四角稍带弧度的圆角,而我们截取的图片是正方形的,现在要给应用统一替换。应用中既用到大圆角头像(即整个头像是圆的)又用到四角稍带弧度的圆角头像,封装一下以便重用。以下直接见代码 [java] view plain copy 在CODE上查看代码片派生到我的代码片 package com.test.demo; import com.test.demo.R; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Shader.TileMode; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.widget.ImageView; /** * 圆角imageview */ public class RoundImageView extends ImageView { private static final String TAG = "RoundImageView"; /** * 图片的类型,圆形or圆角 */ private int type; public static final int TYPE_CIRCLE = 0; public static final int TYPE_ROUND = 1; /** * 圆角大小的默认值 Android平台我的日记 设计文档 项目名称:mydiray 项目结构示意: 阶段任务名称(一)布局的设计 开始时间: 结束时间: 设计者: 梁凌旭 一、本次任务完成的功能 1、各控件的显示 二、最终功能及效果 三、涉及知识点介绍 四、代码设计 activity_main.xml: android:layout_centerHorizontal="true" android:layout_marginTop="88dp" android:text="@string/wo" android:textSize="35sp"/> Android开发把项目打包成apk 做完一个Android项目之后,如何才能把项目发布到Internet上供别人使用呢?我们需要将自己的程序打包成Android安装包文件--APK(Android Package),其后缀名为".apk"。将APK文件直接上传到Android模拟器或Android手机中执行即可进行安装。Android系统要求具有其开发者签名的私人密钥的应用程序才能够被安装。生成数字签名以及打包项目成APK都可以采用命令行的方式,但是通过Eclipse中的向导我们会更加方便地完成整个流程,打包发布的过程非常简单。下面以前面开发的"Hello World"为例,演示如何生成APK。 右键单击项目名称,选择"Android Tools",再选择"Export Signed Application Package…",如下图所示。 进入左图所示页面,单击"Next>"按钮,进入如右图所示窗口。 其中,Location为证书库将要存放的位置,Password是证书库的密码。 打包程序时,系统要求使用数字证书。如果没有数字证书,我们选择"Create new keystore"新创建一个证书库,单击"Browse…"按钮选择证书库将要保存的位置并填入信息,如左图所示。单击"Next>"按钮,如右图所示。 其中,Alias是该证书的名字;password是该证书的密码;Validity是指定证书有效 年份。 如果已经拥有一个证书,那么可以选择"Use existing keystore",之后直接定位到证书库的位置并填入密码,如左图所示,接下来填入密码,单击"Next>"按钮,如右图所示。 单击"Browse…"按钮,选择文件保存的位置,如下图所示。 "Destination APK file "指定APK存储的位置。单击"Finish"按钮,打包完成。 android 自定义控件的过程 invalidate()会导致computeScroll()以及onDraw()方法的执行computeScroll()方法是在屏幕流动的时候不停的去调用,scrollTo(int x,int y)则是滚动到相应的位置; scrollBy(int x, int y)则是移动一些距离,X为正是向左移动,为负时向右移动,Y与X的意义一个,只是是上下移动而已View对象显示在屏幕上,有几个重要步骤: 1.构造方法创建对象 2.测量View的大小onMeasure(int,int); 3.确定View的位置,View自身有一些权,决定权在父View手中. onLayout();基本上不常用,在继承View的时候基本上用不着,但在继承ViewGroup的时候的就要用到了,因为要对View进行布局,确定View的位置,确定的时候使用 指定子View的位置,左,上,右,下,是指在ViewGroup坐标系中的位置https://www.wendangku.net/doc/1d8844972.html,yout(int xtop,int ytop, int xbottom, int ybottom); 4.绘制View的内容onDraw(Canvas) 实现过程: 1、构造方法: /** * 在布局文件中声名的view,创建的时候由系统调用 * * @param context * 上下文对象 * @param attrs * 属性集 */ public MyToggleButton(Context context, AttributeSet attrs) { super(context, attrs); initView(); } 2、测量View的大小: /** * 测量尺寸时的回调方法 */ 总结android项目的基本开发步骤 做了几个android企业应用项目后,总结了项目的基本开发步骤,希望能够交流。一应用规划: -确定功能。 -必须的界面及界面跳转的流程。 -需要的数据及数据的来源及格式。 -是否需要服务端支持。 -是否需要本地数据库支持。 -是否需要特殊权限。 -是否需要后台服务。 二架构设计: -分层。 -网络连接。 -数据处理-xml、domain。 -封装Activity。 三界面设计: -主界面确定。 -模块界面、列表、查看、编辑界面。 -菜单、按钮、对话框、提示信息。 -界面总体颜色。 四数据操作和存储: -数据来源。 -数据类型。 -存储方式。 五业务实现: -客户端业务解析。 六页面跳转: -每个页面间的跳转。 -菜单、按钮、事件等。 #开发之前还需要做一些准备工作 1.技术储备 a.Java 重要程度:????? -框架,编程思想,编码规范,设计模式等 b.Xml 重要程度:???? -布局,选择器,配置文件等 c.数据库重要程度:??? -关系型数据库,SQLite 2.开发工具 a.Eclipse或者AndroidStudio b.Android SDK c.其他:svn / git,JDK,资源,数据库,模拟器,真机等 #开发过程中还有以下的一些流程 1.多种开源框架和优秀源码的引用 -xUtils,Volley,Vitamio,SlidingMenu等 2.数据访问 -访问框架 -传递方式 3.多种API的接入 -短信服务 -即时通信 -消息推送 -第三方登录等 4.后台开发 -后台的开发,为app提供接口 -后台的云服务器 5.内存优化 -垃圾回收 -一、二级缓存 -适配器的优化 -图片框架及资源的优化 6.多线程异步 -Handler -Asynctask 7.屏幕适配 #开发基本结束之后还有很多需要流程 1.多型号真机实测 2.云服务器优化 3.APK加密 4.数字签名 5.用户协议 6.应用平台 7.项目上线 8.应用推广和广告插入 9.版本更新和维护 Android进阶——自定义View之自己绘 制彩虹圆环调色板 引言 前面几篇文章都是关于通过继承系统View和组合现有View来实现自定义View的,刚好由于项目需要实现一个滑动切换LED彩灯颜色的功能,所以需要一个类似调色板的功能,随着手在调色板有效区域滑动,LED彩灯随即显示相应的颜色,也可以通过左右的按钮,按顺序切换显示一组颜色,同时都随着亮度的改变LED彩灯的亮度随即变化,这篇基本上把继承View重绘实现自定义控件的大部分知识总结了下(当然还有蛮多没有涉及到,比如说自适应布局等),源码在Github上 一、继承View绘制自定义控件的通用步骤 自定义属性和继承View重写onDraw方法 实现构造方法,其中public RainbowPalette(Context context, AttributeSet attrs) 必须实现,否则无法通过xml引用,public RainbowPalette(Context context) ,public RainbowPalette(Context context, AttributeSet attrs, int defStyleAttr)可选,通常在构造方法中完成属性和其他成员变量的初始化 重写onMeasure方法,否则在xml中有些设置布局参数无效 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(width, height);//重新设置View的位置,若不重写的话,则不会布局,即使设置centerInParent为true也无效 //setMeasuredDimension(width,height); } 手动调用invalidate或者postInvalidateon方法完成界面刷新 重写onTouchEvent方法实现基本的交互 定义回调接口供外部调用 二、彩虹圆环调色板设计思想 自定义Dialog; dialog = new Dialog(this); dialog.setContentView(https://www.wendangku.net/doc/1d8844972.html,yout.by_baseinfo); dialog.setTitle("dialog的title"); /* * 获取Dialog的窗口对象及参数对象以修改对话框的布局设置, 可以直接调用this.getWindow(),表示获得这个Activity的Window * 对象,这样这可以以同样的方式改变这个Activity的属性. * Activity不可见时getWindow()返回值为null; */ Window dialogWindow = dialog.getWindow(); // 对话框的布局设置参数; https://www.wendangku.net/doc/1d8844972.html,youtParams layoutParams = dialogWindow.getAttributes(); // 设置Window中的内容为左上对齐; dialogWindow.setGravity(Gravity.LEFT | Gravity.TOP); /* * lp.x与lp.y表示相对于原始位置的偏移. * 当参数值包含Gravity.LEFT时,对话框出现在左边,所以lp.x就表示相对左边的偏移,负值忽略. * 当参数值包含Gravity.RIGHT时,对话框出现在右边,所以lp.x就表示相对右边的偏移,负值忽略. * 当参数值包含Gravity.TOP时,对话框出现在上边,所以lp.y就表示相对上边的偏移,负值忽略. * 当参数值包含Gravity.BOTTOM时,对话框出现在下边,所以lp.y就表示相对下边的偏移,负值忽略. * 当参数值包含Gravity.CENTER_HORIZONTAL时 * ,对话框水平居中,所以lp.x就表示在水平居中的位置移动lp.x像素,正值向右移动,负值向左移动. * 当参数值包含Gravity.CENTER_VERTICAL时 * ,对话框垂直居中,所以lp.y就表示在垂直居中的位置移动lp.y像素,正值向右移动,负值向左移动. * gravity的默认值为Gravity.CENTER,即Gravity.CENTER_HORIZONTAL | * Gravity.CENTER_VERTICAL. * * 本来setGravity的参数值为Gravity.LEFT | Gravity.TOP时对话框应出现在程序的左上角,但在 * 我手机上测试时发现距左边与上边都有一小段距离,而且垂直坐标把程序标题栏也计算在内了, Gravity.LEFT, Gravity.TOP, * Gravity.BOTTOM与Gravity.RIGHT都是如此,据边界有一小段距离 */ // 相对于屏幕原位置(加上标题栏) 的偏移量; lp.x = 100; // 新位置X坐标 今天和大家分享下组合控件的使用。很多时候android自定义控件并不能满足需求,如何做呢?很多方法,可以自己绘制一个,可以通过继承基础控件来重写某些环节,当然也可以将控件组合成一个新控件,这也是最方便的一个方法。今天就来介绍下如何使用组合控件,将通过两个实例来介绍。 第一个实现一个带图片和文字的按钮,如图所示: 整个过程可以分四步走。第一步,定义一个layout,实现按钮内部的布局。代码如下: 1. 2. 目录 1 项目简介 (2) 2 开发环境 (2) 2.1Android 平台结构介绍 (2) 22 MVC 框架 (3) 3 功能介绍 (3) 3.1 登录 (3) 3.2 注册 (3) 3.3添加 (4) 3.4 查询 (5) 3.5主页面 (6) 4 数据库结构 (7) 4.1 数据表设计 (7) 5 项目结构 (7) 5.1 src 文件夹 (7) 52 gen 文件夹 (7) 5.3 libs 文件夹 (8) 5.4 bin 文件夹 (8) 5.5 res 文件夹 (8) 5.6 AndroidManifest.xml (8) 6 项目总结 (8) Android 项目开发报告 1 项目简介 本次中软培训主要是关于android 的基本应用开发,培训的任务主要是开发一个与日常生活花费有关的现金日记账软件,由于时间紧张此软件只实现了登录、注册、添加、查询等功能,未涉及细节处理。此次项目开发主要是帮助大家培养理财观念,清楚直白的了解每笔前是怎么消费,何时消费掉的,利于节约一部分开支。 2 开发环境 2.1Android 平台结构介绍 Android 系统架构和其操作系统一样,采用了分层的架构。Android 分为四个层,从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和linux 核心层。 开发人员可以完全访问核心应用程序所使用的API 框架。该应用程序的架构设计简化了组件的重用。任何一个应用程序都可以发布它的功能块并且任何其它的应用程序都可以使用其所发布的功能块(不过得遵循框架的安全性限制)。同样,该应用程序重用机制也使用户可以方便的替换程序组件。 应用程序。Android 会同一些核心程序包一起发布,包括日历、地图、浏览器等。所有的应用程序均是用Java 语言编写。 应用程序框架。这种框架可以使开发人员可以完全的访问核心程序所使用 的API 框架,简化了组件的使用。同时也使用户可以方便的替换程序组件。 系统运行库。An droid包含一些C/C++库,这些库能被An droid系统中不同的组件使用。一般情况下如果要将Android 移植到其他硬件去运行,只需要实现这部分代码即可。Android 也包括了一个核心库,该核心库提供了Java 编程语言核心库的大多数功能。 Linux 内核。Android 的核心系统服务依赖于Linux 2.6 内核,如安全性、内存管理、进程管理、网络协议栈和驱动模型。Linux 内核也同时作为硬件和软件栈之间的抽象层。2.2 MVC 框架 MVC开始是存在于桌面程序中的,M是指业务模型,V是指用户界面,C则是控制 android项目心得体会 篇一:Android实训心得 Android实训心得 刚开始接触Android感觉到它很有意思,在界面开发上和web也可以形成了相通的架构,更加方便,视觉上也是非常的酷,在前期我通过的大量的AndroidSdK开发范例大全中的例子以及Android提供的APIdEmoS进行学习,尽管例子之间的连接比较零散,不过通过这些例子的学习我可以学习到了很多和以前java上相通的思想。 我在为期半个月的实习中学到了很多在课堂上根本就学不到的知识,收益非浅.现在我对这半个月的实习做一个工作小结。 通过半个月的android实习,基本掌握了Android应用程序开发的一般流程。对常用控件基本掌握其用法,对其事件的监听方法也基本掌握。学习Android不仅是对前沿开发技术的了解,也是对编程知识的一次提升。 通过学习Android的控件、布局、Activity、Service等一系列基础知识,对整个Android的开发有了大致的了解。例如要的布局(或者控件),在学习界面中,我发现Android为我们提供了很好的类似反射机制,通过Layout文件夹下的配置文件,可以快速的形成界面,在配置文件可以设置属性或者样式都是很快捷方便。对比较特殊的界面也可以通过处理嵌入到指定的界面,同样你可以通过java代码直接创建View进行添加,不过这种方式比较复杂。对一些点击、选中、按键等处理的事件,界面之间的跳转Intent管理,通过bundle对数据在界面之间进行 传输。 在手机交互式通信服务中,学习了Android手机之间进行短信发送、广播、对广播的监听、服务等,在Service类中没有context,可以通过Handler来每秒反复运行,自动送出系统广播信息,同时在这里我们也知道可以设计一个常用的变量类,设计一个当前的currentActivity这个变量进行控制,进行处理。 在Android编程过程中巩固熟悉了Java的编程。由于Android应用程序的开发离不开Java的支持,所以基础的Java知识是必须的。Android 系统是基于Linux的手机操作系统平台,要深入系统的学习Android,不仅仅是有Java和Android应用开发,必须要具备Linux,cc++高级编程才能深入的涉及Androidframework和Android内核开发。成为Android开发的高素质人才。所以,在后续对Android的学习中可能会看一些较底层的书籍。 由于这次实习时间较短,对于Android应用程序的高级编程讲的很少,是这次实习中的不足。要想开发一些好的应用程序,还需要更多的知识支持。在做实习最后的项目时,遇到了很多平时没有遇到或者没有特别关注的问题,如常见的Activity忘记注册,对Sd卡存取需要权限,在写SqL语句时细微的错误就可能导致程序运行错误。这些问题只有自己在实际开发中才能体会到并且解决,并且在解决后可以长时间的记住。 通过Android的实习,我们在大四毕业前,我们又掌握了一项新的前沿的开发技能,也有了更多的发展方向,这在以后的找工作的过程中无疑为我们增加了砝码,也可以成为我们的一项兴趣爱好,可以根据 android自定义View之Android手机通讯录制作 我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的Android手机通讯录都有这样的效果。那我们今天就来看看这个效果该怎么实现。 一.概述 1.页面功能分析 整体上来说,左边是一个ListView,右边是一个自定义View,但是左边的ListView 和我们平常使用的ListView还有一点点不同,就是在ListView中我对所有的联系人进行了分组,那么这种效果的实现最常见的就是两种思路: 1.使用ExpandableListView来实现这种分组效果 2.使用普通ListView,在构造Adapter时实现SectionIndexer接口,然后在Adapter 中做相应的处理 这两种方式都不难,都属于普通控件的使用,那么这里我们使用第二种方式来实现,第一种方式的实现方法大家可以自行研究,如果你还不熟悉ExpandableListView的使用,可以参考我的另外两篇博客: 1.使用ExpandableListView实现一个时光轴 2.android开发之ExpandableListView的使用,实现类似QQ好友列表 OK,这是我们左边ListView的实现思路,右边这个东东就是我们今天的主角,这里我通过自定义一个View来实现,View中的A、B......#这些字符我都通过canvas的drawText 方法绘制上去。然后重写onTouchEvent方法来实现事件监听。 2.要实现的效果 要实现的效果如上图所示,但是大家看图片有些地方可能还不太清楚,所以这里我再强调一下: 1.左边的ListView对数据进行分组显示 2.当左边ListView滑动的时候,右边滑动控件中的文字颜色能够跟随左边ListView 的滑动自动变化 3.当手指在右边的滑动控件上滑动时,手指滑动到的地方的文字颜色应当发生变化,同时在整个页面的正中央有一个TextView显示手指目前按下的文字 Android高手进阶教程(三)之----Android 中自定义View的应用. 2010-04-18 21:11:25 标签:Android进阶View定义教程 原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处、作者信息和本声明。否则将追究法律责任。https://www.wendangku.net/doc/1d8844972.html,/1556324/311457 大家好我们今天的教程是在Android 教程中自定义View 的学习,对于初学着来说,他们习 惯了Android 传统的页面布局方式,如下代码: view plaincopy to clipboardprint? 1. 2. 目录 1项目简介 (2) 2开发环境 (2) 2.1Android平台结构介绍 (2) 2.2 MVC框架 (3) 3功能介绍 (3) 3.1登录 (3) 3.2注册 (3) 3.3添加 (4) 3.4查询 (5) 3.5主页面 (6) 4数据库结构 (7) 4.1数据表设计 (7) 5项目结构 (8) 5.1 src文件夹 (8) 52 gen文件夹 (8) 5.3 libs文件夹 (8) 5.4 bin文件夹 (8) 5.5 res文件夹 (8) 5.6 AndroidManifest.xml (9) 6项目总结 (9) Android项目开发报告 1项目简介 本次中软培训主要是关于android的基本应用开发,培训的任务主要是开发一个与日常生活花费有关的现金日记账软件,由于时间紧此软件只实现了登录、注册、添加、查询等功能,未涉及细节处理。此次项目开发主要是帮助大家培养理财观念,清楚直白的了解每笔前是怎么消费,何时消费掉的,利于节约一部分开支。 2开发环境 2.1Android平台结构介绍 Android系统架构和其操作系统一样,采用了分层的架构。Android分为四个层,从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和linux 核心层。 开发人员可以完全访问核心应用程序所使用的API框架。该应用程序的架构设计简化了组件的重用。任何一个应用程序都可以发布它的功能块并且任何其它的应用程序都可以使用其所发布的功能块(不过得遵循框架的安全性限制)。同样,该应用程序重用机制也使用户可以方便的替换程序组件。 应用程序。Android会同一些核心程序包一起发布,包括日历、地图、浏览器等。所有的应用程序均是用Java语言编写。 应用程序框架。这种框架可以使开发人员可以完全的访问核心程序所使用的API框架,简化了组件的使用。同时也使用户可以方便的替换程序组件。 系统运行库。Android包含一些C/C++库,这些库能被Android系统中不 GitHub上最火的40个Android开源项目(一) GitHub上最火的40个Android开源项目(一) GitHub上最火的40个Android开源项目(二) GitHub上最火的74个Android开源项目(三) GitHub上最火的40个iOS开源项目(一) GitHub上最火的40个iOS开源项目(二) GitHub在中国的火爆程度无需多言,越来越多的开源项目迁移到GitHub平台上。更何况,基于不要重复造轮子的原则,了解当下比较流行的Android与iOS开源项目很是必要。利用这些项目,有时能够让你达到事半功倍的效果。 下面,就让我们一起来看看,在GitHub平台上,究竟有哪些Android开源项目最火,也最受开发者欢迎。 1.ActionBarSherlock ActionBarSherlock应该算得上是GitHub上最火的Android开源项目了,它是一个独立的库,通过一个API和主题,开发者就可以很方便地使用所有版本的Android动作栏的设计模式。 对于Android 4.0及更高版本,ActionBarSherlock可以自动使用本地ActionBar实现,而对于之前没有Act ionBar功能的版本,基于Ice Cream Sandwich的自定义动作栏实现将自动围绕布局。能够让开发者轻松开发一款带动作栏(Actio n bar)的应用,并且适用于Android 2.x及其以上所有版本。 详情请参考:ActionBarSherlock 2.facebook-android-sdk Facebook SDK for Android是一个开源库,允许开发者将Facebook集成到所开发的Andr oid应用中。 如果想要获取更多关于示例、文档、将SDK集成到App中、源代码等信息,可直接登陆Face book Developers查看。 3.SlidingMenu(SlidingMenu Demos) 基于Android的自定义媒体播放控件设计与实现 摘要:针对日益增加的个性化应用需求,提出了基于Android的自定义媒体播放控件。该控件通过继承VideoView 实现视频、图片媒体的播放,与网络、数据库进行结合可以下载媒体资源与管理资源。控件中定义了下载回调,即实时显示当前的、下载进度,因而有助于提升用户体验。 关键词:Android;自定义控件;媒体播放;VideoView DOIDOI:10.11907/rjdk.161461 中图分类号:TP319 文献标识码:A 文章编号:1672-7800(2016)005-0079-03 0 引言 在Android系统中,提供了很多控件用于Android应用的开发,其控件的丰富性能可满足基本的应用开发需求。但是随着定制应用的日益增加,基本的控件已很难满足需求,从另一方面而言,这也约束了个性化应用的发展。Google提供的自定义控件方法可以达到应用开发的个性化要求[1]。在Android程序中,视频媒体播放使用VideoView控件实现,或者使用MediaPlayer与SurfaceView结合实现媒体播放功能。对于图片的显示则使用ImageView来实现[2]。日常生活中,视频和图片都是大众最常见的媒体,在一个界面上要既能显 示图片又能显示视频,所以,本文提出了一种继承VideoView 的自定义媒体播放控件,该控件不仅可以显示图片,还可以播放视频,并且在下载视频的过程中可以显示下载进度。同时,自定义媒体播放控件和数据库结合,能够实现媒体文件的自动循环播放。 1 Android系统 Android系统由Google公司2007年在Google I/O开发者大会上发布的移动操作系统,Google将其源码开放以供广大开发者研究。Android系统采用分层架构,具体分为Applications、Application Framework、Libraries(包含Android Runtime)、Linux Kernel四层。Android应用开发者最常接触的是前两层,后两层主要用于底层库和硬件驱动等[3-5]。 2 View及其自定义媒体控件相关类 2.1 View类介绍 在Android系统的Application Framework层,提供了丰富的UI控件,所有UI控件都是直接或间接继承View类。View 类是所有UI控件的基类,该类表示了用户界面的基本构建模块――一个View占用屏幕的矩形区域并且负责界面绘制和事件处理[6-7]。 View类中有很多方法,这些方法都与其界面绘制和事件处理相关,下面简单介绍几个方法: ①onMeasure(int,int):该方法用于获取控件的宽、高, Android项目开发 实训报告 姓名:赵炳琪 学号: 140840131 专业:软件技术 项目名称: Android手机记账本 指导教师:陈雪莲 实训日期:2016年10月30日至2016年12月30日2016年12月 25日 Android项目开发实训记录单 目录 第一章概述 (1) 第二章需求分析 (2) 2.1 项目背景 (2) 2.2 项目需求 (2) 第三章相关技术 (4) 3.1 Adnroid平台介绍 (4) 3.2 关键技术研究 (6) 第四章概要设计 (9) 4.1 系统体系结构 (9) 4.2 用户界面设计 (14) 4.2.1计算器界面 (14) 4.2.2小数点运算界面 (14) 4.2.3负数运算界面 (15) 4.2.4开方运算界面 (15) 第五章详细设计 (16) 5.1数据输入模块 (16) 5.2数据显示模块 (16) 5.3 数据计算功能模块 (16) 第六章结论 (26) 第一章概述 随着社会的发展,经济水平的提高,手机越来越普及。同时伴随着已送慧联网技术的发展,手机的功能也变得越来越丰富。从原来只具有简单通信功能的非智能手机到现在具有手机操作系统,除通话功能以外,还集上网、聊天、炒股、收发邮件等功能于一身的智能手机系统。 由Google公式牵头众多实力雄厚的软硬件厂商加盟商成立了OMS联盟,病退出的Android 平台手机系统,作为时代的新生儿,Android手机操作平台有着得天独厚的优势广阔的发展前景。 而计算器作为现在人们日常生活中常用的一种工具也已经可以说是人们日常生活中必不可少的工具了。计算器的发展同样经历了漫长的过程,凝聚无数仙人的智慧,甚至连计算机的发展都可以说是源于计算器的发展。本程序正式基于Android平台开发的计算器。 本课题要求:设计一个基于Android的计算器的软件。实现的功能有: 具有基本的加、减、乘、除功能,能够判断用户输入运算数是否正确,支持小数运算,具有退格功能,能够删除最后一个输入,具有清除功能,即“C”。因为打开(ON)、关闭(OFF)屏幕按键的功能 需重点研究的关键问题:计算器的运算和显示问题。 项目1 网上厨房 项目简介: 传统的家庭主妇做饭套路是:痛苦的思考今晚吃什么菜,翻开菜谱查看怎么做,然后去买相应得到材料,按照步骤做晚饭。“网上厨房”的做法是,打开冰箱看看家里有什么食材,把他们的关键字输入“网上厨房”,在搜索了超过几万份菜谱后,你马上知道该吃什么,怎么做! 项目特点: a)ViewPager的使用: 在目前的UI开发过程当中,如何更好的利用屏幕是一个最主要的课程, 在本项目当中,使用了ViewPager作为界面的基本组织方式,为用户提 供了更好的使用体验; b)图片二次采样: 在项目当中,UI需要展示大量的图片,而手机内存有限,为了保证应用 程序内容使用控制在一定的范围之内,采用二次采样的方法降低图片所 占用的内存数量; c)XMPP; 为了更好的实现软件的商业价值,本项目每天会向客户端推送一条菜谱 信息,该功能使用全球通用XMPP推送协议实现。 项目截图: 项目2 瞭望电子杂志 项目简介: 该关键是某知名新媒体手机客户端,作为大陆发行量最大的新闻类周刊,本客户端利用权威的新闻资源和高端的影响力,致力于为广大客户提供最好的新闻浏览体验。 本客户端提供有观点的新闻,即使更新,在信息碎片化的时代,为用户提供有深度和洞察力的新闻。 项目技术点: a)HTTP协议通信技术; 本项目采用HTTP协议与服务器端通讯,在出现文字与图片混排时使用 异步加载提升系统响应速度,增强用户体验; b)图片缓存技术: 目前3G流量的收费还比较昂贵,而本客户端需要从服务器下载大量的 图片和文本信息,为了减少流量的消耗,本程序采用了强引用、软引用 和SDCard三层缓存来减少图片加载的消耗,与此同时进一步加强了软 件的运行速度 c)pdf解析: 该软件支持需要从服务器下载每一期的电子杂志,需要手机端对PDF格 式的文件进行解析和显示; 项目截图: 自定义Android带图片的按钮 前言 现在移动设备的按钮设计讲究大图标小文字,希望用户只要一看到图标便能知道这个按钮是干嘛的,但又要有必要的文字提示,最常见的就数搜索按钮了,上面一个大大的放大镜图标,下面两个字——搜索。 Bill最近也在做具有这种效果的按钮,过程总是曲折的,不过结果总是美好滴~现在Bill把其做法分享给大家,希望对还不会的朋友有所帮助。 先看看bill曲折的过程吧,也许里面就有你的影子: 最开始以为直接利用Android控件ImageButton即可完事,谁知事不如人料,ImageButton 只能显示图片,并不能对其添加文字,此想法不攻自破。 于是我想到了直接用Button,但是Button的文字却是显示在图片内部,并不能达到我的需求。放弃。 懒人总有懒人的办法,我可以直接在图片下方PS需要的文字嘛,然后把P好的图片放进ImageButton就好了。此法十分简单好用。但是,一旦我们需要改变文字,或者我要把文字显示在图片顶部而不是底部怎么办?此法虽简单,却缺乏可变性。放弃。 这就是所谓的“一钮三折”了~ 那么,有没有一种方法既能够拥有Button的效果,又能够实现Button显示的自定义呢? 答案是肯定的,接下来,bill将一步一步详细解释这个按钮的制作过程。 思路 首先,我们来看一下这个按钮的实现思路。有一种思维方式叫做“out of box”,也就是鼓励大家跳出固定思维模式以寻求新的突破。但是在“跳出箱子”之前,我们必须首先知道困住我们思维的“箱子”是什么。 在这里,这个箱子就是“按钮”。我们一直在想,如何去实现这个“按钮”,怎么才能让“按钮”显示出图片,然后在图片下面还显示一行字。我们就在“按钮”这个箱子里纠结。 但实际上,当我们发现所谓的“按钮”其实就是一个View的时候,一切就变得简单了。 它只不过是一个可点击、可设置监听、可显示文字或者图片的View而已。那么我们就跳出Android给我们设置的这个箱子,自己重新造一个具有我们需要的功能和外观的View 不就OK了? 经过分析,上述按钮效果实际上就是一个布局,一个最简单不过的垂直线性布局,上部分是一个ImageView,下部分是一个TextView,这个布局可点击、可设置监听。 我们首先要编写自己的ImageButton类,然后在主布局文件中为我们自定义的Button 编写布局,最后在Activity中调用我们自定义ImageButton即可。 那么接下来我们就一起来实现这个简单的LinearLayout。 编码实现自己的ImageButton 在编写我们自己的ImageButton之前,如果读者并不清楚如何在一个静态的xml布局文件中动态地加载子布局,请先阅读下面的博文(此文言简意赅,已经写得很清楚了,bill就不再赘述) https://www.wendangku.net/doc/1d8844972.html,/lzx_bupt/article/details/5600187首先,我们编写一个MyImageButton类,继承自LinearLayoutAndroid项目文档
android 自定义圆角头像以及使用declare-styleable进行配置属性解析
Android平台我的日记设计文档
Android项目打包成apk
android 自定义控件的过程
总结android项目的基本开发步骤
Android进阶——自定义View之自己绘制彩虹圆环调色板
android自定义布局或View
Android自定义控件
Android项目开发报告
android项目心得体会.doc
android自定义View之Android手机通讯录制作
Android自定义View
Android项目开发报告
40个Android开源项目
基于Android的自定义媒体播放控件设计与实现
Android项目开发实训项目总结报告
好程序员_项目介绍android
自定义Android带图片的按钮