最全面的android入门知识,请好好收藏

Android一款基于Linux的开放源代码的操作系统,主要用于移动设备,现在许多公司都会基于Android做各种定制开发工作。所以,在开发工作之前,需要全面熟悉了解Android的基础知识,有了基础入门知识之后,才能做好方案设计,并且利于以后更加深入的学习发展。

古人说,工欲善其事,必先利其器,所以,本文首先会介绍环境搭建流程,再简单介绍android的系统架构,接着实现第一个程序Hello World!, 让新手对android在视觉上有个比较清晰的概念。然后再介绍程序的目录功能。紧接着就是本文的重头戏,分别介绍布局管理器、android的重要程序组件、Activity的生命周期、Service的生命周期、BroadcastRecevier的应用,Intent的应用。最后再扩展的知识点,包括分辨率问题、应用程序签名。

一、环境搭建

  • 安装JDK7

  • 下载Eclipse(eclipse-jee-kepler-SR1-win32),Eclipse不需要安装, 下载解压后即可使用
  • 安装ADT扩充套件, 双击eclipse.exe,点击help -> install new software -> Add -> 在Location处输入网址:http://dl-ssl.google.com/android/eclipse/site.xml

  • 下载android SDK, 解压SDK,设定SDK: window -> preferences -> android -> 在SDK Location选择SDK路径

  • 安装mysql
  • 安装tomcat,修改默认端口号为8010,数据库驱动(mysql-connector-java-5.1.13-bin.jar ,用于tomcat和mysql之间的连接)放到目录..\Apache Software Foundation\Tomcat 8.0\lib下

修改文件tomcat-users.xml

  • 设置环境变量,计算机->右键属性—>环境变量->修改变量,进行如下设置

如果想要测试效果,那么在cmd下输入以下命令 java,javac,java-version

  • 上面搭建的环境,只是在本机上,如果开发的程序涉及到服务器端,并且需要将程序推荐给别人使用,就需要购买空间和域名(当然,现在也有免费的空间,但是受到限制,无法商用)

二、 系统架构

Android平台是基于Linux内核。上图是其系统架构。大致可以分为四层。从下到上为:

  1. Linux内核层: 包含了Linux内核和一些驱动模块(比如蓝牙驱动,USB驱动等)
  2. Libraries层: 提供动态库, Android运行时库,Dalvik虚拟机等。这一层大部分都是用C或者C++编写,也可以称为Native层(init、Audio系统、Surface系统)
  3. Framework层: 大部分用Java语言编写。是Android平台的基石。(zygote、system server等)
  4. Application层:与用户之间交互。都是用Java开发。(MediaProvider等)

Java世界与Native世界的关系

  1. JAVA通过JNI层调用Linux的系统调用来完成对应的功能
  2. JAVA世界经过JNI层通过IPC方式与Native世界交互。而IPC方法就是是Binder。
  3. JNI是Java Native Interface的是缩写, 即“Java本地调用”。简单来说,java程序中的函数可以调用Native写的函数。Native程序中的函数可以调用Java层的函数。

三、开始第一个程序

  1. 双击Eclipse, 启动Eclipse
  2. 选择File -> New -> Project, 在打开的对话框中,选择Android -> Android Application Project

  1. 程序创建完成,我们来看看效果,首先利用android 提供虚拟设备管理,创建虚拟机,并运行
  2. 右键工程, Debug as -> Android Application, 运行效果如下
  3. (如果工程暂时不要,可以选择工程,右键“Close Porject,可以提高打开esclipse的速度,当工程多的时候,这个效果特别明显)

    四、程序目录介绍

    总体目录

目录及文件 说明
Src 代码目录,代码编写、功能实现的地方
Assets 存放资源文件,例如歌曲等
Bin 存放编译生成的二进制文件
Libs
Res 布局文件
AndroidManifest.xml 关键配置文件,包括组件的声明,版本的定义,权限的声明等

代码文件说明

