2016-05-24 12:44:13 qq_28938403 阅读数 1096
  • Android移植基础

    Android视频课程,该课程可以让学员了解Android系统架构、学习如何下载Android源码、编译及开发Android、学习如何追踪Android源码、了解Linux内核启动流程、了解Android启动流程、学习如何移植外部函式库至Android源码中。

    26273 人正在学习 去看看 钟文昌
package com.example.baiying;

import java.io.UnsupportedEncodingException;

import android.support.v7.app.ActionBarActivity;
import android.text.TextUtils;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class DengluActivity extends ActionBarActivity  {

    //Long starttimeLong =  System.currentTimeMillis();        //拿到开始时间
    public Button mButton ;
    public EditText username;
    public EditText userpass;
    
    
    public String name;  
    public String password;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);//不顯示标题
        super.onCreate(savedInstanceState);
        setContentView(R.layout.denglu);
        
        username = (EditText) findViewById(R.id.editText1);
        userpass =  (EditText) findViewById(R.id.editText2);
        mButton =  (Button) findViewById(R.id.button1);
        
        mButton.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                // 获取用户名和密码

                try {       

                  //获取edittext内容

                    name = username.getText().toString().trim();
                    password = userpass.getText().toString().trim();
                  } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                  }
                 
                  if(name.equals("14020150029")){
                      Intent intent = new Intent();  
                        intent.setClass(DengluActivity.this, HomeActivity.class);  
                        startActivity(intent);  
                        finish();//停止当前的Activity,如果不写,则按返回键会跳转回原来的Activity
                  }else{
                    Toast.makeText(DengluActivity.this, "账号或密码错误!", Toast.LENGTH_SHORT).show();
                  }
                
            }
        });
       

}
}

2016-09-26 17:20:24 sdkfjksf 阅读数 2121
  • Android移植基础

    Android视频课程,该课程可以让学员了解Android系统架构、学习如何下载Android源码、编译及开发Android、学习如何追踪Android源码、了解Linux内核启动流程、了解Android启动流程、学习如何移植外部函式库至Android源码中。

    26273 人正在学习 去看看 钟文昌

我们知道工厂模式有三兄弟,通常我们说的工厂模式指的是工厂方法模式,它的应用频率最高。本篇博客分享的简单工厂模式是工厂方法模式的“小弟”,确切的来讲它不属于设计模式,而是一种方法。此外,工厂方法模式还有一位“大哥”——抽象工厂模式。

今天我们来分享一下简单工厂模式的一些情况,以及它在Android源码中的应用。

简单工厂模式

定义

简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。

结构

简单工厂模式所涉及到的角色:

  • Product(抽象产品角色):产品的通用接口,定义产品的行为。
  • ConcreteProduct(具体产品角色):具体产品类,实现了Product接口。
  • Creator(工厂角色):工厂类,通过静态工厂方法factoryMethord来创建对象。

实现

抽象产品角色

abstract class Product {  
    //所有产品类的公共业务方法  
    public void methodSame() {  
        //公共方法的实现  
    }  

    //声明抽象业务方法  
    public abstract void methodDiff();  
}

具体产品角色

class ConcreteProduct extends Product {  
    //实现业务方法  
    public void methodDiff() {  
        //业务方法的实现  
    }  
}

工厂角色

class Creator {  
    //静态工厂方法  
    public static Product getProduct(String arg) {  
        Product product = null;  
        if (arg.equalsIgnoreCase("A")) {  
            product = new ConcreteProductA();  
            //初始化设置product  
        }  
        else if (arg.equalsIgnoreCase("B")) {  
            product = new ConcreteProductB();  
            //初始化设置product  
        }  
        return product;  
    }  
}

使用场景

在以下情况下可以考虑使用简单工厂模式:

  1. 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  2. 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。

优点

  • 工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离。

  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。

缺点

  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
  • 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

Android中简单工厂模式的应用

