一、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; } }