程序启动的时候,会调用onCreatesetContentView,进行界面的初始化,后面会详细说明activity的生命周期。onCreateOptionMenuonOptionsItemSelected是选项菜单的实现。

布局文件说明

Android提供了一组View类,用作视图的容器。每个布局实现管理器子布局的大小和位置的特定策略。

布局管理器 说明
LinearLayout 以水平或者垂直的方式组织其子控件
FrameLayout 显示单一帧
TableLayout 以行和列的方式组织其子控件
AbsoluteLayout 绝对布局,兼容性不好,不建议使用
RelativeLayout 相对布局,容器中的控件相

 

Android中,控件通常是在layout目录下定义,但是代码中如何使用呢? 这里先解释下两个定义的不同

“@+”表示新声明, “@”表示引用,例如:

“@+id/tv” 表示新声明一个id, 是id名为tv的组件

“@id/tv” 表示引用id名为tv的组件,比较常用于布局

定义编辑框
<EditText
android:id="@+id/search_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="@string/search_example" />
 
代码中引用:
private EditText text_search;          
text_search = (EditText) findViewById(R.id.search_bar);

AndroidManifest文件说明

<application></application>是进行组件的声明,例如activity, service, brocadcast等注意,如果涉及到网络的交互,要在该文件中加入如下权限:

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

六、 布局管理器

LinearLayout线性布局

线性布局是最常用的一种。此布局会保持组件之间的间隔以及组件之间互相对齐。显示组件的方式有垂直于水平两种,可以通过orientation进行设定。

垂直方式:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal"
     >
    <Button
        android:layout_width="fill_parent"
        android:layout_height = "wrap_content"
        android:text = "Button1"></Button>
    <Button
        android:layout_width="fill_parent"
        android:layout_height = "wrap_content"
        android:text = "Button2"></Button>  
    <Button
        android:layout_width="fill_parent"
        android:layout_height = "wrap_content"
        android:text = "Button2"></Button>          
</LinearLayout>

水平方式:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal"
     >
    <Button
        android:layout_width="wrap_content"
        android:layout_height = "wrap_content"
        android:text = "Button1"></Button>
    <Button
        android:layout_width="wrap_content"
        android:layout_height = "wrap_content"
        android:text = "Button2"></Button>  
    <Button
        android:layout_width="wrap_content"
        android:layout_height = "wrap_content"
        android:text = "Button2"></Button>          
</LinearLayout>

FrameLayout单帧布局

单帧布局新定义的组件永远放在屏幕的左上角,后一个组件总会将前一个组件覆盖

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
     >
    <Button
        android:layout_width="fill_parent"
        android:layout_height = "wrap_content"
        android:text = "Button1"></Button>
    <Button
        android:layout_width="wrap_content"
        android:layout_height = "fill_parent"
        android:text = "Button2"></Button>  
    <Button
        android:layout_width="wrap_content"
        android:layout_height = "wrap_content"
        android:text = "Button3"></Button>          
</FrameLayout>

TableLayout表格布局

表格布局就像一个表格。由TableRow组成,每个TableRow代表一行。

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
     >
     <TableRow>
        <Button android:text = "Button1"></Button>
        <Button android:text = "Button2"></Button>
        <Button android:text = "Button3"></Button>             
     </TableRow>
 
     <TableRow>
        <Button android:text = "Button4"></Button>
        <Button android:text = "Button5"></Button>
        <Button android:text = "Button6"></Button>             
     </TableRow>   
 
     <TableRow>
        <Button android:text = "Button7"></Button>
        <Button android:text = "Button8"></Button>
        <Button android:text = "Button9"></Button>             
     </TableRow>            
</TableLayout>

AbsoluteLayout绝对布局

绝对布局,组件的位置可以准确指定在屏幕的x/y坐标。但是这种布局兼容性不好。

<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
     >
    <Button
        android:layout_width="wrap_content"
        android:layout_height = "fill_parent"
        android:text = "Button1"
        android:layout_x="100dp"></Button>
    <Button
        android:layout_width="fill_parent"
        android:layout_height = "wrap_content"
        android:text = "Button2"
        android:layout_y="100dp"></Button>   