在Android中我们了解的使用到了简单工厂方法的地方有Bitmap对象的获取、Fragment创建等。接下来我们分开看一下。

Bitmap源码分析

首先来说我们是不能通过new方法来创建Bitmap对象的,因为Bitmap类的构造函数是私有的,只能是通过JNI实例化。

接下来我们随便找个入口开始看,比如:

Bitmap bmp = BitmapFactory.decodeFile(String pathName);

我们把源码中的调用关系找出来,如下

public static Bitmap decodeFile(String pathName) {
    return decodeFile(pathName, null);
}

public static Bitmap decodeFile(String pathName, Options opts) {
    Bitmap bm = null;
    InputStream stream = null;
    try {
        stream = new FileInputStream(pathName);
        bm = decodeStream(stream, null, opts);
    } catch (Exception e) {
        /*  do nothing.
            If the exception happened on open, bm will be null.
        */
        Log.e("BitmapFactory", "Unable to decode stream: " + e);
    } finally {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                // do nothing here
            }
        }
    }
    return bm;
}

public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
    // we don't throw in this case, thus allowing the caller to only check
    // the cache, and not force the image to be decoded.
    if (is == null) {
        return null;
    }

    Bitmap bm = null;

    Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
    try {
        if (is instanceof AssetManager.AssetInputStream) {
            final long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
            bm = nativeDecodeAsset(asset, outPadding, opts);
        } else {
            bm = decodeStreamInternal(is, outPadding, opts);
        }

        if (bm == null && opts != null && opts.inBitmap != null) {
            throw new IllegalArgumentException("Problem decoding into existing bitmap");
        }

        setDensityFromOptions(bm, opts);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
    }

    return bm;
}

private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
        Rect padding, Options opts);

/**
 * Set the newly decoded bitmap's density based on the Options.
 */
private static void setDensityFromOptions(Bitmap outputBitmap, Options opts) {
    if (outputBitmap == null || opts == null) return;

    final int density = opts.inDensity;
    if (density != 0) {
        outputBitmap.setDensity(density);
        final int targetDensity = opts.inTargetDensity;
        if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
            return;
        }

        byte[] np = outputBitmap.getNinePatchChunk();
        final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
        if (opts.inScaled || isNinePatch) {
            outputBitmap.setDensity(targetDensity);
        }
    } else if (opts.inBitmap != null) {
        // bitmap was reused, ensure density is reset
        outputBitmap.setDensity(Bitmap.getDefaultDensity());
    }
}

我们来分析一下调用过程,可以看到decodeFile(String pathName)调用的是decodeFile(String pathName, Options opts),在两个参数的decodeFile方法中又去调用了decodeStream(InputStream is, Rect outPadding, Options opts)方法,然后最终调用nativeDecodeAsset或者nativeDecodeStream来构建Bitmap对象,这两个都是native方法(Android中使用Skia库来解析图像 )。再经过setDensityFromOptions方法的一些设置解码密度之类的操作,返回我们要的Bitmap对象。

/**
* Creates Bitmap objects from various sources, including files, streams, and byte-arrays.
*/

看下BitmapFactory的注释我们可以看到,这个工厂支持从不同的资源创建Bitmap对象,包括files, streams, 和byte-arrays,但是调用关系都大同小异。

Fragment创建

有时候,为了简化简单工厂模式,我们可以将抽象产品类和工厂类合并,将静态工厂方法移至抽象产品类中。Fragment的创建使用简单工厂方法没有抽象产品类,所以工厂类放到了实现产品类中。

在AndroidStudio中输入newInstance会自动补全Fragment的简单工厂方法。

public static TasksFragment newInstance() {

    Bundle args = new Bundle();

    TasksFragment fragment = new TasksFragment();
    fragment.setArguments(args);
    return fragment;
}

使用静态工厂方法,将外部传入的参数可以通过Fragment.setArgument保存在它自己身上,这样我们可以在Fragment.onCreate(…)调用的时候将这些参数取出来。

