这几天在忙着复习功课,看面试题,海投简历,结果所有简历都石沉大海,唉,心塞.......
把已整理的知识点先传了吧。囊括了android的定义、系统架构、四大组件、六大布局和五大数据存储,有点多,慢慢理解就好了’
Android是什么?
Android是Google开发的基于Linux平台的手机开源操作系统,它包括操作系统、用户界面和应用程序。android采用了WebKit浏览器引擎,具备触摸屏、高级图形显示和上网功能,用户能够在手机上查看电子邮件 、搜索网址和观看视频节目等。
Android系统架构
android系统架构分为四层,从底层依次为:Linux核心层、系统运行库层、应用程序框架层、应用程序层。
Android四大组件
此处多摘自shenggaofei的csdn博客http://blog.youkuaiyun.com/shenggaofei/article/details/52450668
Android四大组件分别为:activity、service、contentProvider、broadcastReceiver
1.activity
activity是android系统中的四大组件之一,是用来显示view的组件,可用于与用户交互。一个android应用通常是通过activity来启动和运行。
一个activity通常就是一个单独的窗口,activity之间通过Intent进行通信。
android应用中每一个Activity都必须要在AndroidManifest.xml配置文件中声明,否则系统将不识别也不执行该Activity。
2.service
service用于在后台处理一些耗时的逻辑,或者执行某些需要长期运行的任务,必要的时候我们可以在程序退出的情况下,让service在后台继续保持运行状态。
一、启动service的方法有两种:
(1)started(启动):当应用程序组件(如Activity)调用startService()方法启动服务时,服务处于started状态
(2)bound(绑定):当应用程序组件调用bindService()方法绑定服务时,服务处于bound状态
二、两种方法的区别:
(1)startService()方法启动服务,是由其他组件调用startService()方法启动的,这导致服务的onStartCommand()方法被调用。当服务是started状态时,其生命周期与启动它的组件无关,并且可以在后台无限期运行,即使启动服务的组件已经被销毁。因此,服务需要在完成任务后调用stopSelf()方法停止,或者由其他组件调用stopService()方法停止。
(2)bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
三、开发人员需要在应用程序配置文件中声明全部的service,使用<service></service>标签
3.contentProvider
(1)android平台提供了Content Provider使一个应用程序的指定数据集提供给其他应用程序。其他应用可以通过ContentResolver类从该内容提供者中获取或存入数据。
(2)只有需要在多个应用程序间共享数据是才需要内容提供者。例如,通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。它的好处是统一数据访问方式。
(3)ContentProvider实现数据共享。ContentProvider用于保存和获取数据,并使其对所有应用程序可见。这是不同应用程序间共享数据的唯一方式,
因为android没有提供所有应用共同访问的公共存储区。
(4)开发人员不会直接使用ContentProvider类的对象,大多数是通过ContentResolver对象实现对ContentProvider的操作。
(5)ContentProvider使用URI来唯一标识其数据集,这里的URI以content://作为前缀,表示该数据由ContentProvider来管理。
4.broadCastReceiver
(1)你的应用可以使用它对外部事件进行过滤,只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。广播接收器没有用户界面。然而,它们可以启动一个activity或service来响应它们收到的信息,或者用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力,例如闪动背灯、震动、播放声音等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。
(2)广播接收者的注册有两种方法,分别是程序动态注册和AndroidManifest文件中进行静态注册。
(3)动态注册广播接收器特点是当用来注册的Activity关掉后,广播也就失效了。静态注册无需担忧广播接收器是否被关闭,只要设备是开启状态,广播接收器也是打开着的。也就是说哪怕app本身未启动,该app订阅的广播在触发时也会对它起作用。
5.四大组件总结:
(1)四大组件都需要注册才可以使用,每个Activity、service、Content Provider都需要在AndroidManifest文件中进行配置。而broadcastReceiver广播接收者的注册分静态注册(在AndroidManifest文件中进行配置)和通过代码动态创建并以调用Context.registerReceiver()的方式注册至系统。
(2)四大组件的激活:
内容提供者的激活:当接收到ContentResolver发出的请求后,内容提供者被激活。而其它三种组件activity、服务和广播接收器被一种叫做intent的异步消息所激活
(3)四大组件的关闭:
内容提供者仅在响应ContentResolver提出请求的时候激活。而一个广播接收器仅在响应广播信息的时候激活。所以,没有必要去显式的关闭这些组件。
Activity关闭:可以通过调用它的finish()方法来关闭一个activity。
服务关闭:对于通过startService()方法启动的服务要调用Context.stopService()方法关闭服务,使用bindService()方法启动的服务要调用Contex.unbindService()方法关闭服务。
Android系统是一个多任务(Multi-Task)的操作系统,可以在用手机听音乐的同时,也执行其他多个程序。每多执行一个应用程序,就会多耗费一些系统内存,
当同时执行的程序过多,或是关闭的程序没有正确释放掉内存,系统就会觉得越来越慢,甚至不稳定。为了解决这个问题,Android引入了一个新的机制,即生命周期(Life Cycle)。
Android六大布局
LinearLayout(线性布局)、RelativeLayout(相对布局)、FramLayout(帧布局)、TableLayout(表格布局)、GridLayout(网格布局)、AbsoluteLayout(绝对布局)。
android中声明程序布局有两种方式:1) 使用XML文件描述界面布局;2) 在Java代码中通过调用方法进行控制。
使用XML文件声明有以下3个特点:
1) 将程序的表现层和控制层分离;
2) 在后期修改用户界面时,无须更改程序的源程序;
3) 可通过WYSIWYG可视化工具直接看到所设计的用户界面,有利于加快界面设计的过程。
建议尽量采用XML文件声明界面元素布局。在程序运行时动态添加界面布局会大大降低应用响应速度,但依然可以在必要时动态改变屏幕内容。
Android五大存储
SharedPreferences、文件存储、SQLite数据库方式、contentProvider(内容提供器)、网络。
1.SharedPreferences方式
Android提供用来存储一些简单的配置信息的一种机制,例如,一些默认欢迎语、登录的用户名和密码等。其以键值对的方式存储,
使得我们可以很方便的读取和存入。也常常用于存储用户的偏好设置。
1)程序要实现的功能:
我们在Name文本框中输入wangwu,在Password文本框中输入123456,然后退出这个应用。我们在应用程序列表中找到这个应用,
重新启动,可以看到其使用了前面输入的Name和Password,也就是我们常常遇到的记录用户输入的账号和密码。
2)实现的代码
很简单的布局,此处省略代码,直接上java代码实现存储账号密码等。
public static final String SETTING_INFOS = "SETTING_Infos";
public static final String NAME = "NAME";
public static final String PASSWORD = "PASSWORD";
private EditText field_name; //接收用户名的组件
private EditText filed_pass; //接收密码的组件
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Find VIew
field_name = (EditText) findViewById(R.id.name); //首先获取用来输入用户名的组件
filed_pass = (EditText) findViewById(R.id.password); //同时也需要获取输入密码的组件
// Restore preferences
SharedPreferences settings = getSharedPreferences(SETTING_INFOS, 0); //获取一个SharedPreferences对象
String name = settings.getString(NAME, ""); //取出保存的NAME
String password = settings.getString(PASSWORD, ""); //取出保存的PASSWORD
//Set value
field_name.setText(name); //将取出来的用户名赋予field_name
filed_pass.setText(password); //将取出来的密码赋予filed_pass
}
@Override
protected void onStop(){
super.onStop();
SharedPreferences settings = getSharedPreferences(SETTING_INFOS, 0); //首先获取一个SharedPreferences对象
settings.edit()
.putString(NAME, field_name.getText().toString())
.putString(PASSWORD, filed_pass.getText().toString())
.commit();
} //将用户名和密码保存进去
SharedPreferences是以XML的格式以文件的方式自动保存的,在DDMS中的File Explorer中展开到/data/data/<package name>/shared_prefs下,以上面这个为例,可以看到一个叫做SETTING_Infos.xml的文件。
SharedPrefreences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是它也有自身的缺陷,譬如其只能存储boolean,int,float,long和String五种简单的数据类型,无法进行条件查询等。所以不论它的数据存储操作是如何简单,也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。
注意:Preferences只能在同一个包内使用,不能在不同的包之间使用。
context提供了两份方法来打开数据文件里的文件IO流,分别是FileInputStream.openFileInput(String name)和openFileOutput(String name,int mode)。
这两个方法第一个参数用于指定文件名,第二个参数指定打开文件的模式。打开文件模式有以下几种:
MODE_PRIVATE:默认的操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原有的内容。
MODE_APPEND:追加模式,此时会先检查文件是否存在,存在就往文件中追加,否则就创建新文件。
MODE_WORLD_READABLE:读取模式,表示当前文件可以被其他应用读取。
MODE_WORLD_WRITEABLE:写入模式,表示当前文件可以被其他应用写入。
除了这两个方法之外,Context还提供了如下几个重要的方法:
getDir(String name,int mode):在应用程序的数据文件夹下获取或者创建name对应的子目录。
File.getFilesDir():获取该应用程序的数据文件夹的绝对路径。
String[ ] fileList():返回该数据文件夹的全部文件。
下面给出一个实际的小案例:
布局界面就一个EditText和两个Button按钮,负责文件的读写功能。简单布局,代码依然省略了,只看核心代码。
/**文件的读取功能*/
public String read() {
try {
FileInputStream inStream = this.openFileInput("message.txt");
byte[] buffer = new byte[1024];
int hasRead = 0;
StringBuilder sb = new StringBuilder();
while ((hasRead = inStream.read(buffer)) != -1) {
sb.append(new String(buffer, 0, hasRead));
}
/**文件的IO流在使用结束后一定要关闭*/
inStream.close();
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**文件的写入功能*/
public void write(String msg){
// 步骤1:获取输入值
if(msg == null) return;
try {
// 步骤2:创建一个FileOutputStream对象,MODE_APPEND追加模式
FileOutputStream fos = openFileOutput("message.txt",
MODE_APPEND);
// 步骤3:将获取过来的值放入文件
fos.write(msg.getBytes());
// 步骤4:关闭数据流
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
两个方法的第一参数用于指定文件名称,不能包含路径分隔符“/”。
要注意的一点就是,在读写的文件位于sdcard上时,就麻烦了很多。
首先要判断手机上是否存在sd卡,Environment.getExternalStorageState()方法进行判断。并且应用程序要具有读写SD卡的权限,如下:
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
案列如下:
// 文件写操作函数
private void write(String content) {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) { // 如果sdcard存在
File file = new File(Environment.getExternalStorageDirectory()
.toString()+ File.separator+ DIR + File.separator
+ FILENAME); // 定义File类对象
if (!file.getParentFile().exists()) { // 父文件夹不存在
file.getParentFile().mkdirs(); // 创建文件夹
}
PrintStream out = null; // 打印流对象用于输出
try {
out = new PrintStream(new FileOutputStream(file, true)); // 追加文件
out.println(content);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close(); // 关闭打印流
}
}
} else { // SDCard不存在,使用Toast提示用户
Toast.makeText(this, "保存失败,SD卡不存在!", Toast.LENGTH_LONG).show();
}
}
// 文件读操作函数
private String read() {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) { // 如果sdcard存在
File file = new File(Environment.getExternalStorageDirectory()
.toString()
+ File.separator
+ DIR
+ File.separator
+ FILENAME); // 定义File类对象
if (!file.getParentFile().exists()) { // 父文件夹不存在
file.getParentFile().mkdirs(); // 创建文件夹
}
Scanner scan = null; // 扫描输入
StringBuilder sb = new StringBuilder();
try {
scan = new Scanner(new FileInputStream(file)); // 实例化Scanner
while (scan.hasNext()) { // 循环读取
sb.append(scan.next() + "\n"); // 设置文本
}
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (scan != null) {
scan.close(); // 关闭打印流
}
}
} else { // SDCard不存在,使用Toast提示用户
Toast.makeText(this, "读取失败,SD卡不存在!", Toast.LENGTH_LONG).show();
}
return null;
}
3.SQLite存储数据
SQLite是Google为Andorid提供的一款轻量级的关系型数据库系统,它支持SQL语言,在数据存储、管理、维护等各方面都相当出色,功能也非常的强大。
SQLite具备六大特点:
1.轻量级
使用 SQLite 只需要带一个动态库,就可以享受它的全部功能,而且那个动态库的尺寸想当小。
2.独立性
SQLite 数据库的核心引擎不需要依赖第三方软件,也不需要所谓的“安装”。
3.隔离性
SQLite 数据库中所有的信息(比如表、视图、触发器等)都包含在一个文件夹内,方便管理和维护。
4.跨平台
SQLite 目前支持大部分操作系统,不至电脑操作系统更在众多的手机系统也是能够运行,比如:Android。
5.多语言接口
SQLite 数据库支持多语言编程接口。
6.安全性
SQLite 数据库通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只能有一个可以写入数据。
SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类型是什么。例如:可以在Integer类型的字段中存放字符串,或者在Boolean类型的字段中存放浮点数,或者在String类型字段中存放日期型值。
SQLiteDatabase类为我们提供了很多方法,实现对数据库数据的添加、更新和删除。
//执行SQL语句
1 SQLiteDatabase.executeSQL(String sql);
2 SQLiteDatabase.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集
除了统一的形式外,他们还有各自的操作方法:
db.insert(String table, String nullColumnHack, ContentValues values);
db.update(String table, Contentvalues values, String whereClause, String whereArgs);
db.delete(String table, String whereClause, String whereArgs);
这三个方法的第一个参数表示要操作的表名;
insert方法中的第二个参数表示如果插入的数据每一列都为空的话,需要指定此行中某一列的名称,系统将此列设置为NULL,不至于出现错误,第三个参数是ContentValues类型的变量,是键值对组成的Map。Key代表列名,value代表该列要插入的值;
update方法的第二个参数跟insert方法很类似,只不过它是更新该字段key为最新的value值,第三个参数whereClause表示WHERE表达式,譬如“age>?and age<?”等,最后的whereArgs参数是占位符的实际参数值;
delete方法的参数跟update的三四参数一样。
数据的添加
1.使用insert方法
ContentValues cv = new ContentValues();//实例化一个ContentValues用来装载待插入的数据
cv.put("title","you are beautiful");//添加title
cv.put("weather","sun"); //添加weather
cv.put("context","xxxx"); //添加context
String publish = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
cv.put("publish ",publish); //添加publish
db.insert("diary",null,cv);//执行插入操作
String whereClause = "username=?";//删除的条件
String[] whereArgs = {"Jack Johnson"};//删除的条件参数
db.delete("user",whereClause,whereArgs);//执行删除
String sql = "insert into user(username,password) values ('Jack Johnson','iLovePopMuisc');//插入操作的SQL语句
db.execSQL(sql);//执行SQL语句
1.使用delete方法
String whereClause = "username=?";//删除的条件
String[] whereArgs = {"Jack Johnson"};//删除的条件参数
db.delete("user",whereClause,whereArgs);//执行删除
2.使用execSQL方式来实现
String sql = "delete from user where username='Jack Johnson'";//删除操作的SQL语句
db.execSQL(sql);//执行删除操作
1.使用update方法
ContentValues cv = new ContentValues();//实例化ContentValues
cv.put("password","iHatePopMusic");//添加要更改的字段及内容
String whereClause = "username=?";//修改条件
String[] whereArgs = {"Jack Johnson"};//修改条件的参数
db.update("user",cv,whereClause,whereArgs);//执行修改
2.使用execSQL方式的实现
String sql = "update user set password = 'iHatePopMusic' where username='Jack Johnson'";//修改的SQL语句
db.execSQL(sql);//执行修改
数据的查询
接来下说一下数据查询,相对于增删改要复杂些,我们经常面对各种各样的查询条件,系统提供了较丰富的查询形式。
db.rawQuery(String sql, String[] selectionArgs);
db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy);
db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);
db.query(String distinct, String table, String[] columns, String selection, String[] selectionArgs,
String groupBy, String having, String orderBy, String limit);
上面几种都是常用的查询方法, 各个参数分别代表的是:
selectionArgs条件语句的参数数组,table表名称,colums要查询的列的名称集,selection代表WHERE之后的条件语句,可以使用占位符,groupBy指定分组的列名,having指定分组条件,配合groupBy使用,orderBy指定排序的列名,limit指定分页参数,distinct指定“true”或“false”表示要不要过滤重复值
查询方法会返回一个Cursor对象,代表数据集的游标,Cursor也提供了一系列的方法,如下:
c.move(int offset); //以当前位置为参考,移动到指定行
c.moveToFirst(); //移动到第一行
c.moveToLast(); //移动到最后一行
c.moveToPosition(int position); //移动到指定行
c.moveToPrevious(); //移动到前一行
c.moveToNext(); //移动到下一行
c.isFirst(); //是否指向第一条
c.isLast(); //是否指向最后一条
c.isBeforeFirst(); //是否指向第一条之前
c.isAfterLast(); //是否指向最后一条之后
c.isNull(int columnIndex); //指定列是否为空(列基数为0)
c.isClosed(); //游标是否已关闭
c.getCount(); //总数据项数
c.getPosition(); //返回当前游标所指向的行数
c.getColumnIndex(String columnName);//返回某列名对应的列索引值
c.getString(int columnIndex); //返回当前行指定列的值
下面是查询数据的一个简单的案例:
String[] params = {12345,123456};
Cursor cursor = db.query("user",columns,"ID=?",params,null,null,null);//查询并获得游标
if(cursor.moveToFirst()){//判断游标是否为空
for(int i=0;i<cursor.getCount();i++){
cursor.move(i);//移动到指定记录
String username = cursor.getString(cursor.getColumnIndex("username");
String password = cursor.getString(cursor.getColumnIndex("password"));
}
}
然后我们再通过rawQuery方法实现一下带参数的查询:
Cursor result=db.rawQuery("SELECT ID, name, inventory FROM mytable");
//Cursor c = db.rawQuery("s name, inventory FROM mytable where ID=?",new Stirng[]{"123456"});
result.moveToFirst();
while (!result.isAfterLast()) {
int id=result.getInt(0);
String name=result.getString(1);
int inventory=result.getInt(2);
// do something useful with these
result.moveToNext();
} result.close();
注意:当我们完成了对数据库的操作后,记得调用SQLiteDatebase的close()方法释放数据库连接,否则容易出现SQLiteException
4.内容提供器(Content Provider)
Content Provider是android的四大组件之一,主要用于在不同的程序之间实现数据的共享,一个程序可以通过实现Content Provider的抽象借口将自己的数据暴露出去。外界的程序需要通过ContentResolver接口访问ContentProvider提供的数据。在Activity中通过getContentResolver()可以得到当前应用的ContentResolver对象。Android提供了一些已经在系统中实现的标准的ContentProvider,譬如联系人信息,图片库等等,可以直接使用它访问设备上存储的联系人信息、图片等。ContentProvider和ContentResolver提供了一致的接口,供用户进行增删改查功能。如下:
query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder);//通过Uri进行查询,返回一个Cursor。
insert(Uri url, ContentValues values);//将一组数据插入到Uri 指定的地方。
update(Uri uri, ContentValues values, String where, String[] selectionArgs);//更新Uri指定位置的数据。
delete(Uri url, String where, String[] selectionArgs);//删除指定Uri并且符合一定条件的数据。
ContentProvider统一了数据的访问方式,使用的查询字符串有别于标准的SQL查询,它使用了特殊的Uri进行访问,Uri是由三部分组成“content://”+数据的路径+资源标识ID(可选),其中如果存在ID,就表示某一个具体的资源,否则就标识路径下的整体。
下面来进行一个案列的演示,首先是在一个程序中继承ContentProvider类,将共享的数据存储在ContentProvider中,核心代码如下:
//在Create中初始化一个数据库
@Override
public boolean onCreate() {
SQLiteDatabase db = this.getContext().openOrCreateDatabase("test_db.db3", Context.MODE_PRIVATE, null);
db.execSQL("create table tab(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)");
ContentValues values = new ContentValues();
values.put("name", "test");
db.insert("tab", "_id", values);
db.close();
return true;
}
//实现query方法
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = this.getContext().openOrCreateDatabase("test_db.db3", Context.MODE_PRIVATE, null);
Cursor c = db.query("tab", null, null, null, null, null,null);
return c;
}
由于它是android的四大组件之一,需要在AndroidManifest.xml中声明,然后声明authorities属性定义此ContentProvider的Uri标识<provider android:name=".MyProvider" android:authorities="com.test.MyProvider"/>
然后在另一个应用程序中,通过ContentResolver获取第一个程序的ContentProvider中的数据:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//获取上下文
Context ctx = MainActivity.this;
//获取ContentResolver对象
ContentResolver resolver = ctx.getContentResolver();
//获取Uri对象
Uri uri = Uri.parse("content://com.test.MyProvider");
//获取数据
Cursor c = resolver.query(uri, null, null, null, null);
c.moveToFirst();
for(int i=0; i<c.getCount(); i++){
int index = c.getColumnIndexOrThrow("name");
String src = c.getString(index);
Log.d("", src);
c.moveToNext();
}
}
5.网络存储方式
Android中的网络存储方式与android网络数据包息息相关,我们的android SDK是基于Java的,HttpUrlConnection是Java.NET包中提供的API,是我们访问网络的最原始最基本的API。我们一般使用HttpUrlConnection需要几个步骤:
1.将访问的路径字符串转换成URL:
URL url=new URL(path);
2.通过URL获取连接:
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
3.设置请求方式:(http的网络请求方式下面再介绍)
conn.setRequestMethod(GET);
conn.setConnectTimeout(5000);
conn.setRequestProperty(User-Agent, Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0));
提供一个封装好的工具类:
public class MyStreamUtils {
/**
* 将输入流转换成字符串
*
* @param is
* 从网络获取的输入流
* @return
*/
public static String streamToString(InputStream is) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
baos.close();
is.close();
byte[] byteArray = baos.toByteArray();
return new String(byteArray);
} catch (Exception e) {
Log.e(tag, e.toString());
return null;
}
}
}
在HttpUrlConnection中有两种常用的请求方式,分别是GET和POST。它的默认是GET方式。
GET方式是从指定的服务器中获取数据,它的请求能够被缓存,所以即使点击了后退按钮或者是刷新按钮,都不会有太大的影响。GET请求会保留在浏览器历史记录中,也可被收藏为书签,但不应在处理敏感数据时使用,而且请求有长度限制。
POST方式是向指定的资源提交要被处理的数据,它跟GET是相反的。POST请求不会被缓存,所以如果点击了后退或者是刷新按钮,数据会被重新提交。POST请求不会保留在浏览器历史记录中,不能被收藏为书签,POST请求对数据长度没有要求。
首先是HttpUrlConnection发送GET请求:
public static String loginByGet(String username, String password) {
String path = http://192.168.0.107:8080/WebTest/LoginServerlet?username= + username + &password= + password;
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod(GET);
int code = conn.getResponseCode();
if (code == 200) {
InputStream is = conn.getInputStream();
return MyStreamUtils.streamToString(is);// 字节流转换成字符串
} else {
return 网络访问失败;
}
} catch (Exception e) {
e.printStackTrace();
return 网络访问失败;
}
}
HttpUrlConnection发送POST请求:
public static String loginByPost(String username, String password) {
String path = http://192.168.0.107:8080/WebTest/LoginServerlet;
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod(POST);
conn.setRequestProperty(Content-Type, application/x-www-form-urlencoded);
String data = username= + username + &password= + password;
conn.setRequestProperty(Content-Length, data.length() + );
// POST方式,其实就是浏览器把数据写给服务器
conn.setDoOutput(true); // 设置可输出流
OutputStream os = conn.getOutputStream(); // 获取输出流
os.write(data.getBytes()); // 将数据写给服务器
int code = conn.getResponseCode();
if (code == 200) {
InputStream is = conn.getInputStream();
return MyStreamUtils.streamToString(is);
} else {
return 网络访问失败;
}
} catch (Exception e) {
e.printStackTrace();
return 网络访问失败;
}
}
由于HttpClient的API数量过多,使得我们很难在不破坏兼容性的情况下对它进行升级和扩展,所以目前Android团队在提升和优化HttpClient方面的工作态度并不积极。然后我就也偷懒了,对httpClient没怎么关注,只是知道有这么个请求就是了。。。。。
至此,关于Android的一些基础知识整理完毕了,后续就是要多跟那些大大们学习第三方框架了,还有源码的解读以及android的性能优化,任重而道远,皮皮虾,我们走。