1.新创建的android工程下的res/layout 目录下的xml文件为配置整个界面布局,而res/values/strings.xml 文件是指定了一些字符串的,可用于在界面上显示。这带来一个好处,我们可以这样为不同语言设置一个stringsxml文件,如中文,英文版。这样界面上所显示的内容根据不同的strings.xml 就可以动态的变换,也就是实现了本地化。
2.在res/layout/testmain.xml文件中引用strings.xml文件内容的方法:<Button android:text="@string/button_send">
<1> @代表了引用strings.xml文件中的字符串
<2> string代表引用资源的类型
<3> / 作为一个分隔字符串的名字
<4> 字符串的名字(相当于变量名字)
相应的在strings.xml中一定有一行:<string name="button_send">sendmymessage</string>
sendmymessage 这个就是button_send这个变量的内容
3.在layout下的xml文件中可以使用的控件:
<1> <EditText ..../>
<2> <Button ... />
<3> <TextView .../>
4. 从A activity启动一个B activity.
<1> startActivity(intent)
可以让参数intent携带数据,从A 传送到 B。方法:intetnt.putExtra(....);
<2>startActivityForResult()
这个函数不仅可以从A activity启动B avtivity 并且从A传送数据到B ,还可以从B返回数据到A。
当A启动了B,B完成了自己的事情返回时,系统会调用A中的函数:
protected void onActivityResult( int requestCode, int resultCode , Intent data);
其中requestCode是startActivityForResult()的参数传入的。
resultCode是有B activity设置的。
data是从B返回到A的数据。
5.Back stack
当从A activity 启动 B activity ,这时会将A停止,然后将A放入到“back stack”中,这个栈遵循“后进,先出”的顺序。当从B返回时,这时执行弹栈操作,将A从“back stack”弹出,显示给用户。
6.<intent-filter>
<activity> 下的 <intent-filter>的作用是为了让别的app使用隐式的intent来调用我们的activity,只要满足了该activity的 <intent-filter>条件.
7.activity分为两类,一类是显式的,一类是隐式的。
<1> 显式的启动
//Intent的第一个参数指定的是:源activity对应的类。 第二个参数指定的是:目的(启动)activity对应的类。 Intent intent = new Intent(this, SignInActivity.class); //启动 startActivity(intent);
<2>隐式的启动
作用:当我们的应用程序没有实现某些功能,比如照相,我们可以调用照相程序拍摄一张照片,在将照片数据返回到我们的应用程序使用。我们创建一个intent,指定我们需要的action,然后系统替我们需找合适的activity来启动它,如果有多个activity适用,会让我们去选择使用哪一个.
代码(发送email):
//指明了action的类型为ACTION_SEND Intent intent = new Intent(Intent.ACTION_SEND); //让intent去携带了email的地址信息,让recipientArray储存地址。 intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); startActivity(intent);
8.activity的生命周期
activity的生命周期就是不同状态的变换,对于每一种状态都有对应的回调函数可以供我们重写,来做出相应的控制。
如下:
public class ExampleActivity extends Activity { @Override public voidonCreate
(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // The activity is being created. } @Override protected voidonStart()
{ super.onStart(); // The activity is about to become visible. } @Override protected voidonResume()
{ super.onResume(); // The activity has become visible (it is now "resumed"). } @Override protected voidonPause()
{ super.onPause(); // Another activity is taking focus (this activity is about to be "paused"). } @Override protected voidonStop()
{ super.onStop(); // The activity is no longer visible (it is now "stopped") } @Override protected voidonDestroy()
{ super.onDestroy(); // The activity is about to be destroyed. } }
注:你实现上面的这些生命周期的方法之前必须调用它们 父类 的相同方法,如上所示。
<1>OnCreate()
当activity第一次创建时,会调用此方法。其中是activity进行初始化的地方,分配资源什么的。注意:一定在这里调用 setContentView() 来设置activity的布局。
<2>OnStart()
当activity对于用户可见时,会调用此方法。
<3>OnRestart()
当activity已经被停止的时候。
<4>OnResume()
在activity开始于用户交互之前调用。这时,activity处于栈的顶端,伴随着用户的输入即将到达。
<5>OnPause()
在系统正要唤醒其他activityde的时候。
<6>OnStop()
当activity已经对于用户不可见的时候调用该函数。
<7>OnDestory()
当
9.隐式activity
<1>Intent的Action, Category 属性都是一个普通的字符串。
<2>每个intent都只能指定一个Action , 一个Category 属性。
<3>而对于AndroidManifest.xml中的Activity 配置下的<activity.../>的子元素<intent-filter.../>中可以指定多个Action,Category属性。
<4>匹配规则,只要intent中的Action和Category属性满足了<intent-filter.../>其中的一条Action和一条Category属性(两个属性同时满足),那么该activity就作为备选
可以被启动.
<5>intent默认的Category属性是:android.intent.category.DEFAULT. 设置category的函数: intent.addCategory(...)
<6>intent没有默认的Action. 设置action函数: intent.setAction(..)
<7>例子
public final static String TEST_ACTION = "com.example.test.TEST_ACTION";
......
Intent intent = new Intent();
intent.setAction(TEST_ACTION);
startActivity(intent);
......
<activity android:name=".SecondActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="com.example.test.TEST_ACTION"/>
<action andriod:name="com.example.test.HELLO_WORLD"/>
<category android:name="android.intent.category.DEFAULT"/>
<catrgory android:name="android.intent.catrgory.LAUNCHER"/>
</intent-fileter>
</activity>
解释:可以看到在<intent-fileter>中有多条actionhe category,只要各满足一条就可以启动该SecondActivity了。
10.引用资源
java的资源放在assets和res目录下,对于放在res目录下的资源,编译器会生成一个R类作为索引项用于代表其中的资源。
<1>java代码中引用资源
格式:R.资源类型.资源名字
例子:R.id.msg R.string.app_name R.layout.main_layout
<2>xml文件中引用资源
格式:@资源类型/资源名字
例子:@id/msg @string/app_name
11.activity的生命期测试
情形:共有两个activity:A 和 B ,A是入口activity并且重载了:
OnCreate() . onStart() . onRestart() . onResume() . onPause() . onStop() . onDestroy()
输出调用函数:
<1>启动应用
OnCreate()
onStart()
onResume()
<2>从 A 启动 B
onPause()
onStop()
<3>从B 返回到 A
onRestart()
onStart()
onResume()
<4>从A 返回到主界面
onPause()
onStop()
<5>找到应用再次启动
onRestart()
onStart()
onResume()
<6>调用finishi()结束程序
onPause()
onStop()
onDestroy()
<7>直接从任务管理器结束程序
onDestroy()
12.安装应用程序在外存或者内存
在<manifest>元素下添加:android:installLocation;
<pre class="prettyprint"><span class="tag"><manifest</span><span class="pln"> </span><span class="atn">xmlns:android</span><span class="pun">=</span><span class="atv">"http://schemas.android.com/apk/res/android"</span><span class="pln">
</span><span class="atn">android:installLocation</span><span class="pun">=</span><span class="atv">"preferExternal"</span><span class="pln">
... </span><span class="tag">></span>
它的值可以是:
<1>preferExternal
让系统安装应用在外存,但是当外存空间满了之后,就将安装在内存中。
<2>auto
让系统自己决定安装应用的位置
13. Android的Task和activity
<1>Task
(1)每一个应用程序是一个Task,我们可以在Task之间进行切换,一个Task中包含多个activity.
(2)当从A task切换到B task时,A被切换到后台并失去焦点,B被切换到前台获得焦点;且A中的back stack所有activity都会被暂停,B中处于back stack顶部的activity被唤醒,显示给用户进行交互。
(3)每个task都拥有自己的back stack
<2>activity
(1)activity被放在back stack中。
(2)back stack遵循先进后出的原则。且其中的activity的顺序不会再改变,只能操作弹出与压入,不会有处于中间的2个activity互换位置。
(3)处于back stack顶部的activity才会显示给用户交互
(4)从A activity启动 B activity ,然后B acitity 启动 C activity。此时back stack中是:A处于最低部,B处于中间,C处于顶端。 这时从C 返回到 B,C被销毁释放掉,B从stack中弹出到顶端,显示给用户。
(5)A 切换到 B,A的各种状态将被保存下来不会丢失掉。
(6) 如果我们可以从B 和 C 都可以启动A,那么就有一种情况值得注意。列子,back stack中是(从底部到顶部):A,B,C。 此时因为我们可以从C启动A,那么这时会发生什么呢?两种情况考虑:
情况一:会将最底部的A放到最顶端。(注意:此条违反了back stack中的activity顺序不会改变原则)
情况二:此时重新生成一个A的新实例放在back stack的顶端。
所以,正确的情况是:情况二。此时就存在了2个A的实例,但是我们可限制产生多个实例,具体请看官网文档。
14.保存Activity的状态
情形:当我们从A activity启动到 B activity 。此时系统默认会为我们保存A的状态,但是当内存不足的时候,系统会完全的销毁掉A。然后我们从B返回到A时(虽然A已经被销毁掉,但back stack中任然有A的记录),此时系统会重新创建一个A acitivty,先前的状态也自然而然的丢失了,所以我们就要自己保存A的状态。
处理:在onSaveInstanceState()回调方法中。
15.控件的事件传递流程
<1>当某组件所发生的事情不仅可以激发该组件的回调方法,而且会触发该组件所在的Activity的回调方法。(前提:该事件要能传播到该Activity)
<2>回调事件的处理方法几乎都有一个boolean类型的返回值,该返回值用于标示该事件能否进行传播。
返回true: 表示该事件不能再传播
返回false: 表示该事件可以进行传播
<3>当我们重写了:(1)控件的监听事件 (2)控件的回调函数 (3)控件所在activity的回调函数
这时调用的顺序是(前提事件可以进行传播,即这是三个函数都返回false):(1)-> (2)-> (3)
16.线程进行通讯
<1>原因:因为只有UI线程才能操作界面上的元素。所以我们自己创建的线程想要操作界面,就必须将相关数据传送给UI线程。
<2>通讯的工具:使用Handler作为载体,发送和接受消息。它发送的消息会放在MessageQueue队列中。
<3>通讯前提:拥有MessageQueue, 并且拥有MessageQueue的前提是有Looper对象,Looper对象对MessageQueue中的消息进行管理。
(1)主UI线程已经初始化了一个Looper对象,所以直接可以用Handler
(2)新创建的线程是没有Looper对象的,所以我们必须自己创建。
<4>通讯流程
(1)调用Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会创建配套的MeesageQueue.
(2)有了Looper. 创建Handler子类的实例,重写handleMeesage()方法,该方法负责处理来自其他线程的消息。
(3)调用Looer的loop()方法来启动Looper.
<5>例子:
public class MainActivity extends ActionBarActivity{
public Handler mUiHandler;
class CalcThread extends Thread{
public Handler mCalcHandler;
public void run(){
Looper.prepare()
mCalcHandler = new Handler(){
public void handleMessage(Message msg){
super.handleMeesage(msg);
//在新线程这里处理具体的操作,处理完成后可以通过Handler的sendMessage()发送消息
if(msg.what == 0x123){
......
mUIHandler.sendMessage(...);
}
}
};
Looper.loop();
}
}
public void onCreate(Bundle savedInstanceState){
.....
//调用CalcThread线程中的mCalcHandler发送消息
mCalcThread.mCalcHandler.sendMessage(msg);
mUiHandler = new Handler(){
public void handleMeesage(Meesage msg){
类似处理
}
};
<pre name="code" class="java"> mCalcThread = new CalcThread();
mCalcThread.start();
}
}
总结:可以看出来两个线程,相互 调用了对方的Handler对象实现了消息的发送。并且在自己的线程之内, 实现了自己的Handler对象的handleMessage()函数,来处理发送来的消息。另外一个注意的就是新线程,创建的looper对象的问题。