这样写有什么好处呢?

  • 避免了在创建Fragment的时候无法在类外部知道所需参数的问题。

  • Fragment推荐使用setArguments来传递参数,避免在横竖屏切换的时候Fragment自动调用自己的无参构造函数,导致数据丢失。

2018-09-17 23:09:28 qq_43127306 阅读数 4637
  • Android移植基础

    Android视频课程,该课程可以让学员了解Android系统架构、学习如何下载Android源码、编译及开发Android、学习如何追踪Android源码、了解Linux内核启动流程、了解Android启动流程、学习如何移植外部函式库至Android源码中。

    26273 人正在学习 去看看 钟文昌

一个简单漂亮的登录界面源代码!

在这里插入图片描述
在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="2"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/yhdl"
        android:textColor="#ff0000"
        android:textSize="50dp" />
</LinearLayout>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <LinearLayout
        android:layout_width="130dp"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="right"
            android:textSize="25dp"
            android:text="@string/yhm"
            android:paddingTop="15dp"
            />
        <EditText
            android:layout_width="match_parent"
            android:layout_height="20dp" />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="right"
            android:textSize="25dp"
            android:text="@string/mima"
            android:paddingTop="15dp"
            />
    </LinearLayout>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="107dp"
    android:orientation="vertical"
    android:gravity="left">

<EditText
    android:id="@+id/editText7"
    android:layout_width="200dp"
    android:layout_height="5dp"
    android:layout_weight="1"
    android:ems="10"
    android:hint="@string/text"
    android:background="#ffffff"
    android:inputType="textPersonName" />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="20dp" />
    <EditText
        android:id="@+id/editText8"
        android:layout_width="200dp"
        android:layout_height="5dp"
        android:layout_weight="1"
        android:ems="10"
        android:hint="@string/password"
        android:background="#ffffff"
        android:inputType="textPassword"
        />
</LinearLayout>
</LinearLayout>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="20dp">

</LinearLayout>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="3"
    android:orientation="horizontal">



    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_weight="2"

        android:gravity="center"
        android:orientation="horizontal">

        <Button
            android:id="@+id/button11"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="top"

            android:text="登录"
            android:textSize="30dp"/>
        <TextView
            android:layout_width="20dp"
            android:layout_height="match_parent"

            />

        <Button
            android:id="@+id/button12"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="top"
            android:text="取消"
            android:textSize="30dp"/>
    </LinearLayout>


</LinearLayout>
2016-09-09 16:42:12 qq_27813255 阅读数 1297
  • Android移植基础

    Android视频课程,该课程可以让学员了解Android系统架构、学习如何下载Android源码、编译及开发Android、学习如何追踪Android源码、了解Linux内核启动流程、了解Android启动流程、学习如何移植外部函式库至Android源码中。

    26273 人正在学习 去看看 钟文昌

Android也可像iOS7一样做出扁平化的界面。
这里写图片描述
首先是输入框,Android4.2的输入框是只有一条下划线,比较难看
1.在drawable里new–》drawable resource file……编写输入框的样式
然后再activity_main.mxl中background引用。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <corners android:radius="16dp"/>
    <stroke android:color="#fffff4"
        android:width="1dip"/>
    <solid android:color="@null"/>
    <padding android:top="5sp"
        android:left="12sp"
        android:bottom="4sp"/>

</shape>

2.按钮也是一样。也许你会感到奇怪,怎么按钮的根节点是selector??其实是我前面写错了,后来改成这样的。你也可以像输入框的一样以…为根节点。都一样!

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!--<item android:state_pressed="true" android:drawable="@drawable/press"/>-->

    <item android:state_pressed="true">
        <shape>
            <!--色值-->
            <solid android:color="#ffffff" />
            <!--圆角-->
            <corners android:radius="20dp" />

        </shape>
    </item>
    <item>
        <shape>
            <solid android:color="#A4CEFF" />
            <corners android:radius="20dp" />

        </shape>
    </item>