</AbsoluteLayout>

RelativeLayout相对布局

相对布局,是一种比较常用的比较,每个组件都可以指定相对于其他组件或者父组件的位置(通过ID来指定)。一个组件的位置,至少要确定组件“左右”与“上下”两个位置才可以准确确定组件位置

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text = "Button1"
        android:id="@+id/btn1"></Button>
    <Button
        android:layout_width="fill_parent"
        android:layout_height = "wrap_content"
        android:text = "Button2"
        android:id="@+id/btn2"
        android:layout_below="@id/btn1"></Button>
    <Button
        android:layout_width="wrap_content"
        android:layout_height = "wrap_content"
        android:text = "Button3"
        android:id="@+id/btn3"
        android:layout_below="@id/btn2"
        android:layout_alignRight="@id/btn2"></Button>  
    <Button
        android:layout_width="wrap_content"
        android:layout_height = "wrap_content"
        android:text = "Button4"
        android:id="@+id/btn4"
        android:layout_below="@id/btn3"
        android:layout_alignParentRight="true"></Button>
    <Button
        android:layout_width="wrap_content"
        android:layout_height = "wrap_content"
        android:text = "Button5"
        android:id="@+id/btn5"
        android:layout_below="@id/btn4"
        android:layout_centerHorizontal="true"></Button>
</RelativeLayout>

七、程序组件简介

Activity简介

  • 应用程序中的每个屏幕显示都通过几次和扩展基类Activity来实现
  • Activity利用View来实现应用程序的GUI。应用程序通过GUI向用户显示信息,用户通过GUI向应用程序发出指令和响应

    Service简介

  • Service是具有一段较长生命周期且没有用户界面的程序
  • Service继承自android.app.Service类
  • Service不能自己启动
  • 启动和关闭Service的流程
StartService()启动service
stopService() 关闭service
stopSelf() service自身调用关闭
bindservice() 将context对象(如activity)绑定到指定的service
这样的话,context对象消亡,service也会停止运行

BroadcastReceiver简介

  • BroadcastReceiver是用户接受广播通知的组件
  • BroadcastReceiver是对发送出来的Broadcast进行过滤接收并响应的一类组件
  • 如果想要接受到广播,首先要注册BroadcastReceiver,注册的方式有两种,一种是静态的在AndroidManifest.xml中用<receiver>标签声明注册,并设置过滤器。另一种方式,动态的设置一个IntentFilter对象,然后在需要注册的地方调用registerReceiver,取消注册的地方调用unregisterReceiver方法。
  • 如何发生广播呢?首次,在要发送信息的地方,封装一个Intent对象,然后调用sendBroadcast方法吧Intetn对象以广播的形式发送出去。这样的话,所有已经注册的BroadcastReceiver会检查注册时的IntentFilter是否与发送的Intent向匹配,如果匹配则调用onRecevie方。

    ContentProvider简介

    ContentProvider能将应用程序特定的数据提供给另一个应用程序使用。

    Intent连接组件的纽带

    Intent是一种运行时绑定机制,它能在程序运行的过程中连接两个不同的组件

    Intent的主要组成部分:

组成 描述
组件名称 Intent目标组件的名称
Action(动作) Intent所触发动作名字的字符串
Data(数据) 描述Intent要操作的数据URI和数据类型
Category(类别) 对被请求组件的额外描述信息
Extra(附加信息) 附加额外信息

八、Activity的生命周期

Activity生命周期的七个函数:

函数 说明
onCreate Activity初次创建时被调用,一般在这里创建view, 初始化布局,设置监听器。如果Activity首次调用,那么其后会调用onStart,

如果Activity是停止后重新刷新,那么其后调用onRestart()

