标签归档:android

Android中的进程与多线程的讲解(Handler和AsyncTask)

    Hello EveryBody,又到了我们相聚的时间了,今天要总结的东西现在有点迫不及待了,因为在实际的应用中如果用不到它,我们就不能再听歌的同时发送信息,其实大家应该都知道了,今天的主角就是进程与多线程,好了,其他的不多说,直接进入正题吧。

一.Android进程的分类:

(1)前台进程:即与用户正在交互的Activity或者Activity用到的Service等,如果系统内存不足时前台进程是最后被杀死的;

(2)可见进程:可以是处于暂停状态(onPause)的Activity或者绑定在其上的Service,即被用户可见,但由于失去了焦点而不能与用户交互;

(3)服务进程:其中运行着使用startService方法启动的Service,虽然不被用户可见,但是却是用户关系的,例如用户正在非音乐界面听的音乐或者正在非下载页面自己下载的文件等;当系统要用空间运行前两者进程时才会被终止;

(4)后台进程:其中运行着执行onStop方法而停止的程序,但是却不是用户当前关心的,例如后台挂着的QQ,这样的进程系统一旦没有内存就首先被杀死;

(5)空进程:不包含任何应用程序的程序组件的进程,这样的进程系统是一般不会让他存在的;

二.进程与多线程的深入

1.由于单线程而导致的ANR错误:

ANR错误(Application Not Responding),指主UI进程被阻塞超过5秒钟而出现的错误,它会终止程序的正常运行,我们要避免它 ,而产生ANR错误的原因就是:单线程。

例子如下:

package com.example.l0902_anr;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn=(Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {@Override
public void onClick(View v) {
int count=0;
while(count<1000){
count++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});}
}

运行效果如下:

OK,上面的程序出问题的原因是单线程,那么我们可以再创建一个线程去处理耗时操作,就不会阻碍主UI的操作了:

改动上面的程序如下:

package com.example.l0902_anr;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private Button btn,btn_stop;
private Thread thread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn=(Button) findViewById(R.id.btn);
btn_stop=(Button) findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
thread=new Thread(new Runnable() {
@Override
public void run() {
int count=0;
while(count<1000){
count++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count);
}
}
});
thread.start();//启动线程
}
});
btn_stop.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
thread.stop();//停止线程
}
});
}
}

运行效果如下:

代码写到这里,ANR错误就解决了,但是又出现一个新的问题,如果我想把利用新的线程来更新主UI线程,可以不可以呢,好吧,我们用上面的程序试一试,加一个TextView来接收新的线程中自增的数据,看看是否能实现:

程序修改如下:

package com.example.l0902_anr;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private Button btn;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn=(Button) findViewById(R.id.btn);
tv=(TextView) findViewById(R.id.tv);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
int count=0;
while(count<1000){
count++;
tv.setText(count+"");//试图更新主UI线程
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();//启动线程
}
});
}
}

运行效果如下:

我们可以看到程序被意外终止了,那么说明其他线程是不能更改主UI的数据的,除非...除非我们往下看...

2.Android线程之间的通信——Handler

其实,Android线程之间的通信不只是Handler,还需要Message,MessageQueue,Looper的相互使用,Android线程通信模型如下:

(1)Message:即要传递的消息;

(2)MessageQueue:存放消息的队列;

(3)Looper:用于创建MessageQueue以及循环使用其中的Message;

(4)Handler:用于消息的传递了;

好了,我们直接看下面的例子吧:

package com.example.l0902_handler;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private Button btn_start,btn_stop;
private TextView tv;
private int i=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_start=(Button) findViewById(R.id.button1);
btn_stop=(Button) findViewById(R.id.button2);
tv=(TextView) findViewById(R.id.textView1);
btn_start.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//开始发送消息
handler.post(runnabl);
}
});
btn_stop.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//停止发送消息
handler.removeCallbacks(runnabl);
}
});
}
//创建新的线程
private Runnable runnabl=new Runnable() {
@Override
public void run() {
i++;
//使用Message封装非UI线程的消息
Message m=new Message();
//使用Message的arg1属性或者arg2属性传递int类型的消息效率高
m.arg1=i;
//使用Handler发送消息
handler.sendMessage(m);
}
};
@SuppressLint("HandlerLeak")
private Handler handler=new Handler(){
public void handleMessage(Message m){
System.out.println(m.arg1);
String str=m.arg1+"";
//注意:一定一定要记得TextView是String类型哦
tv.setText(str);
handler.post(runnabl);
}
};
}

运行结果如下:

看到了吧,主UI的数据是不是更新了呢,很是神奇吧,这就是线程之间的通信了。

接下来我们要继续讲一个线程通信的机制。。。

3.简化多线程通信开发的——AsyncTask

我们直接用例子说明AsyncTask的使用吧:

(1)我们同样也先写一个类似上面的ANR错误的卡屏的例子:

package com.example.l0902_myasynctask;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private Button btn1,btn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1=(Button) findViewById(R.id.button1);
btn2=(Button) findViewById(R.id.button2);
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
try {
//超过5秒了,其实就和前面的例子一样了(ANR错误)
Thread.sleep(7000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("Hello To EveryOne");
}
});
}
}

运行效果如下:
如果把上面等待的时间改为5以内,则就是典型的卡屏的例子了,试试看吧:初始界面:

点击下面的按钮:

点击上面的按钮:此时就卡住了,屏幕什么都干不了了

卡屏期间点击了多少下下边的按钮,5秒之后都会显示出来:

上面就是经典的卡屏的例子,怎么解决呢?当然是:AsyncTask了

(2)使用AsyncTask创建后台进程,解决卡屏问题:

代码如下:

MainActivity.java

package com.example.l0902_myasynctask;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private Button btn1,btn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1=(Button) findViewById(R.id.button1);
btn2=(Button) findViewById(R.id.button2);
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//创建AsyncTask并执行
new MyAsyncTask().execute();
}
});
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("Hello To EveryOne");
}
});
}
}MyAsyncTask.java:package com.example.l0902_myasynctask;
import android.os.AsyncTask;
/**
* 在后台创建线程,不会出现卡屏现象
* @author asus
*/
public class MyAsyncTask extends AsyncTask<Void, Void, String>{
//核心方法,在后台启动一个线程
@Override
protected String doInVoid...  params) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}运行效果我们就不再给出了,描述一下就可以了,即无论我们是否按卡屏按钮,执行按钮都能正常输出,这正是因为AsyncTask创建了一个后台进程来处理耗时功能,不影响主UI的正常功能的处理。

(3)最后总结一个使用AsyncTask的例子——下载滚动条的进度:

MainActivity.java:

package com.example.l0902_usinganysc;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends Activity {
private Button btn;
private ProgressBar bar;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn=(Button) findViewById(R.id.button1);
bar=(ProgressBar) findViewById(R.id.progressBar1);
tv=(TextView) findViewById(R.id.textView1);
tv.setText("开始下载");
btn.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
MyAsyncTask my=new MyAsyncTask(tv, bar);
my.execute("","i=","打开文件");//启动方法
}
});
}
}

MyAsyncTask.java:

package com.example.l0902_usinganysc;
import android.os.AsyncTask;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* 总结:参数相关
* @author asus
*/
public class MyAsyncTask extends AsyncTask<String, Integer, String>{
private ProgressBar bar;
private TextView tv;
//构造方法,初始化ProgressBar和TextView
public MyAsyncTask(TextView tv,ProgressBar bar){
this.bar=bar;
this.tv=tv;
}
/*
* 这个方法的参数不能改,其返回类型与第三个参数一致,其参数与第一个参数类型一致
* (non-Javadoc)
* @see android.os.AsyncTask#doInParams[])
*/
@Override
protected String doInString...  params) {//可变参数
String p1=params[1];
String p2=params[2];
int i=1;
for(i=1;i<=100;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(i);
}
return p1+i+p2;//也作为下一个方法的参数
}
/*
* 当异步结束时触发此方法,其参数类型与第三个参数类型一致
* (non-Javadoc)
* @see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
@Override
protected void onPostExecute(String result) {
if(result!=null){
tv.setText("下载完成"/*+result*/);
}
super.onPostExecute(result);
}
/*
* 当异步开始的时候触发
* (non-Javadoc)
* @see android.os.AsyncTask#onPreExecute()
*/
@Override
protected void onPreExecute() {
System.out.println("异步开始");
tv.setText("开始下载");
super.onPreExecute();
}
/*
* 正在处理的时候触发,与主UI线程交互,其参数与第二个参数一致
* (non-Javadoc)
* @see android.os.AsyncTask#onProgressUpdate(Progress[])
*/
@Override
protected void onProgressUpdate(Integer... values) {//第二个可变参数,由上面的publishProgress方法的参数决定
bar.setProgress(values[0]);
tv.setText(values[0]+"%");//可变参数就是这么用的,values[1]表示publishProgress的第二个参数
super.onProgressUpdate(values);
}
}