</selector>

然后同样在朱布局文件中引用

2015-04-13 01:03:01 biezhihua 阅读数 2109
  • Android移植基础

    Android视频课程,该课程可以让学员了解Android系统架构、学习如何下载Android源码、编译及开发Android、学习如何追踪Android源码、了解Linux内核启动流程、了解Android启动流程、学习如何移植外部函式库至Android源码中。

    26273 人正在学习 去看看 钟文昌

前言

 好久没有写博客了,都感觉有些生疏了。
 总觉的人对自己要求高一些比较好,这样才进步比较快。接下来会继续给大家带来一些更有用的知识。
 个人水平有限,如果感觉我的博客对您有用处,那就留个言给下鼓励;如果那里写的有误,请各位看客老爷多多拍砖!
 注意:此处我使用的IDE是Android Studio

入门

 相信每个人在学习Android时,都创建过很多Demo工程,那么下面的代码,大家一定非常眼熟了。

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 这句代码是为了讲解方便加的。目的是去掉标题。
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
    }
}

 代码的主要目的是,将布局文件activity_main.xml展现到屏幕上。运行后的效果如下:
 
 使用过View.inflate()方法的朋友,肯定知道这个方法可以将一个XML布局文件,填充为一个View对象,相应的上面的代码就可以转化为这样子了:

View view = View.inflate(this, R.layout.activity_main, null);
setContentView(view);

 是不是感觉到了一丝丝的奇怪?
 Google作为一个伟大公司,里面的程序员也绝对都是大牛级别的人物,他们对方法的命名是肯定可以起到“见名知意”的作用的。
 那么,问题来了。我们明明是给MainActivity设置activity_main布局,应该使用这样命名的方法setView(view)才会显得更专业呀!
 这里为什么使用的是setContentView(view)呢?
 其实,我们的布局都是被放置在一个FrameLayout的布局中的,由于此处就是给FrameLayout设置内容,那么使用setContentView(view)也就不奇怪了?
 在activity_main.xml中给根据加上id,获取一下它的父亲来看看它到底是什么吧。

protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       requestWindowFeature(Window.FEATURE_NO_TITLE);
       View view = View.inflate(this, R.layout.activity_main, null);
       setContentView(view);

       RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.rl_main);
       ViewParent parent = relativeLayout.getParent();
       System.out.println(parent);
   }

 打印的结果如下:
 
 可以看到,activity_main.xml被转化成为一个View之后,确实放置在FrameLayout中了。看到此处,相信你一定明白了,为什么调用的是setContentView(view)而不是setView()了。
 当然,到目前为止还都是开胃菜!
 应用从启动到页面展示,Android系统都为我们额外做了哪些工作,请继续往下看!

视图树

 为了搞清Android系统都为我们做了哪些额外的工作以及应用的视图树是怎么样的,就需要用到SDK的一个工具了,它放在了SDK目录下:/SDK/tools/hierarchyviewer.bat
 双击打开后,会看到如下的视图,其中黑色显示的是当前手机或者模拟器正在运行的APP。
 
 双击进入黑色条目进入后,会看到下面的视图。这里面就是视图树了。
 
 这个工具可以帮我们显示项目的View层级关系,在代码中由于去除掉了标题栏,所以显得清爽了很多。而绿色被选中的,就是我们R.layout.main布局文件了,右下方红色的代表屏幕上布局文件的区域。
 就如我们上面所说的,Relativilayout布局是被嵌套在一个id为content的FrameLayout中的,这样也可以印证,在onCreate()方法中,为什么设置布局的方法叫做setContetnView(view),而不是setView(view)了。而ViewStub是一个懒加载的空间,不占大小,默认为0,我们也就不用关心了。
 从左侧开始看,当我们选中PhoneWindow$DectorView时,会发现右侧整个APP代表的屏幕空间都会以红色为边框亮起,这样就间接说明了DectorView是根布局了(暂且这么说,其实顶端还有个ViewRoot)。
 
 补充一下,在这个视图中,PhoneWindow$DectoryView这种形式的,$之前是代表着一个类,$之后是代表这个这个类中的一个内部类。
 

