一、app的运行方式
操作系统会给每一个andorid应用程序(App)分配一个唯一userId。所以每一个App都是以一个独立的用户运行在android操作系统之上。
二、app的framework组成
android的App框架主要包含三大核心组件Activity、Service、BroadcastReceiver和一个重要消息承载组件Intent。
1)Activity
Activity是一个掌控与UI交互的一个组件。负责加载UI的layout,并注册UI上的可视化组件的监听器(比如一个button的click事件的监听处理器)。使用activity需要关注他的生命周期不同阶段所调用的方法,这些方法和对应的activity状态关系可以参考下图。
更多详情参阅这里。
2)Service
Service是提供后台逻辑处理的组件,不与UI进行绑定,用来在后台处理耗时较长的任务(注意需要另起线程处理,因为service仍然是在他的host线程运行的)。
该组件有两种使用方式:
a)startService():某一组件调用startService()来启动service,启动后即使负责启动的组件已经失效(destoryed)该service仍然可以存在并并运行。
b)bindService():一般情况下是用activity绑定一个service,这样activity和service可以一起交互协作。当绑定在service上的所有组件都unbund之后,该service才会被销毁。
生命周期和相关的调用方法如下图所示:
更多详情参考这里
3)broadcastReceiver
BroadcastReceiver是为了实现系统广播而提供的一种组件。比如,我们可以发出一种广播来测试手机wifi信号连接的变化,这时候就可以定义一个BraodcastReceiver来接受广播,当wifi连接上internet时可以提示用户可以更新一写软件。我们可以用Intent配合sendBroadcast()方法发起一个系统级别的事件广播来传递消息。当然我们也可以在自己的应用程序中实现BroadcastReceiver来监听和响应广播的Intent。broadcastReceiver的生命周期非常短暂,仅用户持续与onReceive()方法,而且该方法一般情况下不能够长时间的执行,而且在该方法中启动的thread会在该方法返回后销毁,所以一般在这里启动service来处理消息。
更多信息参考这里
4)intent
Intent对象就是一个信息包(bundle),他主要包含接受处理该intent的组件关心的信息数据和android系统关心的信息数据。
更多信息参考这里
三、一个helloworld的实例
根据以上三个核心组件和信息承载组件Intent的知识,我们做一个负责一点的helloworld的例子来练下手。大家先参考google等在本地安装起来一个环节,并创建一个初步的helloworld的例子。一般的网上找的这个例子只是一个初步的包含了activity组件的例子。我带着大家一起改造下这个项目,将三大核心组件都加入进来(其实app框架是有四大重要组件的,除了我们提到的三大核心组件还有另外一个contentprovider暂时先不讲)。
0)App项目程序结构和App demo逻辑
大家根据google来的信息肯定已经先搭起来了一个只包含了activity的例子。先简单的介绍下这个项目的程序代码结构,如下图。
为了练手3大核心组件,我们设计一个简单的场景,用户在界面上输入一个字符串,然后点击一个广播的按钮,通过该按钮触发一个系统广播(即发送一个自定义的广播信息,在Activity中绑定具体UI组件的事件监听器),然后我们再顶一个广播信息的接受者来处理这个消息(BroadcastReceiver),具体的处理触发动作我们放到一个service中在后台处理,具体的处理逻辑是在屏幕上显示一下这个输入信息,并且渐隐。
2)下面是具体的实现逻辑代码的核心部分。请参考。
andoridmanifest.xml文件,这里配置了整个app组件信息
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myfirstapp"
android:versionCode="1"
android:versionName="1.0" >
<!-- 指定适用的sdk信息 -->
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<!-- 应用组件的配置,主要配置activity、service、broadcastReceiver 、contentProvider -->
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<!-- 配置启动要使用的主Activity -->
<activity
android:name="com.example.myfirstapp.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 配置系统消息的接收器 -->
<receiver android:name="MyReceiver" >
<intent-filter>
<!-- 指定接受消息的action名称-->
<action android:name="com.example.action.MyAction" />
</intent-filter>
</receiver>
<!-- 配置我们的消息处理服务 -->
<service
android:name="MyService"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.ACTION_SCREEN_ON" />
</intent-filter>
</service>
</application>
</manifest>
/res/layout/layout_main.xml配置了我们的交互UI的组件,虽然此处很简单只有2个按钮和2个textview但是我们后台的逻辑都是通过这里触发的。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:id="@+id/button1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:text="@string/button1" />
<EditText
android:id="@+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="text" >
<requestFocus />
</EditText>
<Button
android:id="@+id/button2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/button2" />
</LinearLayout>
com.example.myfirstapp.MainActivity.java文件,我们的系统中的Activity,修改后代码如下。
//activity需要继承android.app.Activity
public class MainActivity extends Activity {
private Boolean clickSign = false;
private final static String MY_ACTION = "com.example.action.MyAction";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//装载UI的Layout
setContentView(R.layout.activity_main);
//获取页面各组件
final TextView hello = (TextView) this.findViewById(R.id.textView1);
final TextView info = (TextView)this.findViewById(R.id.editText1);
Button button = (Button) this.findViewById(R.id.button1);
Button broadcastBtn = (Button)this.findViewById(R.id.button2);
//绑定页面按钮的click事件监听器
button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
if(!clickSign){
hello.setText(R.string.tttttt);
}else{
hello.setText(R.string.hello_world);
}
clickSign = !clickSign;
}
});
//点击该按钮后将会发送系统消息
broadcastBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
CharSequence infoText = info.getText();
Intent intent = new Intent();
intent.setAction(MY_ACTION);
intent.putExtra("msg", "your input info:"+infoText);
sendBroadcast(intent);
}});
}
}
com.example.myfirstapp.MyReceiver我们的定义Receiver。
//系统消息接收器,可以跨系统接受消息,需要继承自android.content.BroadcastReceiver
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String msg=intent.getStringExtra("msg");
//构造启动消息处理服务的intent
Intent serviceIntent=new Intent(context, MyService.class);
serviceIntent.putExtra("msg", msg);
//启动服务
context.startService(serviceIntent);
}
}
com.example.myfirstapp.MyService定义service,具体信息可以参照下面的代码和注释
//service 需要继承android.app.Service
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
//Unbund Service 此处可以返回空
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int result = super.onStartCommand(intent, flags, startId);
//拿到消息数据并展示,如果此处消息的处理比较耗时可以启动线程进行处理
String msg = intent.getStringExtra("msg");
Toast.makeText(this, "msg received in service.msg is---"+msg, Toast.LENGTH_LONG).show();
return result;
}
}