运行效果如下:

好了。今天的内容就到这里了,希望真的能帮到你,如果有需要改进的地方请多多指出批评和指点,我欣然接受哦O(∩_∩)O哈哈~

本文出自 “MySpace” 博客,请务必保留此出处http://wangzhaoli.blog.51cto.com/7607113/1287545

AsyncTask使用解析和同步执行的问题

Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制。不过为了更加方便我们在子线程中更新UI元素,Android从1.5版本就引入了一个AsyncTask类,使用它就可以非常灵活方便地从子线程切换到UI线程。 AsyncTask 很早就出现在Android的API里了,所以我相信大多数朋友对它的用法都已经非常熟悉。不过今天我还是准备从AsyncTask的基本用法开始讲起, 然后我们再来一起分析下AsyncTask的并行执行情况

AsyncTask的基本用法

首先来看一下AsyncTask的基本用法,由于AsyncTask是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它。使用时需要继承这个类,然后调用execute()方法。注意继承时需要设定三个泛型Params,Progress和Result的类型,如AsyncTask<Void,Inetger,Void>:

  • Params是指调用execute()方法时传入的参数类型和doInBackgound()的参数类型
  • Progress是指更新进度时传递的参数类型,即publishProgress()和onProgressUpdate()的参数类型
  • Result是指doInBackground()的返回值类型
上面的说明涉及到几个方法:
  • doInBackgound() 这个方法是继承AsyncTask必须要实现的,运行于后台,耗时的操作可以在这里做
  • publishProgress() 更新进度,给onProgressUpdate()传递进度参数
  • onProgressUpdate() 在publishProgress()调用完被调用,更新进度

布局文件如下:

<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示异步的执行情况" android:id="@+id/tv_show"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动一个异步任务"
android:id="@+id/bt_start_AsyncTask" android:layout_below="@+id/tv_show" android:layout_alignLeft="@+id/tv_show"
android:layout_marginTop="12dp" android:focusableInTouchMode="true"/>

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动一个异步 长耗时 任务"
android:id="@+id/bt_start_long_AsyncTask"
android:focusableInTouchMode="true"
android:layout_above="@+id/bt_toast" android:layout_alignLeft="@+id/tv_show2"
android:layout_marginBottom="13dp"/>
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="弹出对话框"
android:id="@+id/bt_toast"
android:focusableInTouchMode="true"
android:layout_centerVertical="true" android:layout_alignLeft="@+id/bt_start_long_AsyncTask"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="显示长耗时情况"
android:id="@+id/tv_show2"
android:layout_above="@+id/bt_start_long_AsyncTask" android:layout_alignLeft="@+id/bt_start_AsyncTask"
android:layout_marginBottom="11dp"/>

</RelativeLayout>

源代码如下:

 package cn.iigrowing.android.MyAsyncTask;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

private Button bt_start_AsyncTask = null;
private Button bt_start_long_AsyncTask = null;
private Button bt_toast = null;

private TextView tv = null;
private TextView tv2 = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

bt_start_AsyncTask = (Button) findViewById(R.id.bt_start_AsyncTask);
bt_start_long_AsyncTask = (Button) findViewById(R.id.bt_start_long_AsyncTask);
bt_toast = (Button) findViewById(R.id.bt_toast);

tv = (TextView) findViewById(R.id.tv_show);
tv2 = (TextView) findViewById(R.id.tv_show2);

bt_start_AsyncTask.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
update();
}
});
bt_start_long_AsyncTask.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
update2();
}
});
bt_toast.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
Toast.makeText(MainActivity.this, "点击了按钮", Toast.LENGTH_LONG).show();
}
});

}

private void update() {
UpdateTextTask updateTextTask = new UpdateTextTask(this, 1, tv);
updateTextTask.execute();
}