源码分析

 了解这些,还远远不够,再进一步看看源码吧。此处,我的源码版本是API22的,使用的IDE是Android Studio。
 点击setContentView(view)方法,看一下内部实现,会发现调用了getWindow()然后调用了其内部的setContentView()方法。

public void setContentView(View view) {
    getWindow().setContentView(view);
    initWindowDecorActionBar();
}

 而getWindow()返回一个mWindow,mWindow是一个Window的变量,我们继续跟进一下,看看一下Widnow的源码,可以发现Window是一个抽象类,setContentView()也是要求子类实现的抽象方法。

public abstract void setContentView(int layoutResID);

 发现Window是一个抽象类,那么肯定会有它的实现类,在AS中,Ctrl+H,会发现Window的默认实现类是PhoneWindow,由于PhoneWindow被Google隐藏了,在Eclipse中,无法直接看到。
 
 找到PhoneWindow中的setContentView()方法,app第一次加载时mContentParent肯定为null,所以会调用installDecor()。走完installDecor()方法后,mContentParent也就有值了(可以推测出mContentParent就是FrameLayout),在第二个★处,使用布局填充器将activity_main.xml转化为View对象,并放置到mContentParent中。

@Override
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        // ★
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                getContext());
        transitionTo(newScene);
    } else {
        // ★
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

 installDecor()是初始化装饰的意思,可以推测出,在这个方法中Android系统为我们做了很多操作,我们跟进一下。这个方法有200多行,此处只给出重要逻辑。

private void installDecor() {
      if (mDecor == null) {
          // ★ 生成装饰
          mDecor = generateDecor();
          mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
          mDecor.setIsRootNamespace(true);
          if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
              mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
          }
      }
      if (mContentParent == null) {
          // ★
          mContentParent = generateLayout(mDecor);

          // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
          mDecor.makeOptionalFitsSystemWindows();

          ......
       }
}

 当首次进入此方法时,mDecor肯定为null,那么必然会进入到generateDecor()方法,见其名知其意,就是生成装饰的意思。继续跟进一下。

protected DecorView generateDecor() {
    return new DecorView(getContext(), -1);
}

 方法很简单,new一个DecorView对象,第一个参数是上下文,那么第二个-1是代表什么呢?打开继承树,可以看到DecorView继承自一个FrameLayout,而FrameLayout是ViewGroup的孩子。
 

 在ViewGroup中可以找到如下信息:

public static final int MATCH_PARENT = -1;
public static final int WRAP_CONTENT = -2;

 传入-1说明,DécorView对象默认填充屏幕,这也与我们在Hierarchy-Viwer中看到的现象一致。拿到mDecor后,继续向下走,由于mContentParent肯定为null,会走到 generateLayout(mDecor);方法中,并将mDecor传入。我们继续跟进,方法的含义是,根据装饰生成布局,源码很长,此处只给出关键一些的。

