《第一行代码》读书笔记
摘要:
主要内容:
对书上的重点和难点内容进行总结和回顾;
任务列表:
- 优化文档结构(2016.05.26)
第二章
每一次学习 , 都会有新的收获;
我相信我看到的奇迹,没有是平白无故产生的,它们是源于环环相扣的逻辑巧妙组合而成。
隐藏标题栏(p35)
在调用 setContentView()之前,写上下面代码:requestWindowFeature(Window.FEATURE_NO_TITLE);
========== 更新 2016.05.23 10:42:53 =============
也可以通过配置主题的方式应用到所有 Activity 中:
在AppTheme
中添加:
1 | <item name="android:windowNoTitle">true</item> |
隐式 Intent(p44)
隐式里的 category 和 data 就像是更精确的过滤器
保存临时数据 (p67)
当启动新的活动时,当前的活动数据如果不加以保存,那么就会有可能丢失掉数据(系统回收)。
这样的用户体验不好,可以通过在onSaveInstanceState()
方法中保存数据来解决这个问题。(重要的数据还是在 onPause 中保存的好,在 onPause 中不要进行耗时操作)
相应的,在onCreate(Bundle)
中进行恢复操作。
活动启动模式(p68)
使用方式:在 Manifest.xml 的对应 activity 中添加android:launchMode="standard|singleTop|singleTask|singleInstance"
参数说明:
- standard 模式:无论返回栈中是否存在该活动,每次启动都会创建一个新的实例(例如,自己启动自己,也会创建多个实例出来)
- singleTop 模式:如果返回栈的栈顶是要启动的活动,则直接使用它,而不是再创建一个新的活动实例出来。
- singleTask 模式:使该活动在整个应用程序的上下文中只存在一个实例,如果不在栈顶,则将该活动上面的所有活动出栈,如果没有该活动,则创建一个活动实例。
- singleInstance 模式:指定为该模式的活动就启用新的返回栈来管理这个活动。(还不是很了解)
技巧:
进入某个界面在日志中打印对应的 Activity 的名称(方便定位) (p77):
原理: 简单来说是通过 java 的重写机制 。
具体步骤:
- 创建一个基类 Activity,例如
BaseActivity
; - 在基类 Activity 的 onCreate()方法中,添加代码
Log.d("BaseActivity", getClass().getSimpleName())
随时随地退出程序(p78):
利用 List 作为保存 Activity 的容器:一旦有 Activity 被创建,就加入到容器中;对应的,一旦 Activity 被销毁,就从容器中移除 。在想要退出的地方,逐个结束容器中的 Activity. activity.finish()
参考网址: 2.6.2 随时随地退出程序
启动活动(p80):
给 Activity 添加一个封装优美的,静态的,清晰的启动方法。
步骤:
- 在 Activity 中定义一个静态的方法
1 | private static String mArg0; |
- 在需要启动 SecondActivity 的地方调用:
1 | SecondActivity.startActivity(mContext, arg0, arg1); |
第三章
从整体到局部,从构架到细节。
宽度,高度(p84)
match_parent:表示让当前控件的大小和父控件的大小一样
fill_parent:match_parent 的别名
wrap_content:使当前控件的大小正好包含住控件的内容(文字,图片 ) 等。
控件可见性(p98)
在 xml 布局中控制:
为控件添加属性(所有控件均支持),android:visibility="visible|invisible|gone"
visible 或者不写:可见,占空间
invisible:不可见,占空间(透明状态)
gone:不可见,不占空间
Java 代码中控制:
动态控制可见性:View.setVisibility(View.VISIBLE|View.INVISIBLE|View.GONE)
效果同 xml
另外,可以通过getVisibility()
方法获取当前的控件状态,根据比较的结果,可以做一些特定的操作;
1 | View view = findViewById(R.id.tv_main); |
LinearLayout 重要属性说明(p105)
- android:orientation=”vertical|horizontal”;控制 LinearLayout 的排列方向 (该属性用在 LinearLayout 本身上)
- android:layout_gravity=”left|right|top|bottom|center_vertical|center_horizontal”;控件在父控件中的对齐方式。(该属性用在 LinearLayout 的子控件中)
- android:layout_weight=”1”;通过比例的方式控制控件的大小。 (该属性用在 LinearLayout 的子控件中,剩余空间按比例分配。适配方案还得靠它)
易混淆的属性(p107)android:layout_gravity
和android:gravity
属性区别:
android:layout_gravity
属性:用于指定该控件在父控件中的对齐方式(可选值:top|bottom|left|right|center|center_vertical|center_horizontal
)android:gravity
属性:用于指定控件中的内容在控件中的对齐方式( 可选值:top|bottom|left|right|center|center_vertical|center_horizontal
)- 注意:layout_gravity,当父控件 LinearLayout 排列方向是 horizontal 时,
只有垂直方向的对齐方式才会生效(bottom, top, center_vertical);
当父控件 LinearLayout 排列方向是 vertical 时,只有水平方向的对齐方式才会生效(left,right,center_horizontal)
RelaviteLayout 布局
相对于父布局进行定位:
- android:layout_alignParentTop=”true”
- android:layout_alignParentBottom=”true”
- android:layout_alignParentLeft=”true”
- android:layout_alignParentRight=”true”
- android:layout_centerInParent=”true”
相对于其他控件进行布局:
- android:layout_above=”@id/view3”
- android:layout_below=”@id/view3”
- android:layout_toRightOf=”@id/view3”
- android:layout_toLeftOf=”@id/view3”
相对于其他控件的边缘进行对齐显示:
- android:layout_alignRight= “@id/view3”
- android:layout_alignLeft= “@id/view3”
- android:layout_alignTop= “@id/view3”
- android:layout_alignBottom= “@id/view3”
其他:
- android:layout_centerVertical=”true”
- android:layout_centerHorizontal=”true”
注意 1:通过@id/tv_view
引用的控件一定要先定义;而通过@+id/tv_view
引用的控件也可以出现在后面。
注意 2:可以在一个控件中使用上面的一个或多个。例如,相对于父布局的“左上”布局,
就需要填写两个属性android:layout_alignParentTop="true";android:layout_alignParentLeft="true"
。
TableLayout 布局
- TableLayout 中的每一个 TableRow 都表示表格中的一行,每一个子控件表示一列。
- TableRow 中的控件不可以指定宽度。
- 在 TableLayout 中添加属性:
android:stretchColumns="1"
,使指定的那一列拉伸,以自动适应屏幕的宽度。(0 表示第一列,1 表示第二列)android:shrinkColumns="0"
,收缩指定的列;android:collapseColumns="0"
,隐藏指定的列;
其他布局
- FrameLayout 布局
(所有控件默认摆放在左上角;多个子控件情况下下面的控件覆盖上面的控件;可通过 gravity 和 layout_gravity 来控制子控件的对齐方式) - AbsoluteLayout 布局(不推荐使用)
ListView 控件(p127)
需要的元素:
- 数据源
- 单个 item 的 layout 布局
- 适配器(简单的名称显示可继承自 ArrayAdapter,更丰富的布局可继承自 BaseAdapter)
**优化 **
- 利用 android 自带的缓存机制,convertView;
- 使用 ViewHolder 和 Tag;每一个 View 都可以存储一个 Tag 对象(看源码 mTag),对控件对应的实体进行缓存。当需要实体的时候,从 tag 中获取;
- 推荐阅读:【Android】通用系列 —— 用简单通用的方式操作 ListView
其他补充:
- 为 listview 绑定适配器:lv.setAdapter(mAdapter);
- 数据发生变化,要及时更新界面:mAdapter.notifyDataSetChanged();
- 定位到某一项(即在屏幕上显示这一项):lv.setSelection(num);
- 点击事件:setOnItemClickListener(OnItemClickListener ocl);
- 给 ListView 项的分割线设置为透明色:android:divider=”@null”
- 不显示滚动条:
android:scrollbars="none"
- 平滑滚动到指定条目:
mLv.smoothScrollToPosition(pItem);
- 设置 ListView 不可用:
mLv.setEnable(false)
- 设置 listView 不可滑动(可以通过拦截触摸事件,和
mLv.setEnable(false)
达到的效果不同):
1 | public static void setListViewCannotSlide(ListView lv) { |
- 点击效果:设置 listSelector 和设置 item 的 layout 两种方式。(最好不要混用,推荐使用第二种方式)
- 取消点击效果:
andrdoi:listSelector="@android:color/transparent"
- 动态取消点击效果:
mLv.setSelector(new ColorDrawable(Color.TRANSPARENT));
- 动态设置点击效果:
mLv.setSelector(R.drawable.item_selector);
外部链接
第四章 Fragment 碎片
第一遍:不知道自己不知道。
第二遍:知道自己不知道,或不知道自己知道。
第三遍:知道自己知道。
简而言之,碎片(Fragment)是一种可以嵌入在活动当中的 UI 片段,它能让程序更加合理和充分地利用大屏幕空间。
学习资料:
- Android Fragment 完全解析,关于碎片你所需知道的一切
- Android Fragment 真正的完全解析(上)
- [Android Fragment 真正的完全解析(下)]
- Android Fragment 你应该知道的一切
要点难点:
- 通信–数据传递。
- 抽象成一个公用的类。
- 回退栈(remove,add,hide,show 等方法的区别)
- 屏幕适配:限定符;
- 双页单页模式(p182)
第五章 广播机制
注册广播:
1. 动态注册 (p190)
新建一个类,继承 BroadcastReceiver,重写父类的 onReceive 方法。
自定义的 MainActivity 中通过 Context 的registerReceiver(BroadCastReceiver bc,IntentFilter if)
方法来注册 。
说明:其中参数 bc 是刚才新建类的实例,参数 if 是广播发送过来的 action 值包装成 IntentFilter 对象。
注意: 用完之后需要销毁,在 activity 的 onDestroy()方法中调用 unregisterReceiver()方法。
注意: 当访问的内容涉及到系统的关键性信息,那么需要在配置文件中配置相应的权限 permission ( http://developer.android.com/reference/android/Manifest.permission.html)。
注意: 应用程序发送的广播是可以被其他应用程序接收到的。跨进程通信。
2. 静态注册
- 创建一个集成自 BroadCast 的类,并重写 onReceive()方法
- 类似于 activity 的注册,使用
标签,使用 android:name 来指定刚才创建的广播接收器(即实现了 BroadCast 的类的实例) - 在
标签中添加想要接收的广播。
另外: 使用静态注册可以达到开机启动的目的。静态注册在程序未启动的时候也可以接收广播。
注意: 监听某些广播也是需要声明权限的。
注意: 不要在 onReceive()中添加过多的逻辑或者任何的耗时操作,因为在广播接收器中是不允许开启线程的(如果运行时间较长,程序会报错)。
应用场合: 启动其他组件,例如创建一条状态栏通知,或启动一个服务等。
发送广播
标准广播
例如在 MainActivity 中点击按钮时发送广播:
1 | Intent intent = new Intent("com.lyloou.broadcasttest.MY_BROADCAST");//还可以绑定一些数据到Intent中供接收者使用; |
有序广播
- 区别于标准广播的
sendBroadcast(Intent intent)
, 有序广播是sendOrderedBroadcast(Intent intent, String receiverPermission )
。 (可以参考 Context 的 API 文档看更详细内容) - 广播接收器的先后顺序,是通过在注册的时候设定的。例如,
<intent-filter android:priority="100">
。 - 有序广播是可以截断的。在 onRecevie()中调用
abortBroadcast();
方法将广播截断,后续的接收器就无法接收到该条广播。
(only works with broadcasts sent through Context.sendOrderedBroadcast.
)
本地广播(p202)
- 区别于一般的广播,本地广播只允许本应用程序接收本应用程序发送的广播,解决了广播的安全性问题。
其他程序的广播无法发送到我们程序的内部,更安全。比全局广播更高效。 - 与一般的广播的动态注册方式类似。(一般广播,这里指的是全局广播)
- 区别于一般广播的接收方式
registerReceiver()
,本地广播使用:
1 | LocalBroadcastManager localBroadCastManager = LocalBroadcastManager.getInstance(Context c); |
- 区别于一般广播的发送方式
sendBroadcast(intent)
,本地广播使用:localBroadCastManager.sendBroadcast(intent)
- 注意:也需要 unregister 进行注销处理。
- 注意:本地广播无法通过静态方式注册接收, 静态注册在程序未启动的时候也可以接收广播,而本地广播肯定是在启动程序之后发送,所以不需要静态注册 。
- 注意:不可以混用系统广播和本地广播,(例如通过 localBroadCastManager.registerReceiver 来注册蓝牙广播,是不对的,
如果非得这样做,onReceiver 中将无法接收到蓝牙开启和关闭的广播)
其他
在广播接收器写一个弹框(p210)。
从广播接收器中启动活动需要注意的内容(p211):给 Intent 加入 FLAG_ACTIVITY_NEW_TASK 标识。
第六章 数据存储
持久化的方式
- 文件存储:存储简单的文本数据和二进制数据。
- SharePreference 存储 :存储的是键值对。
- 数据库–SQLITE: 存储复杂关系型的数据。
文件存储(p221)
核心方法:Context 提供的 openFileInput()和 openFileOutput()方法;
注意:不适用于存储复杂类型的数据。
SharePreference 存储(p228)
使用键值对的方式存储。
使用 xml 格式来对数据进行管理。
获取 SharePreference(下面三种方法不同之处在于参数和存储地址)
- Context 类中的 getSharedPreference(String filename, MODE_PRIVATE|MODE_MULTI_PROCESS),
在系统中的具体表现:/data/data/<package name>/shared_prefs/filename参数名
- Activity 类中的 getPreference(MODE_PRIVATE|MODE_MULTI_PROCESS),文件名以当前活动的类名起名。
- PreferenceManager 类中的 getDefaultSharedPreference( MODE_PRIVATE|MODE_MULTI_PROCESS ),文件名以包名起名。
- Context 类中的 getSharedPreference(String filename, MODE_PRIVATE|MODE_MULTI_PROCESS),
保存数据步骤:
- 通过获取到的 SharePreference 对象实例 sp,引用其 edit()方法,
SharedPreferences.Editor editor = sp.edit();
- editor.putInt(“age”,18);
- editor.putString(“name”,”Bob”);
- …
- editor.commit();
- 通过获取到的 SharePreference 对象实例 sp,引用其 edit()方法,
获取数据步骤:
- 同样首先获取到 SharePreference 对象实例 sp;
- int age = sp.getInt(“age”, 0);
- String name = sp.getString(“name”, “”);
- …
- 获取到数据后的其他操作。
数据库(SQLITE-p238)
- 创建一个 继承自 SQLiteOpenHelper 类的帮助类,重写 onCreate()和 onUpgrate()方法,在这两个方法中实现创建表和升级数据库的逻辑。
- 通过帮助类获取实例:getReadableDatabase()和 getWritableDatabase()方法获取实例。两者的区别是前者在磁盘满的时候以只读方式打开数据库,而后者直接抛出异常。
- 通过 db.execSQL()可以直接执行数据库语句。
- 事务保证数据安全:进行读写操作,要使用事务(读数据就不需要事务了);
- 数据库创建后,将不再重新创建,这意味着在客户端,
onCreate()
方法只执行一次。 除非卸载掉重新安装,
如果是覆盖安装的话,修改了了数据库结构,就要通过onUpgrade()
方法来控制了。
CRUD – 添加数据
利用 ContentValues 组件一组数据,通过 insert 来添加到数据库中。
ContentValues 利用键值的方式添加:,
1 | ContentValues contentValues = new ContentValues(); |
CRUD – 更改数据
利用 ContentValues 组件一组数据,通过 update 来添加到数据库中。
ContentValues 利用键值的方式更新:,
1 | ContentValues contentValues = new ContentValues(); |
CRUD – 删除数据
获取到 db 实例后,即可执行删除操作
1 | SQLiteDatabase db = dbHelper.getWritableDatabase(); |
CRUD – 查询数据
利用 db 的 query 方法来得到一个 Cursor 实例。对 Cursor 进行取值操作,即可得到想要的值。
cursor.moveToFirst(); 指针移动到第一行;
cursor.moveToNext(); 指针移动到下一个;
1 | Cursor cursor = db.query("Book", null , null , null , null , null , null ); |
技巧: 利用 switch 来优化数据库升级(p264)。
第七章 内容提供器(p268)
首先作为一个客户端程序员,来使用 API,接着创建自己的 API;
内容提供器主要用于在不同的应用程序之间实现数据共享,目前内容提供器是 Android 实现跨程序共享数据的标准方式。
ContentProvider 比起文件和 SharedPreference 的 MODE_WORLD_READABLE 和 MODE_WORLD_WRITEABLE 两种操作模式要更安全可靠。
因为你只提供想要给其他程序访问的数据,其他数据就不会有任何影响。ContentResolver 对象获取方式:‘’以通过 Context 的 getContentResolver()来获取。
ContentResolver 提供的一些方法进行 CRUD 操作。
(基本类似于数据库的 CRUD,最明显的区别就是:
数据库中的 CRUD 方法传入的参数是 表名,而 ContentResolver 中的传入的参数是 Uri,
对应的继承自 ContentProvider 的自定义内容提供器里面的 CRUD 方法设置的参数也是 Uri。)内容提供器的用法有两种:
- 使用现有的提供器来读取和操作某程序的数据。(作为客户端)
- 自己创建 ContentProvider 给自己的程序或其他程序提供外部访问接口,以供其读取和操作数据。(客户端和 API 端都有)
Uri:区别于 SQLiteDatabase 接受的参数
table
,ContentResolver 接受的参数是“URI”,
要对某程序的数据进行读取和操作,需要制定其Uri
。URI 格式:由两部分组成,权限 authority 和路径 path(p269) + 通配符的使用 (p277)
UriMatcher 的使用(p279)
Uri 的 getPathSegments()方法可以将字符串按照“/”分割成字符串列表,通过 get(0)这种方式访问列表中的字符串。
所有内容提供者必须提供的方法(getType()),getType()方法的实现,用于获取 Uri 对象所对应的 MIME 类型;(p280)
自定义的 ContentProvider 需要注册到 Manifest 中(p286)。
注意: 在每次创建内容提供者的时候,都要提醒自己,是不是真的需要这样做。
因为只有真正需要将数据共享出去的时候我们才应该创建内容提供器,
仅仅是用于内部程序访问的数据没必要使用内容提供者。
Lou: ContentProvider 扮演的是程序和程序之间数据传递的桥梁角色。
A 程序规定好自己的哪些数据内容可以访问,并设置好对应的 Uri,
B 程序借助 ContentProvider 提供器传入 A 程序规定好的 Uri 来读取和操作 A 程序的数据。
在 ContentProvider 中操作数据库,
就好像是 ContentProvider 提供了一个包装,
在其内根据传入的 Uri 来进行具体的数据库操作,
对外只需要提供一个接口即可(接口需要有正确的参数,例如 Uri、过滤条件等)。
第八章 多媒体
通知
使用步骤:
- 得到 manager:
NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
- 得到 notification 实例:
Notification notification = new Notification(R.drawable.ic_launcher, "This is ticker text", System.currentTimeMillis());
- 设置通知里的布局:
notification.setLatesEventInfor(this, "This is content title", "This is content text", null);
,
其中第四个参数是用来设置点击通知触发的逻辑,用 PendingIntent 来设定。 - 利用 manager 发出通知:
manager.notify(1, notification);
,其中 1 是该通知的唯一标志,可以用于之后的取消。
取消通知栏的通知
1 | NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); |
通知栏点击事件处理
使用 PendingIntent(p302)
- 被延迟执行的 Intent。(Intent 倾向于立即执行某个动作,PendingIntent 倾向于在某个合适的时机去执行某个动作)
- 通过 getActivity(),或 getBroadCast(),或 getService()来获取 PendingIntent 实例,
PendingIntent 结合第二个参数 Intent 来构建出“意图”,当被点击时执行相应的逻辑。 (p302) 1. 如果使用的是 getActivity(),那么就执行 startActivity(intent); 其中 intent:Intent intent = new Intent(getActivity(), MyActivity.class)
,指定其目标 Activity。 2. 如果使用的是 getBroadCast(),那么就调用 sendBroadCast(intent); 其中 intent:Intent intent = new Intent("com.example.broadcasttext.MY_BROADCAST")
,指定其 action。 3. 如果使用的是 getService(),那么就调用 startService(intent);其中 intent:Intent intent = new Intent(getActivity(), MyService.class)
,指定目标 service。 - 将得到的实例作为
notification.setLatesEvenInfor()
的第四个参数以实现点击通知的逻辑(启动一个 Activity、发送一条广播、启动某个服务等等 )。
通知的交互处理(p305)
- 添加声音:
1 | Uri soundUri = Uri.fromFile(new File("/system/media/audio/ringtones/Basic_tone.ogg")); |
- 添加振动:
1 | long[] vibrates = {0, 1000, 1000, 1000}; |
- 添加 LED 通知
1 | notification.ledARGB = Color.GREEN; |
- 设置默认通知类型:
1 | notification.defaults = Notification.DEFAUT_ALL |
- 扩展:
点亮屏幕
第九章 服务
多线程编程
子线程中不允许进行 UI 操作。
异步消息处理机制:
- handler
- AsyncTask
- Activity.runOnUIThread(Runnable runnable)
- IntentService
Handler(p348)
- 在主线程中创建 Handler 实例,并重写 handMessage()方法。
- 在子线程中通过 handler 发送消息(
handler.sendMessage(msg);
) - msg 会被添加到 MessageQueue 等待处理。
- Looper 不断的监测 MessageQueue 中是否有 Message,如果有那么就取出来分发到 handler 的 handleMessage()方法中处理。
- 在 handler.handleMessage()方法中进行 UI 操作。
AsyncTask(p349)
AsyncTask 是一个抽象类,需要去继承才能用。
三个泛型参数
- Params:执行 AsyncTask 任务需要的参数(例如进行网络操作的 URL 字符串);
- Progress:后台执行任务的百分比;
- Result:任务的执行完成后的返回值(例如 Bitmap)
常用的方法(重写)
- onPreExecute(),任务执行之前的初始化操作(可以进行 UI 更新)。
- doInBackground(Params…),耗时操作(不可用进行 UI 更新)
- onProgressUpdate(Progress…),当在 doInBackground 方法里调用 publishProgres(Progress…)时会被调用,用于更新当前的 UI 状态。(可以进行 UI 更新)
- onPostExecute(Result),当执行完 doInBackground()方法之后,返回 Result 值给 onPostExecute()方法。用于善后操作。(可以进行 UI 更新)
执行方式:
new MyAsyncTask().execute();
服务
- 间接继承自 Context
- 不要因为服务是后台的概念,就把服务和线程搞混了,服务依然是在主线程中运行(即和活动共用一个线程)
外部连接里有不错的解释:
如果服务中用到耗时操作,依然需要使用子线程: - 外部连接:
既然在 Service 里也要创建一个子线程,那为什么不直接在 Activity 里创建呢?
这是因为 Activity 很难对 Thread 进行控制,当 Activity 被销毁之后,
就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。
而且在一个 Activity 中创建的子线程,另一个 Activity 无法对其进行操作。
但是 Service 就不同了,所有的 Activity 都可以与 Service 进行关联,
然后可以很方便地操作其中的方法,即使 Activity 被销毁了,之后只要重新与 Service 建立关联,
就又能够获取到原有的 Service 中 Binder 的实例。
因此,使用 Service 来处理后台任务,Activity 就可以放心地 finish,
完全不需要担心无法对后台任务进行控制的情况。
两种方式创建服务
- startService(serviceIntent);
- bindService(bindIntent, connection, BIND_AUTO_CREATE);
- 我们完全有可能对一个服务既调用了 startService()方法,有调用了 bindService()方法。
这种情况如何销毁服务?需要同时调用 stopService()(或者 stopself())和 unBindService()方法才行。(p364) - stopself()可以在 MyService 的任何位置调用,以停止服务。
- stopService()跟 startService()一样,需要根据传入的参数来确定 stop 哪个服务。
1 | Intent stopIntent = new Intent(this, MyService.class); |
注意事项
- 需要在 Manifest 中注册服务。
- 通过 bindService 的方式创建的服务,可以更方便的控制它。
- IntentService,一个异步的,可以自动停止的服务。(p367)。
在重写的方法 onHandleIntent()里的进行耗时操作;
服务的应用
定时任务(Alarm)
外部连接
- Android 基本功:IntentService 的使用
- Android Service 的生命周期
- Android Service 的绑定 续篇:关于绑定的补充说明
- 深入理解 Android 的 startservice 和 bindservice
第十章 网络技术
使用 Http 协议访问网络(注意要添加网络权限)
HttpURLConnection(p380)
get 数据
1 | private void sendRequestWithHttpURLConnection(){ |
post 数据
1 | // 获取输出流并写出数据。 |
HttpClient(p385 )
get 数据
1 | private void sendRequestWithHttpClient(){ |
post 数据
1 | HttpPost httpPost = new HttpPost(" http://www.baidu.com"); |
回调机制(p406,真牛)
1 | public interface HttpCallbackListener{ |
XML 解析
1 | <apps> |
PULL 方式(p391 )
1 | private void parseXMLWithPull(String xmlData){ |
SAX 方式(p394)
1 | private void parseXMLWithSAX(String xmlData){ |
扩展:DOM 方式
解析 JSON
1 | [ |
JSONObject 方式(p399)
1 | private void parseJSONWithJSONObject(String jsonData){ |
GSON 方式(p401)
1 | class App{ |