private void update2() {
UpdateTextTask updateTextTask = new UpdateTextTask(this, 10, tv2);
updateTextTask.execute();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

class UpdateTextTask extends AsyncTask<Void, Integer, Integer> {
private Context context;
private TextView mytv = null;

private int sleepTime = 1;

UpdateTextTask(Context context, int sleepSecond, TextView tv) {
this.context = context;
sleepTime = sleepSecond;
this.mytv = tv;
}

/**
* 运行在UI线程中,在调用doInBackground()之前执行
*/
@Override
protected void onPreExecute() {
Toast.makeText(context, "开始执行", Toast.LENGTH_SHORT).show();
}

/**
* 后台运行的方法,可以运行非UI线程,可以执行耗时的方法
*/
@Override
protected Integer doInBackground(Void... params) {
int i = 0;
while (i < 10) {
i++;
publishProgress(i);
try {
Thread.sleep(1000 * sleepTime);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}

/**
* 运行在ui线程中,在doInBackground()执行完毕后执行
*/
@Override
protected void onPostExecute(Integer integer) {
Toast.makeText(context, "执行完毕", Toast.LENGTH_SHORT).show();
}

/**
* 在publishProgress()被调用以后执行,publishProgress()用于更新进度
*/
@Override
protected void onProgressUpdate(Integer... values) {
this.mytv.setText(this.mytv.getText() + " " + values[0]);
}
}
}

通过上面的例子发现, 在同时点击两个测试按钮时, 两个文本框不能同时更新, 证明两个异步任务没有并行执行!!

查找网络资料有如下:研 究过Android系统源码的同学会发现:AsyncTask在android2.3的时候线程池是一个核心数为5线程,队列可容纳10线程,最大执行 128个任务,这存在一个问题,当你真的有138个并发时,即使手机没被你撑爆,那么超出这个指标应用绝对crash掉。 后来升级到3.0,为了避免并发带来的一些列问题,AsyncTask竟然成为序列执行器了,也就是你即使你同时execute N个AsyncTask,它也是挨个排队执行的。 这一点请同学们一定注意,AsyncTask在3.0以后,是异步的没错,但不是并发的。关于这一点的改进办法,我之前写过一篇《Thread并发请求封装——深入理解AsyncTask类》没有看过的同学可以看这里,本文是在这个基础上对AsyncTask做进一步的优化。参考:http://my.oschina.net/kymjs/blog/350565

程序源代码

链接: http://pan.baidu.com/s/1Eqw3O 密码: 6kll

从0开始学编程(22)-android开发环境搭建与入门教程

一. Android的钱景

参考2013年9月份的数据, Android生态中国市场份额达9成 追逐者争相涌现, 基本上是市场占有率最高的手机操作系统了, 它市场前景不用多说, 开发它的应用程序自然也非常有前景。

Android生态中国市场份额达9成 追逐者争相涌现

腾讯数码讯(苏扬)北京时间5月16日消息,谷歌Chrome和Android部门主管Sundar Pichai在I/O开发者大会的Keynote环节正式公布,全球Android设备激活总量达9亿的最新数据。而2012年全球Android设备的 激活量仅4亿,同比增长125%。而2011年,该数字刚刚突破1亿。两年时间一共增量高达8亿,对于Android操作系统而言,成绩斐然,同时这也意 味着Android作为世界第一大移动操作系统生态所言非虚。

相比在全球市场庞大的占有量,Android操作系统在发展中国家,尤其是新兴市场的占有量更是惊人。其中,中国市场的Android设备占移动手 持设备总量的9成,这不仅反映出了新兴智能手机市场的巨大潜力,也给其它非Android操作系统生态形成了巨大压力。相比之下,在已经高度成熟发展的北 美智能手机市场,iOS依旧是主力平台,而Android能否借力打力再下一城,全新的操作系统功能特征、更好的交互设计以及更优质的用户体验将成为其考 核新标准。与此同时,面对Windows Phone 8、BB10、Firefox OS等不同定位且针对不同用户群体操作系统的追赶,Android能否保持高速的领跑节奏和领先优势,同样值得商榷。

二. Android来源和历史

Android一词的本义指“机器人”,同时也是Google于2007年11月5日宣布的基于Linux平台的开源手机操作系统的名称,该平台由操作系统、中间件、用户界面和应用软件组成。
Android一词最早出现于法国作家利尔亚当(Auguste Villiers de l'Isle-Adam)在1886年发表的科幻小说《未来夏娃》(L'ève future)中。他将外表像人的机器起名为Android。
Android的Logo是由Ascender公司设计的,诞生于2010年,其设计灵感源于男女厕所门上的图形符号,[1] 于是布洛克绘制了一个简单的机器人,它的躯干就像锡罐的形状,头上还有两根天线,Android小机器人便诞生了。其中的文字使用了Ascender公司专门制作的称之为“Droid ” 的字体。Android是一个全身绿色的机器人,绿色也是Android的标志。颜色采用了PMS 376C和RGB中十六进制的#A4C639来绘制,这是Android操作系统的品牌象徵。有时候,它们还会使用纯文字的Logo。[1]
2012年7月美国科技博客网站BusinessInsider评选出二十一世纪十款最重要电子产品,Android操作系统和iPhone等榜上有名。

这么有钱景的一个系统, 自然有更多人学习了, 从网络上找一套比较好的 视频教程, 从中挑选了, 几个集初级入门的 视频, 分享出来, 版权属于员作者, 后面会陆续根据 情况不断分享资源出来

http://pan.baidu.com/s/1gdAL6EZ      m7yr   anroid学习教程入门

另外, 搭建android 过程还是比较麻烦的, 特别是下载sdk是个繁琐的事情, 我这里下载好了, 打包了, 大家下载了, 解压缩到 e:\ 就可以 进到里面目录中,找到eclipse.exe 进行执行

http://pan.baidu.com/s/1sj9Lfpb   cyz4     android开发环境, 包括一家下载好的 android sdk文件

android的ADT-Bundle环境快速创建   这个是一篇关于android开发环境的 资料, 可以参考。

下面是从网络上找到的, 比较好的 介绍android开发的教程, 我从中摘抄一部分比较合适的, 原文地址: http://www.ibm.com/developerworks/cn/opensource/os-android-devel/

三. Android 平台

Android 有丰富的功能,因此很容易与桌面操作系统混淆。Android 是一个分层的环境,构建在 Linux 内核的基础上,它包括丰富的功能。UI 子系统包括:

  • 窗口
  • 视图
  • 用于显示一些常见组件(例如编辑框、列表和下拉列表)的小部件

Android 包括一个构建在 WebKit 基础上的可嵌入浏览器,iPhone 的 Mobile Safari 浏览器同样也是以 WebKit 为基础。

Android 提供多种连接选项,包括 WiFi、蓝牙和通过蜂窝(cellular)连接的无线数据传输(例如 GPRS、EDGE 和 3G)。Android 应用程序中一项流行的技术是链接到 Google 地图,以便在应用程序中显示地址。Android 软件栈还提供对基于位置的服务(例如 GPS)和加速计的支持,不过并不是所有的 Android 设备都配备了必需的硬件。另外还有摄像支持。

过去,移动应用程序努力向桌面应 用程序看齐的两个领域分别是图形/媒体和数据存储方法。Android 通过提供对 2D 和 3D 图形的内置支持,包括 OpenGL 库,解决了图形方面的挑战。由于 Android 平台包括流行的开源 SQLite 数据库,因此缓解了数据存储的负担。图 1 显示一个简化的 Android 软件层次结构。

图 1. Android 软件层次结构

Android 软件层次结构

四. 应用程序架构

如 前所述,Android 运行在 Linux 内核上。Android 应用程序是用 Java 编程语言编写的,它们在一个虚拟机(VM)中运行。需要注意的是,这个 VM 并非您想象中的 JVM,而是 Dalvik Virtual Machine,这是一种开源技术。每个 Android 应用程序都在 Dalvik VM 的一个实例中运行,这个实例驻留在一个由 Linux 内核管理的进程中,如下图所示。

图 2. Dalvik VM

Dalvik VM

Android 应用程序由一个或多个组件组成:

活动
具有可视 UI 的应用程序是用活动实现的。当用户从主屏幕或应用程序启动器选择一个应用程序时,就会开始一个动作。
服务
服务应该用于任何需要持续较长时间的应用程序,例如网络监视器或更新检查应用程序。
内容提供程序
可 以将内容提供程序看作数据库服务器。内容提供程序的任务是管理对持久数据的访问,例如 SQLite 数据库。如果应用程序非常简单,那么可能不需要创建内容提供程序。如果要构建一个较大的应用程序,或者构建需要为多个活动或应用程序提供数据的应用程序, 那么可以使用内容提供程序实现数据访问。
广播接收器
Android 应用程序可用于处理一个数据元素,或者对一个事件(例如接收文本消息)做出响应。

Android 应用程序是连同一个 AndroidManifest.xml 文件一起部署到设备的。AndroidManifest.xml 包含必要的配置信息,以便将它适当地安装到设备。它包括必需的类名和应用程序能够处理的事件类型,以及运行应用程序所需的许可。例如,如果应用程序需要访 问网络 — 例如为了下载一个文件 — 那么 manifest 文件中必须显式地列出该许可。很多应用程序可能启用了这个特定的许可。这种声明式安全性有助于减少恶意应用程序损害设备的可能性。

下一节讨论构建 Android 应用程序所需的开发环境。

五. 所需的工具

开始开发 Android 应用程序的最简捷的方式是下载 Android SDK 和 Eclipse IDE(参见 参考资料)。Android 开发可以在 Microsoft® Windows®、Mac OS X 或 Linux 上进行。

本 文假设您使用的是 Eclipse IDE 和用于 Eclipse 的 Android Developer Tools 插件。Android 应用程序是用 Java 语言编写的,但是是在 Dalvik VM(非 Java 虚拟机)中编译和执行的。在 Eclipse 中用 Java 语言编程非常简单;Eclipse 提供一个丰富的 Java 环境,包括上下文敏感帮助和代码提示。Java 代码通过编译后,Android Developer Tools 可确保适当地将它打包,包括 AndroidManifest.xml 文件。

虽然没有 Eclipse 和 Android Developer Tools 插件也可以开发 Android 应用程序,但是那样就需要熟悉 Android SDK。

Android SDK 是作为一个 ZIP 文件发布的,可以将该文件解压到硬盘上的一个目录中。由于有多个 SDK 更新,建议有意识地组织开发环境,以便在不同的 SDK 安装之间轻松地切换。SDK 包括:

android.jar
Java 归档文件,其中包含构建应用程序所需的所有的 Android SDK 类。
documention.html 和 docs 目录
本地和网上提供的 SDK 文档。这些文档的主要形式为 JavaDocs,以便于在 SDK 中导航大量的包。文档还包括一个高级开发指南和 Android 社区的链接。
Samples 目录
samples 子目录包含各种应用程序的源代码,包括 ApiDemo,该应用程序演示了很多 API。这个示例应用程序可以作为 Android 应用程序开发的良好起点。
Tools 目录
包含所有用于构建 Android 应用程序的命令行工具。最常用、最有用的工具是 adb 实用程序(Android Debug Bridge)。
usb_driver
该目录包含将开发环境连接到支持 Android 的设备(例如 G1 或 Android Dev 1 解锁开发手机)所需的驱动程序。只有 Windows 平台的开发人员才需要这些文件。

Android 应用程序可以在实际的设备上运行,也可以在 Android SDK 附带的 Android Emulator 上运行。图 3 显示 Android Emulator 的主屏幕。

图 3. Android Emulator

Android Emulator

Android Debug Bridge

adb 实用程序支持一些可选命令行参数,以提供强大的特性,例如复制文件到设备或从设备复制文件。可以使用 shell 命令行参数连接到手机本身,并发送基本的 shell 命令。图 4 显示在通过 USB 线连接到 Windows 笔记本电脑的一个实际设备上运行的 adb shell 命令。

图 4. 使用 adb shell 命令

使用 adb shell 命令

在这个 shell 环境中,可以:

  • 显示网络配置,网络配置可显示多个网络连接。注意这多个网络连接:
    • lo 是本地或 loopback 连接。
    • tiwlan0 是 WiFi 连接,该连接由本地 DHCP 服务器提供一个地址。
  • 显示 PATH 环境变量的内容。
  • 执行 su 命令,以成为超级用户。
  • 将目录改为 /data/app,其中存放用户应用程序。
  • 列出包含某个应用程序的目录。Android 应用程序文件实际上是归档文件,可通过 WinZip 之类的软件查看。扩展名为 apk。
  • 发出 ping 命令,查看 Google.com 是否可用。

从相同的命令提示符环境中,还可以与 SQLite 数据库交互,启动程序以及执行许多其他系统级任务。想像一下您正在连接到电话,因此这是非常了不起的功能。

在下一节,您将创建一个简单的 Android 应用程序。

六. 编写一个基本的应用程序

本节展示如何构建一个 Android 应用程序。示例应用程序非常简单:一个修改后的 “Hello Android” 应用程序。您将进行一个微小的修改,使屏幕背景全部变为白色,以便把手机用作手电筒。这个例子不是很有创意,但是可以作为一个有用的例子。请 下载 完整的源代码。

为了在 Eclipse 中创建应用程序,选择 File > New > Android project,这将启动 New Android Project 向导。

图 5. New Android project 向导

new Android project 向导

接下来,创建一个简单的应用程序,该应用程序有一个活动,并且在 main.xml 中有一个 UI 布局。布局包含一个文本元素,您将修改这个文本元素,以显示 Android FlashLight。下面的清单显示了这个简单的布局。

清单 1. Flashlight 布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/all_white">
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello" android:textColor="@color/all_black" 
   android:gravity="center_horizontal"/>
</LinearLayout>

在 strings.xml 中创建两个颜色资源。

清单 2. strings.xml 中的颜色
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Android FlashLight</string>
    <string name="app_name">FlashLight</string>
    <color name="all_white">#FFFFFF</color>
    <color name="all_black">#000000</color>
</resources>

主屏幕布局有一个定义为 all_white 的背景色。在 strings.xml 文件中,可以看到 all_white 被定义为一个值为 #FFFFFF 的 RGB 三元组,即纯白。

布局包含一个 TextView,这实际上是一块静态文本。它是不可编辑的。文本被设为黑色,并通过 gravity 属性设为水平居中。

该应用程序有一个名为 FlashLight.java 的 Java 源文件,如以下清单所示。

清单 3. Flashlight.java
package com.msi.flashlight;
import android.app.Activity;
import android.os.Bundle;
public class FlashLight extends Activity {
    /** Called when the activity is first created. */
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

该代码是直接来自 New Project 向导的模板代码:

  • 它是 Java 包 com.msi.flashlight 的一部分。
  • 它有两个 import:
    • 一个用于 activity 类
    • 一个用于 bundle 类
  • 当该活动发起后,onCreate 方法被调用,传入一个 savedInstanceState。对于我们来说,不必关心这个 bundle。只有在暂停然后恢复活动时才会用到。
  • onCreate 方法覆盖了同名的 activity 类方法。它调用超类的 onCreate 方法。
  • setContentView() 的调用将关联 main.xml 文件中定义的 UI 布局。main.xml 和 strings.xml 中的任何内容都自动映射到 R.java 源文件中定义的常量。任何时候都不要直接编辑这个文件,因为它随着每次构建而改变。

运行该应用程序可以看到一个白色屏幕,其中有黑色文本。

图 6. flashlight 的白色屏幕

flashlight 的白色屏幕

下面显示用于 FlashLight 应用程序的 AndroidManifest.xml 文件。

清单 4. 用于 FlashLight 的 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.msi.flashlight"
      android:versionCode="1"
      android:versionName="1.0.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".FlashLight"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

该文件是由用于 Eclipse 的 Android Developer Tools 插件自动创建的。您不需要做任何事情。

当然,这个应用程序并不是很强大。但是如果希望读点书,又不想打扰正在睡觉的爱人,或者如果需要在断电时去地下室查看保险丝盒,那么这个应用程序还是很方便的。

 

相关文章

从0开始学编程(22)-android开发环境搭建与入门教程

从0开始学编程(21)-Java网络编程入门

从0开始学编程(20)-Java线程入门

从0开始学编程(19)–java流概念入门

从0开始学编程(18)–java快速入门

从0开始学编程(17)–面向对象思想了解

从0开始学编程(16)–数据库加强

从0开始学编程(15)–总结篇-php编程强化巩固

从0开始学编程(14) – Php数据相关操作

从0开始学编程(13) Php获取form表单数据

从0开始学编程(12) 使用 eclipse的 php插件单步调试php程序

从0开始学编程(11) 使用 eclipse的 php插件 调试php程序

从0开始学编程(10) 用例子学习bootstrap的布局

从0开始学编程(9) – css、html和js简便工具

从0开始学编程(8) – 数据库简介

从0开始学编程(7) – 常用网站介绍

从0开始学编程(6)–在多了解一下php都涉及些啥东西

从0开始学编程(5)–方便的php编辑工具notepad++

从0开始学编程(4)–html基础入门

从0开始学编程(3)–学习必备的基础技能

从0开始学编程(2)–学习的方法和目标

从0开始学编程(1)–xampp配置php学习环境

Android学习基本概念

一 了解android

Android是非常流行的手机操作系统了, 现在android市场占有率在70%以上, 他的编程自然是一个很大的市场了。 最近也学习了一下android的编程知识,在网络上查找了很多文章, 找了很多资料, 把相关内容总结一下。

android的维基百科:http://zh.wikipedia.org/zh/Android

Android开发用的开发语言:
Java (学习Android之前最好有Java基础 android视频那个人出了一套android的java基础教程, 有时间我分享一下,我看了人家写的很好,值得学习和研究)

Android系统:
Android是基于Linux系统针对手机开发的系统

二 Android的大框架:

Android应用程序开发是基于组件的开发:
Android四大组件:

1. Activities

Activity之间的关系:
一个Activities代表一个单独和用户界面。

相当于windows中的窗口, 其实android程序同windows 的dot net下的 form窗体很像 ,一个程序由多少个窗体组成, 每个窗体内部有多个控件, 控件有消息, 窗体有消息。 各个窗体直接可以相互通讯。连ui线程是不安全都是一样。 仅仅是开发语言不一样了,换成java, 执行环境更换成linux了。
一个程序可以有多个Activity,不同程序里和同一个程序里的Activity可以通过Content Provider来交流(Intent就是Content下的一个类)

Activity的生命周期: -- 具体生命周期中的切换触发情况见Android Developer Doc

android的activity生命周期

生命周期是非常重要的事情, 不了解声明周期, 有时候您写代码到不同事件中, 可能造成 非预期的效果。 声明周期中要特别注意: 那些是可以显示前的 事件, 那些是显示后的事件。  那些是切换时发生的。  这个相关情况, 在后面参考视频中有详细讲解,欢迎观看。

Activities是被Task的back stack所管理:   这个概念比麻烦, 初学可以忽略,以后慢慢在看了。
Task是一系列Activity的集合(用户交互时的Activity)
Task运行概念图:

android的task简图

Back Stack运行概念图:

android的task

Activity的状态也可以通过启动的时候传入一些Flag来指定,也可以通过在Mainifest.xml里面指定:
e.g.
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_SINGLE_TOP

如何创建一个自己的Activity:
1. 创建一个类,并继承至Activity
2. 重写一些必要的生命周期函数
3. 在Mainifest里面注册Activity

2. Services

A Service是一个应用程序里做那些需要长期运行但是不需要和用户交互或者为其他应用程序提供服务的组件

Service的两个特点:

  1.      一个告诉应用程序哪些事需要在后台去做的组件
  2.      一个把应用程序的一些功能暴露给其他应用程序的组件

Service Lifecycle:

  1.      开启服务 -- Context.startService()

这里系统回去查看有哪些服务,如果未被开启会先调用Service::onCreate()方法,然后在调用onStartCommand(),否则只调用onStartCommand()

  1.      关闭服务 – Context.stopService() or stopSelf()

关闭服务的时候会调用Service::onDestroy()方法

具体更多的Lifecycle还跟Service在特定情况下的优先级有关,具体查看Service文档

注意:

Service不是一个单独的进程也不是一个单独的线程

  1. Content Provider

提供为存储和获取数据提供了统一的接口

可以在不同的应用程序之间共享数据

URI (Unique resource identify) – 每一个content provider都有一个唯一的URI

更多内容参考Android文档

4. Broadcast Receivers

分为发送方()和接收方(BroadcastReceiver)

针对发送方的事件进行特定处理

需要通过1. AndroidManifest.xml去注册接受者(***) 2.在程序代码中注册—Context.registerReceiver(),IntendFilter类相当于AndroidManifest.xml里的 tag,而且receiver的实例需要自己去初始化),去表明该接受者对哪些action感兴趣,具体处理在接收方的OnReceiver()里

发送方需要定义发送的action和data是什么(封装在Content相关类里),然后通过context.sendBroadCast发送出去(发出后,Android会通过AndroidManifest.xml去查看哪些BroadcastReceiver对该动作感兴趣就生成相应的BroadcastReceiver对象去处理)
针对Android项目里的一些文件和中要知识学习:

详细信息参考资料:  链接:http://pan.baidu.com/s/1dD3vFVF 密码:i9td

 

解决android studio Gradle警告GBK编码的不可映射字符的问题2

前面用as开发android项目中, 遇到编码问题, 查找了各种办法, 但是没有好的解决
在前面的给出了一个比较不好的解决办法将编码转换成gbk然后进行编译
今天重新查找了些文章, 仔细阅读, 再三尝试, 终于可以把代码编译成utf8方式了,相关过程如下:

1. 编译项目后, 发现如下错误

android studio编译时出现的问题
android studio编译时出现的问题

2. 启动cmd窗口, 到dos下 ,用下面命令进行编译,获取编译的详细信息

gradlew compileDebug --stacktrace 1> a.log 2>&1

上面命令将编译的详细信息, 输出到a.log中, 然后查看日志文件

进入cmd(控制台)进行编译, 获取详细编译信息

进入cmd(控制台)进行编译, 获取详细编译信息

3. 查看日志文件,根据日志文件定位, 代码中那个代码有问题

 

查看android studio详细日志文件 查看android studio详细日志文件

 

查看今天的android studio编译错误
查看具体的android studio编译错误

4. 设置项目的模块编译特性为utf8 ,然后问题解决

设置 android studio的utf-8方式编译代码解决编译错误
设置 android studio的utf-8方式编译代码解决编译错误

为了更好的进行设置,记录了一下处理过程。
链接: http://pan.baidu.com/s/1sj4sqG9 密码: usqi
tasks.withType(Compile){
options.encoding = "UTF-8"
}