protected ViewGroup generateLayout(DecorView decor) {
    // Apply data from current theme.
    // 省略若干代码
    ... ... ...

    // Inflate the window decor.

    int layoutResource;
    int features = getLocalFeatures();
    // System.out.println("Features: 0x" + Integer.toHexString(features));
    if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
        layoutResource = R.layout.screen_swipe_dismiss;
    } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
        if (mIsFloating) {
            TypedValue res = new TypedValue();
            getContext().getTheme().resolveAttribute(
                    R.attr.dialogTitleIconsDecorLayout, res, true);
            layoutResource = res.resourceId;
        } else {
            layoutResource = R.layout.screen_title_icons;
        }
        // XXX Remove this once action bar supports these features.
        removeFeature(FEATURE_ACTION_BAR);
        // System.out.println("Title Icons!");
    } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
            && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
        // Special case for a window with only a progress bar (and title).
        // XXX Need to have a no-title version of embedded windows.
        layoutResource = R.layout.screen_progress;
        // System.out.println("Progress!");
    } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
        // Special case for a window with a custom title.
        // If the window is floating, we need a dialog layout
        if (mIsFloating) {
            TypedValue res = new TypedValue();
            getContext().getTheme().resolveAttribute(
                    R.attr.dialogCustomTitleDecorLayout, res, true);
            layoutResource = res.resourceId;
        } else {
            layoutResource = R.layout.screen_custom_title;
        }
        // XXX Remove this once action bar supports these features.
        removeFeature(FEATURE_ACTION_BAR);
    } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
        // If no other features and not embedded, only need a title.
        // If the window is floating, we need a dialog layout
        if (mIsFloating) {
            TypedValue res = new TypedValue();
            getContext().getTheme().resolveAttribute(
                    R.attr.dialogTitleDecorLayout, res, true);
            layoutResource = res.resourceId;
        } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {

            layoutResource = a.getResourceId(
                    R.styleable.Window_windowActionBarFullscreenDecorLayout,
                    R.layout.screen_action_bar);
        } else {
            // ★★★★★
            layoutResource = R.layout.screen_title;
        }
        // System.out.println("Title!");
    } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
        layoutResource = R.layout.screen_simple_overlay_action_mode;
    } else {
        // Embedded, so no decoration is needed.
        layoutResource = R.layout.screen_simple;
        // System.out.println("Simple!");
    }

    mDecor.startChanging();

    View in = mLayoutInflater.inflate(layoutResource, null);
    decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    mContentRoot = (ViewGroup) in;

    // 省略若干代码
    ... ... 
    return contentParent;
}

 我们在之前使用了requestWindowFeature(Window.FEATURE_NO_TITLE);给窗体设置了一个装饰,我们直接来到关键的代码处。在此处会不断的判断features到底是什么东西,经过一堆判断后,会达到上面代码中★★★★★处。

if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
     ... ...
     // ★★★★★
     layoutResource = R.layout.screen_title;
}

 这样走到这个if中,并得到一个layoutResource,它其实就是一个XML的布局,我们接着看一下R.layout.screen_title是什么样的布局。
 R.layout.screen_title内容如下,一个LinearLayout中包含着两个FragmenLayout和一个ViewStub,由于我们设置了没有Title,那么第二个FrameLayout就不会显示出来,第三个就是我们id=content的帧布局。看到此处,是不是渐渐有些清晰了?

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:fitsSystemWindows="true">
    <!-- Popout bar for action modes -->
    <ViewStub android:id="@+id/action_mode_bar_stub"
              android:inflatedId="@+id/action_mode_bar"
              android:layout="@layout/action_mode_bar"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:theme="?attr/actionBarTheme" />
    <FrameLayout
        android:layout_width="match_parent" 
        android:layout_height="?android:attr/windowTitleSize"
        style="?android:attr/windowTitleBackgroundStyle">
        <TextView android:id="@android:id/title" 
            style="?android:attr/windowTitleStyle"
            android:background="@null"
            android:fadingEdge="horizontal"
            android:gravity="center_vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
    <FrameLayout android:id="@android:id/content"
        android:layout_width="match_parent" 
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foregroundGravity="fill_horizontal|top"
        android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

 在generateLayout(DecorView decor)方法的如下代码中,将screen_titlle.xml文件转化成的View对象添加到了decor中,也就是PhoneWindow$DecorView中。

View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;

 最后,再回到PhoneWindow的setContentView(resId)方法中,在378行通过mLayoutInflater.inflate(layoutResID, mContentParent);将我们自己的布局文件,放置到mContentParent中。
至此,整个View界面的挂载与显示就结束了。

 如果感觉,本篇博客讲的对你还有益处,请多多留言;如果讲的有误,也请多多拍砖,谢谢大家了!!!

没有更多推荐了,返回首页