onStart() 当Activity对用户即将可见时被调用,其后调用onResume()
onRestart() 当Activity停止后重新显示被调用,其后调用onStart()
onResume() 当用户能在界面中进行操作的时候调用
onPause() 当系统要启动一个其他的Activity时调用,这个方法被用来停止动画和其他占用CPU资源的事情
onStop() 当另一个Activity恢复并遮盖住当前Activity,导致其对用户不再可见时调用
onDestory() 当前的Activity被销毁前所调用的最后一个方法,或者进程终止时调用

为了详细说明生命周期的变化,创建“MyFirstProject”的项目,添加两个类“MainActivity.java”和“OtherActivity.java”,这两个类都继承Activity,并实现了上面的七 函数,在每个生命周期函数中添加了一个Log打印语句,方便观察周期变化。MainActivity添加了一个按钮,用于跳转到OtherActivity

MainActivity.java关键代码
public class MainActivity extends Activity implements OnClickListener {
    private Button btn;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Log.v("MainActivity", "onCreate");
        btn = (Button) findViewById(R.id.Main_btn);
        btn.setOnClickListener(this);
    }
 
    @Override
    public void onClick(View arg0) {
        if (arg0 == btn) {
            Intent intent = new Intent();
            intent.setClass(this, OtherActivity.class);
            this.startActivity(intent);
        }
    }
 
    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        Log.v("MainActivity", "onDestroy");
    }
 
    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        Log.v("MainActivity", "onPause");
    }
 
    @Override
    protected void onRestart() {
        // TODO Auto-generated method stub
        super.onRestart();
        Log.v("MainActivity", "onRestart");
    }
 
    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        Log.v("MainActivity", "onResume");
    }
 
    @Override
    protected void onStart() {
        // TODO Auto-generated method stub
        super.onStart();
        Log.v("MainActivity", "onStart");
    }
 
    @Override
    protected void onStop() {
        // TODO Auto-generated method stub
        super.onStop();
        Log.v("MainActivity", "onStop");
    }
 
}
OtherActivity.java 关键代码
public class OtherActivity extends Activity implements OnClickListener {
    private Button btn;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.other);
        Log.v("OtherActivity", "onCreate");
        btn = (Button) findViewById(R.id.Other_btn);
        btn.setOnClickListener(this);
    }
 
    @Override
    public void onClick(View arg0) {
        if (arg0 == btn) {
            this.finish();
        }
    }
 
    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        Log.v("OtherActivity", "onDestroy");
    }
 
    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        Log.v("OtherActivity", "onPause");
    }
 
    @Override
    protected void onRestart() {
        // TODO Auto-generated method stub
        super.onRestart();
        Log.v("OtherActivity", "onRestart");
    }
 
    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        Log.v("OtherActivity", "onResume");
    }
 
    @Override
    protected void onStart() {
        // TODO Auto-generated method stub
        super.onStart();
        Log.v("OtherActivity", "onStart");
    }
 
    @Override
    protected void onStop() {
        // TODO Auto-generated method stub
        super.onStop();
        Log.v("OtherActivity", "onStop");
    }
 
}

 效果图如下所示

1)首次启动项目,进入MainActivity

02-16 08:35:49.673: V/MainActivity(1303): onCreate
02-16 08:35:49.673: V/MainActivity(1303): onStart
02-16 08:35:49.693: V/MainActivity(1303): onResume

2)按下手机上的“Back”键

02-16 08:40:21.593: V/MainActivity(1303): onPause
02-16 08:40:24.413: V/MainActivity(1303): onStop
02-16 08:40:24.413: V/MainActivity(1303): onDestroy

3)重新打开程序,单击手机上的Home

02-16 08:42:55.133: V/MainActivity(1303): onPause
02-16 08:43:03.983: V/MainActivity(1303): onStop

4)单击程序图标

02-16 08:44:21.963: V/MainActivity(1303): onRestart
02-16 08:44:21.963: V/MainActivity(1303): onStart
02-16 08:44:21.973: V/MainActivity(1303): onResume

上面的情况是单个Activity的时候,下面讲述两个Activity的情况

(1)打开OtherActivity

02-16 08:47:38.743: V/MainActivity(1303): onPause
02-16 08:47:41.423: V/OtherActivity(1303): onCreate
02-16 08:47:41.473: V/OtherActivity(1303): onStart
02-16 08:47:41.473: V/OtherActivity(1303): onResume
02-16 08:47:43.833: V/MainActivity(1303): onStop

2)在OtherActivity,按下“Back”按钮或者按下“关闭当前Activity”按钮

02-16 08:51:22.223: V/OtherActivity(1303): onPause
02-16 08:51:22.583: V/MainActivity(1303): onRestart
02-16 08:51:22.583: V/MainActivity(1303): onStart
02-16 08:51:22.593: V/MainActivity(1303): onResume
02-16 08:51:24.493: V/OtherActivity(1303): onStop
02-16 08:51:24.493: V/OtherActivity(1303): onDestroy

OtherActivity的主题风格,设置成对话框的形式,效果图如下所示

1)打开OtherActivity

02-16 09:04:23.103: V/MainActivity(1390): onPause
02-16 09:04:23.743: V/OtherActivity(1390): onCreate
02-16 09:04:23.743: V/OtherActivity(1390): onStart
02-16 09:04:23.753: V/OtherActivity(1390): onResume

从上面可以看出,如果新打开的Activity不能完全覆盖前面的Activity,  那么前面的Activity就不会调用onStop这个生命周期。

九、Service的生命周期

下面通过创建项目,在service的各个状态回调方法中加入log信息,了解其生命周期

  • 首先创建service类
public class SampleService extends Service {
    final String TAG = "Service";
    
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        return null;
    }
    @Override
    public boolean onUnbind (Intent intent) {
        Log.d(TAG, "onUnbind");
        return super.onUnbind(intent);
    }
    @Override
    public void onRebind (Intent intent) {
        super.onRebind(intent);
        Log.d(TAG, "onRebind");
    }
    @Override
    public void onCreate () {
        super.onCreate();
        Log.d(TAG, "onCreate");
    }
    @Override
    public void onDestroy () {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }
    @Override
    public void onStart (Intent intent, int startId) {
        super.onStart(intent, startId);
        Log.d(TAG, "onStart");
    }
}
  •   Activity设置监听按钮
public class MainActivitySampleService extends Activity {
    OnClickListener listener;
    ServiceConnection connection;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ch6ex1);
        // 定义ServiceConnection对象,用于绑定Service
        connection = new ServiceConnection(){
            @Override
            public void onServiceConnected(ComponentName arg0, IBinder arg1) {
            }
            @Override
            public void onServiceDisconnected(ComponentName arg0) {
            }
        };
        /*定义Button的点击监听器*/
        listener = new OnClickListener(){
            @Override
            public void onClick(View v) {
                Intent i = new Intent(MainActivitySampleService.this,SampleService.class);
                switch (v.getId()) {
                case R.id.startService:
                    startService(i);
                    break;
                case R.id.stopService:
                    stopService(i);
                    break;
                case R.id.bindService:
                    bindService(i, connection, BIND_AUTO_CREATE);
                    break;
                case R.id.unbindService:
                    unbindService(connection);
                    break;
                default:
                    break;
                }
            }
        };
        /*设置点击监听器*/
     findViewById(R.id.startService).setOnClickListener(listener);
        findViewById(R.id.stopService).setOnClickListener(listener);
        findViewById(R.id.bindService).setOnClickListener(listener);
        findViewById(R.id.unbindService).setOnClickListener(listener);
    } 
}

  • 按下四个按钮的流程信息
StartService:
03-29 14:46:33.801: D/Service(17346): onCreate
03-29 14:46:33.802: D/Service(17346): onStart
 
stopService:
03-29 14:47:31.801: D/Service(17346): onDestroy
 
bindService:
03-29 14:48:13.689: D/Service(17346): onCreate
03-29 14:48:13.713: D/Service(17346): onBind
 
unbindService:
03-29 14:48:41.871: D/Service(17346): onUnbind
03-29 14:48:41.871: D/Service(17346): onDestroy

十、BroadcastRecevier的应用

下面通过一个简单的例子来说明,如何处理广播消息。利用android系统启动完毕时,会发送一个action为ACTION_BOOT_COMPLETED的Intent,来实现开机自启动服务。

  • 首次,为了能够接收广播,需要在AndroidManifest.xml中,加入权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  • 然后创建类MyBootRecevier并在onReceiver方法中启动服务
public class MyBootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent i = new Intent(context,SampleService.class);
        context.startService(i);
    }
}
  • 最后,采用静态注册的方法注册MyBootReceiver
<receiver android:name=".MyBootReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

十一、 Intent的应用

1、 利用intent在两个Activity之间传递数据

首先,创建intent, bundle对象,bundle存入数据,并通过intent将数据传递给RoutePlanActivity
        Int iLatitude = 10;
        Int iLongtitude = 20;
        Intent intent = new Intent();
        Bundle bundle = new Bundle();
        bundle.putInt("latitude", iLatitude);
        bundle.putInt("longtitude", iLongtitude);
        intent.putExtras(bundle);      
        intent.setClass(MainContentHuntSheActivity.this, RoutePlanActivity.class);
        startActivity(intent); 
 
RoutePlanActivity接收到消息,进行如下处理
Bundle myBundle = this.getIntent().getExtras();
int iLatitude   = myBundle.getInt("latitude");
int iLongtitude = myBundle.getInt("longtitude");

2、 通过intent,实现信息分享

// 分享短串结果
 Intent it = new Intent(Intent.ACTION_SEND);
   
 String str = "冬日暖曲,一款时尚音乐软件,界面简洁实用哦!";
 it.putExtra(Intent.EXTRA_TEXT, str);
 it.setType("text/plain");
 ((Activity)mainActionView.getContext()).startActivity(Intent.createChooser(it, "将短串分享到"));

十二、分辨率问题

Android资源文件中,各个文件存放的分辨率

目录 说明
drawable-ldpi 240×320
drawable-ldpi 320×480
drawable-hdpi 480×800、480×854
drawable-xhdpi 至少960*720
drawable-xxhdpi 1280×720

长度单位dp、sp和px的区别

  • dp也就是dip,这个和sp基本类似。

如果设置表示长度、高度等属性时可以使用dp或sp。但如果设置字体,需要使用sp。

  • dp是与密度无关,sp除了与密度无关外,还与scale无关。如果屏幕密度为160,这时dp和sp和px是一样的。
1dp=1sp=1px,但如果使用px作单位,如果屏幕大小不变(假设还是3.2寸),而屏幕密度变成了320。那么原来TextView的宽度设成160px,在密度为320的3.2寸屏幕里看要比在密度为160的3.2寸屏幕上看短了一半。
但如果设置成160dp或160sp的话。系统会自动将width属性值设置成320px的。也就是160 * 320 / 160。其中320 / 160可称为密度比例因子。
  • 如果使用dp和sp,系统会根据屏幕密度的变化自动进行转换

十三、应用程序签名

Android应用程序要发布,并被别人使用,需要进行签名,下面将说明如何进行签名

  • 生产私钥,Android的SDK中,有个工具keytool.exe,专门用来生产私钥。打开cmd, 进入工具keytool.exe的所在目录,执行以下命令,那么,在当前目录就会生成文件test.keystore
keytool -genkey -dname "CN=Zijun Li,OU=Zijun Li,O=Zijun Li,L=shenzhen,S=guangdong,C=0086" -storepass 密码 -keystore test.keystore -keyalg RSA -keypass 密码 -validity 15000
  • 然后在eclipse中,选中项目,右击鼠标,选择Android Tools ->Export Unsigned Application Package…,然后,按照提示执行,最后导出的apk,即为签名的apk,可以提供给别人使用或者上传应用商店

十四、推荐学习

  • 通过android SDK中的api demo进行学习
  • 反编译别人的apk,学习别人的代码,目前有两种方法(方法一,dex2jar和jd-gui; 方法二,apktool)