开发工具:
文件大小: 2mb
下载次数: 0
上传时间: 2014-12-12
详细说明:
Android Android Android Android学习笔记 一 一 一 一 . . . .Android Android Android Android基础 基础 基础 基础 一. Android 的体系结构图 四层 , 底层 linux 内核(驱动) , 程序包(C 或 c++)和 Android 运行时(java 类似) ,应用程序框 架 (基本 API) , 应用程序层 .. 向下调用关系 . 二 , 王国历史 05 年 google 收购成立仅 22 个月的 android 公司 , 07 年 11 月 google 为首的 34 家公司成立了开放手机联盟 08 年 9 月 T-moblie usa 发布第一款手机 T-moblic G1 三 , 开发精神 (随时随地为每个人提供信息) 开发平台普及 (pc,mac,linux) 以 linux 为基础 , java 语言,, 支持 web 下载应用 四 , 开发中的四大天王 Activity (构造应用程序界面的) 门面 Intent (程序传递数据) Service (处理大部分数据工作) Content provider (提供数据的接口) 五 , 开发的工具 SDK , ec lipse (插件支持 ADT) 六 , 环境搭建 1 . Android SDK 安装 developer.android.com 2. ADT 安 装 www.ecplise.org 在 ecplise 中 软 件 更 新 一 栏 填 入 https://dl-ssl.google.com/android/eclipse 3. 在 eclipse 的首选项 android 中选择 android 的 location 填入本地 android SDK 的安装路径 4. 创建一个新的 android 的虚拟机 打开 android SDK and AVD manager 介绍一个很好的视频网站及资料站 www.mars-droid.com(作者网站) 二 二 二 二 . . . . 工程创建及目录结构 工程创建及目录结构 工程创建及目录结构 工程创建及目录结构 一 , 新建 project New -> android project -> project name -> build target (开发的版本选择)-> apllcation name -> package name -> create activity(显示界面) -> min sdk version(最低兼容 sdk 版本) 二 , android 程序的目录结构 Src ==> 编写的源文件 Gen ==> 引用程序的资源文件 (不要修改) Android ==> 源文件 jar 文件 Assets ==> 放置任何文件 Res ==> 此处放置会在 gen 中生成相应 ID Drawable 放置图片 分为多个分辨率图片 hdpi,ldpi,mdpi 高中低 Layout 布局方式 Values adnroidManifest.xml 全局配置文件 三 三 三 三 . . . .Activity Activity Activity Activity初步 初步 初步 初步 1 . Activity 的主要作用(UI) 应用程序组件 创建一个 activity 类 创建 Activity 要点 1. 一个 activity 就是一个类, 并且这个类要继承 activity 2. 需要从写 onCreate 方法(程序运行首先调用) 3. 在配置文件中注册每一个 activity 4. 要为 activity 中添加必要的控件 5. 对应布局文件 一个布局文件对应一个 activity 得到控件 例 findViewById(R.id.MyButton); 四 四 四 四 . . . .Activity Activity Activity Activity和 和 和 和intent intent intent intent 多个 Activity 之间的关系 跳转关键 startActivity(Intent intent) 在 onClickListener 监听器的 onClick 方法中 内部类继承 OnClickListener Intent intent = new Intent(); intent.putExtra(key , value); // 设置传参数据 intent.setClass(this,class); // 设置跳转参数 Activity.this.startActivity(intent); 事件绑定 myButton = (Button)findViewById(R.id.myButton); myButton.setOnClickListener(new 内部类名()); // 注册成功 Intent 对象的获取 Intent intent = getIntent(); String value = intent.getStringExtra(key); TextView = (TextView)findViewById(R.id.myTextView); TextView.setText(value); Intent 的基本作用 Intent 对象包含了一组信息 相当于一个请求 1. Component name (欲启动 Activity 的名称等等) 2. Action (另一个 Activity 的动作) ACTION_CALL EDIT , MAIN, SYNC, BATTERY_LOW , SCREEN_ON 等等 3. Data (传递的数据) 4. Category 5. Exreas (额外的键值对信息) 6. Flags 启动另一个 Activity 例 Url url = Url.parse("smsto://08000000123"); Intent intent = new Intent(Intent.ACTION_SENDTO,url); intent.putExtra("sms_body","The SMS text"); startActivity(intent); 五 五 五 五 . . . .Android Android Android Android开发时常用控件 开发时常用控件 开发时常用控件 开发时常用控件( ( ( (一 一 一 一) ) ) ) TextView , Button , EditText , Menu 例 , 实现一个简单的计算器功能 实现过程一 1 . 在第一个 Activity 中,声明 4 个控件 (2 个编辑框 , 1 个文本域 , 1 个按钮) 2. 要为其中的两个空间设置显示的值 (文本域 和 按钮) 3. 创建一个监听器 . 监听按钮事件 4. 将监听器对象绑定到按钮对象上 在布局的 xml 文件中添加控件 例: 在使用空间的 Activity 页面中取出控件 例: public class Activity extends Activity { Private EditText eText1; Private EditText eText2; Private TextView tView; Privete Button bBtn; @override Public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 根据控件的 ID 来取得代表控件的对象 eText1 = (EditText)findViewById(R.id.eText1); eText2 = (EditText)findViewById(R.id.eText2); tView = (TextView)findViewById(R.id.tView); tView,setText("乘以"); bBtn = (Button)findViewById(R.id.bBtn); bBtn.setText("计算"); // 为 button 设置值 // 或设置在 res/strings.xml 中设置 //例 : 计算 //bBtn.setText(R.string.bBtnText); // 将监听器对象绑定按钮对象上去 bBtn.setOnClickLinstrener(new CalculateListener()); } // 内部类监听器 Class CalculateListener implements OnClickListener { @Override Public void onClick(View v) { // 取得两个编辑框的值 String eText1 = eText1.getText().toString(); String eText2 = eText2.getText().toString(); // 将两个值放入到 Intent 对象之中 Intent intent = new Intent(); // 使用这个 Intent 对象启动下一个 Activity intent.putExtra("one",eText1 ); intent.putExtra("two",eText2); intent.setClass(Activity.this , ResultActivity.class); Activity.this.startActivity(intent); } } } 实现过程二 : 1. 接受从 Activity 当中传递的值 2. 计算两个值的积 3. 将计算的结果显示在当前的 Activity 中 //在当前的 Activity 中的 xml 文件中添加一个文本域 在 onCreate 中执行语句 (不再累赘) 关键代码: // 取到 RestltView 的对象 Intent intent = getIntent(); String tText1 = intnet.getStringExtra("one"); String tText2 = intnet.getStringExtra("two"); Int tText1int = Integer.parseInt(tText1); Int tText2int = Integer.parseInt(tText2); Int result = tText1int * tText2int; RestltView.setText(result + ""); Menu 对象的实现 复写函数 onCreateOptionMenu() Public boolean onCreateOptionMenu(Menu menu) { // 第二个参数就是 itemid Menu.add(0,1,1,R.string.exit); Menu.add(0,2,2,R.string.about); Return super.onCreate } 继续实现 menuitem 的事件方法 // 当用户点击菜单的某一选项时,会调用该方法 复写 onOPtionsItemSelected(MenuItem item); Public boolean onOPtionsItemSelected(MenuItem item) { If(item.getItemId() == 1) { Finish(); } Return super.onOptionsItemSelected(MenuItem item); } 六 六 六 六 . . . .Activity Activity Activity Activity的生命周期 的生命周期 的生命周期 的生命周期 参考文档 : 安装目录/docs/index.html Activity 的生命周期函数 onCreate (Activity 被第一个创建时), onReStart , onStart(Activity 可视的时候) , onDestroy , onPause (Activity 暂停状态), onResume (Activity 可被获得焦点的时候), onStop(Activity 不可见的 时候) 启动一个新的 Activity 会依次调用 onCreate , onStart , onResume 调用另外一个 Activity 会依次调用 onPause(第一个) , onCreate (第二个), onStart (第二个), onResume(第二个) , onStop(第一个) 调用返回按钮 Activty 会依次调用 onPause (第二个) , onReStart(第一个) , onStart (第一个), onResume(第一个), onStop(第二个) , onDestory (第二个) onDestory()被调用的时机 1. 明确调用 finish 方法 2. 系统自适应释放 Task 基本概念 (栈中的所有 Activity) 栈 压栈,弹栈 (后进先出原则) Task 运行过程 , 当应用程序启动之后,运行第一个 Activity 被压入栈中 (显示会时栈中最顶部的 Activity) 3 . 模态化窗体(对话框) 在 AndroidManifest.xml 文件中 可被*的方法 onStop , onPause , onDestory 七 七 七 七 . . . .Activity Activity Activity Activity的布局 的布局 的布局 的布局 LinearLayout TableLayout 2 . // 指定列拉伸 // 填写控件 // 两行 3 . LinearLayout 高级布局 例 : 思想 3 个 LinearLayout 注 : 在 LinearLayout 中还可以嵌套 TableLayout 4 . RelativeLayout 相对布局 Relative 常见属性的概要 Android:layout_above -- 将该控件的底部至于给定 ID 的控件之上 Android:layout_Below -- 将该控件的底部至于给定 ID 的控件之下 Android:layout_toLeftOf -- 该控件的右边缘个给定 ID 的控件的左边缘对齐 Android:layout_toRightOf -- 该控件的左边缘个给定 ID 的控件的右边缘对齐 Layout_alignBaseline -- 该控件的 baseline 与给定 ID 的控件的 baseline 对齐 Layout_alignBottom -- 该控件的底部边缘与给定 ID 的控件的底部边缘对齐 Layout_alignLeft -- 该控件的左边缘个给定 ID 的控件的左边缘对齐 Layout_alignRight -- 该控件的右边缘个给定 ID 的控件的右边缘对齐 Layout_alignTop -- 该控件的顶部边缘与给定 ID 的控件的顶部边缘对齐 Layout_alignParentBottom , Layout_alignParentLeft , Layout_alignParentRight , Layout_alignParentTop 该值为 True 时 , 该控件的边与父控件的边的对齐方式 Layout_centerHorizontal , Layout_centerInParent , Layout_centerVertical 八 八 八 八 . . . .Android Android Android Android开发时常用控件 开发时常用控件 开发时常用控件 开发时常用控件( ( ( (二 二 二 二) ) ) ) RadioGroup , RadioButton CheckBox Toast 例 1 , 代码 : 1. 控件对象声明 2. 取得对象控件 3. 设置监听器 ( 只为 RadioGroup 注册一个 ) Public void onCheckedChange(RadioGroup group , int checkedId) { If (femaleButton.getId() == checkedId) { System.out.println("Female"); } Else if (maleButton.getId() == checkedId) { System.out.println("Male"); } } 4. 触发事件 // 为 RadioGroup 设置 RadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() ) 例 2 . 代码 : 1. 控件对象声明 2. 取得对象控件 3. 设置监听器(为每一个 CheckBox 注册监听器) Public void onCheckedChanged(CompoundButton buttonView , boolean isChecked) { If(isChecked) { System.out.println("yes"); } Else { System.out.println("NO"); } } 4. 触发事件 CheckBox.setOnCheckedChangeLinstener(new CompoundButton.onCheckedChangeLinstener() {}) 例 3 . Toast Toast.makeText(this.class , displaystring , messageTime).show() 九 九 九 九 . . . .Android Android Android Android开发时常用控件 开发时常用控件 开发时常用控件 开发时常用控件( ( ( (三 三 三 三) ) ) ) ProgressBar ListView 例 : 代码 : 1 . 声明变量 2 . 根据 ID 取得控件对象 findViewById 3 . 设置监听类 Class ButtonLinstener implements OnClickListener { Public void onClick(View v) { If (i == 0) { pBar.setVisibility(View.VISIBLE); } Else if ( i < pBar.getMax() ) { pBar.setProgress(i); -- 设置主进度条的当前值 pBar.setSecondaryProgress(i+10); -- 设置第二进度条的当前值 } Else { pBar.setVisbility(View.GONE); } I = i + 10; } } 4 . 绑定事件 myButton.setOnClickListener(new ButtonLinstener()); 例 : main 布局文件 User 布局文件略 (两个 TextView) 代码 : public class Activity extends ListActivity { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 用一个集合对象装数据 ArrayList> list = new ArrayList>(); HashMap Map1 = new HashMap(); HashMap Map2 = new HashMap(); HashMap Map3 = new HashMap(); Map1.put("user_name","zhangsan"); Map1put("user_ip","192.168.0.1"); Map2.put("user_name","lisi"); Map2.put("user_ip","192.168.0.2"); Map3.put("user_name","wangwu"); Map3.put("user_ip","192.168.0.3"); List.add(Map1); List.add(Map2); List.add(Map3); // listActivity 对象 , map , 第二个布局文件 , 对应 hashMap 的值对(可想象成列) , 控件显示的位置 SimpleAdapter listAdapter = new SimpleAdapter(this , list , R.layout.user , new String[] {"user_name","user_ip"} , new int[] {R.id.user_ip,R.id.user_name}); setListAdapter(listAdapter); } // 重写 Protected void onListItemClick(ListView lv , View v , int position , long id) { super.onListItemClick(1, v , position , id); System.out.println("id--------" + id); System.out.println("position-------" + position) } 十 十 十 十 . . . .Handler Handler Handler Handler的用法 的用法 的用法 的用法 Handler 的基本概念 (可以进行另外线程的处理程序 , 优化程序 , 类似于线程概念) 异步线程处理方案 Handler 基本的使用方法 代码 : 可以在事件中调用 Handler 的方法 例 : 在 Button 的单击事件中: Handler.post(updateThread); // 线程对象加入到消息队列中, 此消息队列中只有一个线程对象 // 取消线程队列 handler.removeCallbacks(updateThread); // 创建一个 Handler 对象 Handler handler = new Handler(); // java 中实现线程的方法 1 继承 thread 类 2.实现 runnable 接口 // 将要执行的操作写在线程对象的 run 方法中去 Runnable updateThread = new Runnable (){ Public void run() { System.out.println("UpdateThread"); // 在 run 方法内部执行 postDelayed 或者 post 方法 handler.postDelayed(updateThread , 3000); // 延迟加入消息队列 } } // 消息队列(数据结构) 先进先出 使用 Handler 更新 ProgressBar 例 : main.xml 中的布局 Activity 中的代码: Public class TestBarHandler extends Activity { // 声明控件对象 ProgressBar bar = null; Button startButton = null; Public void onCreate (Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 得到控件对象 Bar = (ProgressBar)findViewById(R.id.bar); startButton = (Button)findViewById(R.id.startButton); // 为按钮设置监听器 startButton.setOnClickListener(new ButtonListener()); } // 创建监听器 Class ButtonListener implements OnClickLinstener { Public void onClick(View v) { pBar.setVisibility(View.VISIBLE); pBar.setMax = 200; updateBarHandler.post(updateThread); } } // 创建一个 Handler 对象 使用匿名内部类来复写 handler 的 handlerMessage 中 Handler updateBarHandler = new Handler() { Public void handlerMessage(Message msg) { bar.setProgress(mag.arg1); updateBarHandler.post(updateThread); // 线程加入线程队列中 } }; // 匿名内部线程类 Runnable updateThread = new Runnable(){ Int i = 0 ; Public void run() { // 直接执行了当前 Activity 的线程 System.out.println("begin Thread"); I = i +10; // 得到一个消息对象 , message 类是有 android 操作系统提供 Message msg = updateBarHandler.obtainMessage(); // 将 msg 对象的 arg1 参数的值设置为 i , 用 arg1 和 arg2 这两个成员变量传递消息,可以使系统的性能 消耗较小 Msg.arg1 = i; Try { Thread.sleep(1000); } catch ( InterruptedException e) { e.printStackTrace(); } // 将 msg 加入消息队列中 updateBarHandler.sendMessage(msg); If(i == pBar.getMax()) { // 如果 i 的值到达最大值时,移除线程 updateBarHandler.removeCallbacks(updateThread); } } }; } 4 . Handler 与线程 (默认情况下 Activity 与 Handler 共享一个线程) 例 : // 证明 Activity 与 Hnadler 共享一个线程 Public class HnadlerTest extends Activity { private Handler handler = new Handler(); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 执行完这一行代码 Activity 中才有控件 Handler.post(r); //Thread t = new Thread(r); // 独立线程 //t.start(); // currentThread 得到当前运行线程对象 System.out.println("activity----->" + Thread.currentThread().getId()); System.out.println("activityname----->" + Thread.currentThread().getName()); } Runnable r = new Runnable() { Public void run () { System.out.println("Handler----->" + Thread.currentThread().getId()); System.out.println("HandlerName----->" + Thread.currentThread().getName()); Try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }; } // 输出对比 需要等待 10 秒,Activity 中才会有控件 Activity----> 1 ActivityName ---> main Handler----> 1 HandlerName ---> main // 独立线程输出 无等待时间 Handler ---> 9 HandlerName ---> Thread-9 Activity----> 1 ActivityName ---> main 5 . Bundle 的用法(相对特殊的 map , key 一般为 string , value 为个个数据类型) // Looper , handlerThread 都可以创建一个新的线程 例 : Public class HnadlerTest extends Activity { private Handler handler = new Handler(); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); System.out.println("Activity ----> " + Thread.currentThread().getId()); // 生成一个 HandlerThread 对象,实现了使用 looper 来处理消息队列的功能,这个类有 android 内部实现 HandlerThread handlerThread = new HandlerThread(); handlerThread.start(); MyHandler myHandler = new MyHandler(handlerThread.getLooper()); // 获取消息对象 Message msg = myHandler.obtainMessage(); msg.sendToTarget(); } Class MyHandler extends Handler { Public MyHandler () { } Public MyHnadler(Looper looper) { // 调用父类的构造函数 , 有 looper 的方法 Super(looper); } Public void handleMessage(Message msg) { System.out.println("handler---->" + Thread.currentThread().getId()); System.out.println("HandlerMessage"); } } } 6 . 在新线程当中处理消息的方法 // 首先创建 Message 对象 // 可以用 arg1 , arg2 (int) , obj (object) , setData(Bundle data) 赋值传递 // 取值 变量 = msg.arg1 等等 Bundler 例 : // 赋值 Bundle b = new Bundle(); b.putInt("age",20); b.putString("name" , "zhangsan"); msg.setData(b); // 取值 Bundle b = msg.getData(); Int age = b.getInt("age"); String name = b.getString("name"); 十一 十一 十一 十一 . . . .SQLite SQLite SQLite SQLite使用方法 使用方法 使用方法 使用方法 SQLite 介绍 http://www.sqlite.org 官方网站 小型关系数据库 SQLiteOpenHelper 使用方法 getReadableDatabase() getWritableDatabase() onCreate(SQLiteDatabase db) onOpen(SQLiteDatabase db) onUpgrade(SQLiteDatabse db , int oldVersion , int newVersion) Close(); // DatabaseHelper 所为一个访问 SQLite 的助手类, 提供两个方面的功能 // 第一, getReadableDatabase() 和 getWritableDatabasr() 可以获得 SQLiteDatabase 对象 // 第二, 提供 onCreate 和 onUpgrade 两个回调函数 , 允许我们在创建和升级数据库时, 进行操作 例 : public class DatabaseHelper extends SQLiteOpenHelper { // 数据库版本号 Private static final int VERSION = 1; // 必须的构造函数 Public DatabaseHelper (Context context , String name , CursorFactory factory , int version) { Super(context , name , factory , version); } Public DatabaseHelper (Context context , String name , int version) { Super(context , name , null , version); } Public DatabaseHelper (Context context , String name) { Super(context , name , null , VERSION); } Public void onCreate(SQLiteDatabase db) { System.out.println("create a database"); Db.execSQL("create table user(id int , name varchar(20))"); } Public void onUpgrade(SQLiteDatabase db) { System.out.println("update a database"); } } 对 SQLite 的增 删 查 改 Activity 操作数据库 例 : 1 . 声明控件对象(略) 2 . 获得控件对象(略) 3 . 绑定事件(略) 4 . 创建监听器对象 (调用 DatabaseHelper) // 创建一个数据库 Public void onClick(View v) { // 当前的 activity , 还有数据名 DatabaseHelper dbHelper = new DatabaseHelper(SQLiteActivity.this , "test_db"); SQLiteDatabase db = dbHelper.getReadableDatabase(); // 此时才会创建一个数据库 } // 修改一个数据库 Public void onClick(View v) { // 当前的 activity , 还有数据名 DatabaseHelper dbHelper = new DatabaseHelper(SQLiteActivity.this , "test_db" , 2); // 版本号 变了 SQLiteDatabase db = dbHelper.getReadableDatabase(); } // 插入操作 Public void onClick(View v) { // 生成 ContentValues 对象 ContentValues values = new ContentValues(); // key 是列名 , value 是值 , 值必须对应数据库列数据类型 Values.put("id" , 1); Values.put("name" , "zhangsan" ); // 当前的 activity , 还有数据名 DatabaseHelper dbHelper = new DatabaseHelper(SQLiteActivity.this , "test_db"); // 得到可写数据库 SQLiteDatabase db = dbHelper.getWritableDatabase(); // 1.表名 2,不允许空列 3, 值 Db.insert("user", null , values); } // 更新操作 Public void onClick(View v) { // 当前的 activity , 还有数据名 DatabaseHelper dbHelper = new DatabaseHelper(SQLiteActivity.this , "test_db"); // 得到可写数据库 SQLiteDatabase db = dbHelper.getWritableDatabase(); // 1.表名 2,不允许空列 3, 值 // 生成 ContentValues 对象 ContentValues values = new ContentValues(); // key 是列名 , value 是值 , 值必须对应数据库列数据类型 Values.put("name" , "zhangsanfeng" ); // 1.表名 2. 值 , 3 , where 子句 (不包括 where) 4, 为占位符赋值 Db.update("user", values , "id=?" , new String[] {"1"}); } // 查询数据库 Public void onClick(View v) { // 当前的 activity , 还有数据名 DatabaseHelper dbHelper = new DatabaseHelper(SQLiteActivity.this , "test_db"); // 版本号变了 SQLiteDatabase db = dbHelper.getReadableDatabase(); // 1, 表名 2 所要查询的列名 3 , 筛选器 4 , 筛选器值 5 .groupby 6 . having //7 orderby 创建游标对象读取数据 Cursor cursor = db.query("user" , "new String[] {"id" , "name"}" , "id=?") While (cursor.moveToNext()) { String name = cursor.getString(cursor.getColumnIndex("name")); System.out.println("query--->" + name); } } // 删除操作 Public void onClick(View v) { // 当前的 activity , 还有数据名 DatabaseHelper dbHelper = new DatabaseHelper(SQLiteActivity.this , "test_db"); // 得到可写数据库 SQLiteDatabase db = dbHelper.getWritableDatabase(); // 1.表名 2. 值 , 3 , where 子句 (不包括 where) 4, 为占位符赋值 Db.delete("user", values , "id=?" , new String[] {"1"}); } 使用 adb 访问 SQLite (linux 命令行调试) abd shell = > ls -i = > cd data = > 创建了数据库之后 = > 报名.数据库名 => 即可进入该 SQLite SQLite 语句 .schema // 查看所有表 Linux 知识补习 : cd 目录 (进入目录) ls (查看当前目录) 十二 十二 十二 十二 . . . . 程序调试 程序调试 程序调试 程序调试 1 . DDMS 的使用 LogCat 的 Verbose Debug Info Warning Error 的功能 增加过滤器 create filter => system.out 通过 file explorer 功能实现文件的取出,放入 2 . 常见程序调试 A) 多多查看 DDMS 的 log 和 java 中的方式相同 B) 使用 Log 类输出各类信息 十三 十三 十三 十三 . . . . 文件下载 文件下载 文件下载 文件下载 1 . 使用 http 协议下载文件 // 步骤 A ) : 创建一个 HttpURLConection 对象 HttpURLConnection urlConn = (HttpURLConnection)url.openConnection(); B ) : 获取一个 InputStream urlConn.getInputStream(); C ) : 访问网络的权限 android.permission.INTERNET 例 : 1 . 声明控件对象(略) 2 . 获得控件对象(略) 3 . 绑定事件(略) 4 . 创建监听器对象 // 封装方法 httpDownloader Public class HttpDownloader { Private URL url = null; Public String download(String urlStr) { StringBuffer sb = new StringBuffer(); String line = null; BufferedReader buffer = null; Try { // 创建一个 URL 对象 Url = new URL(urlStr); // 创建一个 Http 连接 HttpURLConnection urlConn = (HttpURLConnection)url.openConnection(); // 使用 IO 流读取数据 Buffer = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); While ((line = buffer.readline()) != null) { Sb.append(line); } catch (Execption e) { e.printStackTrace(); } finally { Try { Buffer.close(); } catch (Execption e) { e.printStackTrace(); } } Return db.ToString(); } } // 返回值 -1 . 下载文件出错 0 下载成功 1 文件已存在 Public int downFile(String urlStr , String path , String fileName) { InputStream inputStream = null; Try { FileUtils fileUtils = new FileUtils(); If(fileUtils.isFileExists(path + fileName)) { Return 1; } else { InputStream = getInputStreamFromUrl(urlStr); File resultFile = fileUtils.write2SDFromInput(path , fileName , inputStream); If(resultFile == null) { Return -1; } } } catch (Exception e) { e.printStackTrace(); Return -1; } finally { Try { inputStream.close(); } catch (Execption e) { e.printStackTrace(); } } Return 0; } // 根据 url 得到输入流 Public InputStream getInputStreamFromUrl (String urlStr) Throws MalfromedURLExecption , IOExecption { Url = new URL(urlStr); HttpURLConnection urlConn = (HttpURLConnection)url.openConnection(); InputStream inputStream = urlConn.getInputStream(); Return inputStream; } } Public void onClick(View v) { HttpDownloader httpDownloader = new HttpDownloader(); String lrc = httpDownloader.download("http://192.168.0.1:8080/XXX.txt"); System.out.println(lrc); } 2 . 将下载的文件写入 SDCARD 访问 SDCARD // 得到当前设备 sdka 的目录 Environment.getExternalStorageDirectory(); // 访问 SD 卡的权限 Android.permission.WRITE_EXTERNAL_STORAGE 例 : // 一个完整的访问封装类 Public class FileUtils { Private String SDPATH; Public String getSDPATH() { Return SDPATH; } Public FileUtils() { SDPATH = Environment.getExternalStorageDirectory() + "/"; } // 在 SD 卡上创建文件 Public File createSDFile(Stirng fileName) throws IOException { File file = new File(SDPATH + fileName); file.createNewFile(); Return file; } // 在 SD 卡上创建目录 Public File createSDDir(String dirName) { File dir = new File(SDPATH + dirName); Dir.mkdir(); Return dir; } // 判断 SD 卡上的文件夹是否存在 Public boolean isFileExist (String fileName) { File file = new File(SDPATH + fileName); Return file.exists(); } // 将一个 inputStream 里面的数据写入到 SD 卡上 Public file write2SDFromInput(String path , string fileName , InputStream input) { File file = null; OutputStream output = null; Try { createSDDir(path); File = createSDFile(path + fileName); Output = new FileOutPutStream(file); Byte buffer [] = new byte [4 * 1024]; While ((input.read(buffer)) != -1) { Output.write(buffer); } Output.flush(); } catch (Exception e) { e.printStackTrace(); } finally { Try { Output.close(); } catch (Exception e) { e.printStackTrace(); } } Return file; } } 最后在 AndroidManifest,xml 中加入标签 十四 十四 十四 十四 . . . .Content Content Content ContentProvider Provider Provider Provider 1.ContentProvider 基本概念 A:ContentProvider 提供为存储和获取数据提供了统一的接口 B: 使用 ContentProvider 可以在不同的应用程序之间共享数据 C:Android为常见的一些数据提供了ContentProvider(包括音频 , 视频,图片和通讯 录等等) 2.Uri A:每一个 ContnetProvider 都拥有一个公共的 URI,这个 URI 用于表示这 个 ContnetProvider 所提供的数据 B:Android 所提供的 ContentProvider 都存放在 android.provider 包当中 3.ContnetProvider 实现方法 Query Insert Update Delete getType onCreate 4. 实现 ContentProvider 的过程 A: 定义一个 Content_URI 常量 B: 定义一个类 , 继承 ContentProvider C: 实现 query,insertupdate,deletegetType,和 onCreate 方法; D: 在 AnroidManifest.xml 当中进行声明; 例 : // DatabaseHelper 所为一个访问 SQLite 的助手类, 提供两个方面的功能 // 第一, getReadableDatabase() 和 getWritableDatabasr() 可以获得 SQLiteDatabase 对象 // 第二, 提供 onCreate 和 onUpgrade 两个回调函数 , 允许我们在创建和升级数据库时, 进行操作 例 : public class DatabaseHelper extends SQLiteOpenHelper { // 数据库版本号 Private static final int VERSION = 1; // 必须的构造函数 Public DatabaseHelper (Context context , String name , CursorFactory factory , int version) { Super(context , name , factory , version); } Public DatabaseHelper (Context context , String name , int version) { Super(context , name , null , version); } Public DatabaseHelper (Context context , String name) { Super(context , name , null , VERSION); } Public void onCreate(SQLiteDatabase db) { System.out.println("create a database"); // 拼出了建表的语句 db..execSQL("create table" + FirstMetaData.USER_TABLE_NAME +"("+ FirstMetaData.UserTableMetaData._ID +"INTEGER PRIMARYKEYAUTOINCREMENT," +FirstMetaData.UserTableMetaData.USER_NAME +"varchar(20));"; } Public void onUpgrade(SQLiteDatabase db) { System.out.println("update a database"); } } ContentProviderActivity 例 : 1 . 声明控件对象(略) 2 . 获得控件对象(略) 3 . 绑定事件(略) 4 . 创建监听器对象 // insert Public void onClick(View v) { ContentValues values = new ContentValues (); Values.put(FirstMetaData.UserTableMetaData.USER_NAME , "zhangsan"); Uri uri = getContentesolver().insert(FirstMetaData.UserTableMetaData.CO NTENT_URI,values); System.out.println("uri ---->" + uri.toString()); } // query Public void onClick(View v) { Cursor c= getContentResolver().query( FirstMetaData.UserTableMetaData.CONTENT_URI , null,null,null,null ) ; While(c.moveToNext()) { System.out.println(c.getString(c.getColumnIndex(UserTa bleMeatData.USER_NAME))); } } FirstContentProvider 继承 ContentProvider 例 : PublicclassFirstContentProviderextendsContentProvider { Publicstatic finalUriMatcheruriMatcher; Publicstatic finalintINCOMING_USER_COLLECTION =1; Publicstatic finalintINCOMING_USER_SINGLE =2; Private DatabaseHelper dh; Static { uriMatcher= newUriMatcher(UriMatcher.NO_MATCH); //URI 限定名的添加验证 定义了一个验证的规则 uriMatcher.addURI(FirstMetaData.AUTHORTY , "/users", INCOMING_USER_COLLECTION); uriMatcher.addURI(FirstMetaData.AUTHORTY , "/users/#", INCOMING_USER_SINGLE); } Public static HashMap userProjectionMap; Static { userProjectionMap = new HashMap(); // ._ID 就是 baseColumns 实现的结果 userProjectionMap.put(FirstMetaData._ID,FirstMetaData._ID); userProjectionMap.put(FirstMetaData .USER_NAME , FirstMetaData.USER_NAME); } @Override Public int delete(Uri arg0 , String arg1 , String[] arg2) { System.out.println("delete"); Return 0; } // 根据传入的 Uri,返回该 Uri 所表示的数据类型 @Override Public String getType(Uri uri) { System.out.println("getType"); Switch (uriMatcher.match(uri)) { Case INCOMING_USER_COLLECTION: Return FirstMetaData.CONTENT_TYPE; CaseINCOMING_USER_SINGLE: ReturnFirstMetaData.CONTENT_TYPE_ITEM; Default: ThrownewIllegalArgumentExecption("Unknown URI"+uri); } } // 该函数的返回值是一个 Uri , 这个 URi 表示的是刚刚使用这个函数所插入的数据 // content://com.android.FirstContentProvider/users/1 @Override Public Uri insert(Uri uri , ContentValue values) { System.out.println("insert"); SQLiteDatabase db = dh.getWrittableDatabase(); Long rowId = db.insert(FirstMetaData.TABLE_NAME,null,values); If(rowId > 0) { // 以 Content 起头的 Uri 都可以用 ContentUris 来处理 Uri insertedUserUri = ContentUris.withAppendedId(UserTableMetaData.CONTENT_URI , rowId); // 通知监听器 , 数据已经改变 getContext().getContentResolver().notifyChange(insertedUserUri , null); Return insertedUserUri; } Throw new SQLExecption("Failed to insert row into " + uri); } @Override Public boolean onCreate() { Dh = new DatabaseHelper(getContext() , FirstMetaData.DATABASE_NAME); System.out.println("onCreate"); Return true; } @Override Public Cursor query(Uri uri , String[] projection , String selection , String[] selectionArgs , String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder (); Switch (uriMatcher.match(uri)) { Case INCOMING_USER_COLLECTION: qb.setTables(FirstMetaData.TABLE_NAME); qb.setProjectionMap(userProjectionMap); Break; CaseINCOMING_USER_SINGLE: qb.setTables(FirstMetaData.TABLE_NAME); qb.setProjectionMap(userProjectionMap); // 取回了单条数据 list qb.appendWhere(FirstMetaData._ID + "="+uri.getPathSeqments().get(1)); Break; } String orderBy; If (TextUtils.isEmpty(sortOrder)) { orderBy = FirstMetaData.DEFAULT_SORT_ORDER; } else { orderBy = sortOrder; } SQLiteDatabase db = dh.getWritableDatabase(); Cursor c = qb.query(db , projection , selection , selectionArgs , null , null , orderBy); c.setNotificationUri ( getContext().getContentResolver() , uri); System.out.println("query"); Return c; } @Override Public int update(Uri arg0 , ContentValues arg1 , String arg2 , String[] arg3) { System.out.println("update"); } } FirstMetaData(一些静态常量) 例 : PublicclassFirstMetaData { //URI 限定名的名称 包名 + 类名 Publicstatic finalStringAUTHORTY="com.android.FirstContentProvider"; // 数据库名称 Publicstatic finalStringDATABASE_NAME="FirstContentProvider.db"; // 数据库版本 Publicstatic finalintDATABASE_VERSION =1; // 表名 Publicstatic finalStrintUSERS_TABLE_NAME ="users"; //BaseColumns 实现了表的_id 列 Publicstatic finalclassUserTableMetaDataimplementsBaseColumns{ // 表名 Publicstatic finalStringTABLE_NAME= "users"; // 访问该 ContentProvider 的 URI Public static final Uri CONTENG_URI = Uri.parse("content://" + AUTHORY + "/users"); // 整张表的数据类型是 vnd.android.cursor.dir/vnd+name; Public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.FinrstContentProvider.ser"; // 单条数据类型定义 vnd.android.cursor.item/vnd+name Public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.FinrstContentProvider.user"; // 列名 Publicstatic finalStringUSER_NAME="name"; // 默认排序方法 Publicstatic finalStringDEFAULT_SORT_ORDER= "_iddesc"; } } 最后在 androidMnaifest.xml 中注册 provider 与 Activity 同级 authorities 中的数据一定要 与 CONTENG_URI 的一致 十五 十五 十五 十五 . . . .XML XML XML XML文件解析 文件解析 文件解析 文件解析 1. 什么是 SAX SimpleAPI forXML, 既是指一种接口 , 也是指一个软件包 作为接口 ,SAX 是事件驱动型 XML 解析的一个标准接口 2.SAX 基本原理 SAX 的哦给你工作原理简单地说就是对文档进行顺序扫描,当扫描到文档 (document)开始与结束,元素(element)开始与结束等地方时通知事件处理函数,由事件处 理函数做相应动作,然后继续同样的扫描,直至文档结束. 大多数 SAX 实现都会产生一下类型的事件 { 在文档的开始和结束时出发文档处理事件 在文档内每一 XML 元素接受解析的前后触发元素事件 任何元数据通常都由氮素的事件交付 在处理文档的 DTD 或 Schema 时产生 DTD 或 Schema 事件 产生错误事件用来通知主机应用程序解析错误 } 3.SAX 常用接口 ContentHandler 接口 ContentHandler是java类包中一个特殊的SAX接口,位于org.xml.sax包中.该接 口封装了一些对事件处理的方法,当XML解析器开始解析XML输入文档时,它会遇 到某些特殊的事件,比如文档的开头和结束,元素的开头和结束,以及元素中的字符 数据等事件.当遇到这些事件时,XML解析器会调用ContentHandler接口中相应的方 法来响应该事件 ContnetHandler 接口的方法有以下几种 { Void startDocument(); Void endDocument(); Void startElement(String uri,StringlocalName ,stringqName ,Attributesatts) Void endElement(Stringuri,String localName,StringqName) Void characters(char[]ch,intstart,intlength) } 4.SAX 解析 解析文档过程 例 : HelloWorld! 在解析文档的过程中会产生如下一系列事件 Startdocument { Startelement:doc A: 创建事件处理程序 Startelement:para Characters:HelloWorld! B: 创建 SAX 解析器 Endelement:para Endelement:doc C: 将事件处理程序分配给解析 器 D: 对文档进行解析 , 将每个 事件发送给处理程序 Enddocument } 解析样例 : 1 . 声明控件对象(略) 2 . 获得控件对象(略) 3 . 绑定事件(略) 4 . 创建监听器对象 Public void onClick(View v) { HttpDownloader hd = new HttpDownloader(); String resultStr = hd.download("XMLURL"); System.out.priintln(resultStr); Try { // 创建一个 SAXParseFactory SAXParserFactory factory = SAXParserFactory.newInstance(); XMLReader reader = factory.newSAXParser().getXMLReader(); // 为 XMLReader 设置内容处理器 MyContentHandler reader.setContentHandler(new MyContenHandler()); // 开始解析文件 字符串构造成 reader 之后构造成 inputSource Reader.parse(new InputSource(new StringReader(resultStr))); } catch (Execption e) { e.printStackTrace(); } } XML 文件写法 : mark male manager New York $4000 lily female assists H $2000 tom male manager F $5000 MyContenHandler 的写法 例 : Public class MyContenHandler Extends DefaultHandler { // 此处体现了适配器模式 String Name , Sex , Status , Address , Salary String tagName; // 开始 document Public void startDocument() throws SAXExecption { System.out.println("-------begin--------"); } // 结束 document Public void endDocument() throws SAXExecption { System.out.println("-------end--------"); } // 开始节点对象 Public void startElement(String namespaceURI , String localName , String qName , Attributes attr) throws SAXExecption { tagName = localName ; If (localName.equals("worker")) { // 获取标签的全部属性 For (int i = 0 ; i < attr.getLength(); i ++) { System.out.println(attr.getLocalName(i) + "=" + attr.getValue(i)) } } } // 结束节点对象 Public void endElement(String namespaceURI , String localName , String qName ) throws SAXExecption { // 在一个标签解析完之后,打印所有标签的信息 If (localNmae.equals("worder")) { This.printout(); } } // 读取文本对象 Public void characters(char[] ch , int start , int length) throws SAXExecption { If (tagNmae.equals("name")) Hisname = new String(ch , start , length); Else if (tagNmae.equals("sex")) Sex = new String(ch , start , length); Else if (tagNmae.equals("status")) Status= new String(ch , start , length); Else if (tagNmae.equals("address")) Address= new String(ch , start , length); Else if (tagNmae.equals("salary")) Salary= new String(ch , start , length); } // 打印读出的信息 Public void printout() { System.out.println("name--->" + Name); System.out.println("name--->" + Sex); System.out.println("name--->" + Status); System.out.println("name--->" + Address); System.out.println("name--->" + Salary); } } 十六 十六 十六 十六 . . . . 广播机制 广播机制 广播机制 广播机制 1.Adnroid 的广播机制 2.BroadcastReceiver 的作用 事件触发之后的一种解决方法 3.BroadcasrReceiver 的编写方法 在 AndroidManifest.xml 中注册广播 例 ://BroadcasrReceiver PublicclassTestReceiverextendsBroadcastReceiver { PublicTestReceiver(){ System.out.println("TestReceiver"); } @override PublcvoidonReceive(Contextcontext,Intentintent){ System.out.println("OnReceiver"); // 对象会被销毁 TestReceiver } } Activity 中的写法 例: 1 . 声明控件对象(略) 2 . 获得控件对象(略) 3 . 绑定事件(略) 4 . 创建监听器对象 Publicvoid onClick(Viewv) { TestReceivertr= newTestReceiver(); Intentintent=newIntent(); intent.setAction(Intent.ACTION_EDIT); // 与 AndroidManifest 中的过滤内容 对比 TestActivity.this.sendBroadcast(intent); } 4.BroadcastReceiver 的生命周期 5. 注册 BroadcastReceiver 的方法 BroadcastReceiver 用 于 监 听 被 广 播 的 事 件 (Intent) 为 了 达 到 这 个 目 的,BroadcastReceiver 必须进行注册,以下是注册的两种方法 在应用程序的代码当中进行注册 注册 BroadcastReceiver registerReceiver(receiver,filter) 取消注册 UnregisterReceiver(receiver); Activity 中代码 例 : 1 . 声明控件对象(略) 2 . 获得控件对象(略) 3 . 绑定事件(略) 4 . 创建监听器对象 // 绑定广播事件 Publicvoid onClick(Viewv) { // 生成 receiver 对象 smsReceiver=newSMSReceiver(); IntentFilterfilter=newIntentFilter(); filter.addAction("android.provider.Telephony.SMS_RECEIVED"); // 注册广播事件 TestActivity.this.registerReceiver(smsReceiver,filter); } // 接触广播事件 Publicvoid onClick(Viewv) { TextActicity.this.unregisterReceiver(smsReceiver); } PublicclassSMSReceiverextendsBroadcastReceiver { @override Publicvoid onReceive(Contextcontext, Intentintent){ System.out,println("receivemessage"); // 对接受的短消息进行处理 // 接受 Intent 对象中的数据 Bundlebundle=Intent.getExtras(); // 在 Bundle 对象当中有一个属性名为 pdus, 这个属性的值是一个 Object 数组 Object[]myObjects=(Object[]) bundle.get("pdus"); // 创建一个 SmsMessage 类型的数组 SmsMessage[]message=newSmsMessage(myObjects.length); System.out,println(message.length); For(inti=0;i 6.Android 内置的 BroadcastActions 十七 十七 十七 十七 . . . .WIFI WIFI WIFI WIFI的操作 的操作 的操作 的操作 1. 什么是 WIFI WIFI 就是一种无线联网的技术 , 则又称为"热点" 2. 获取 WIFI 网卡的状态 0--> 正在关闭 1--> 关闭状态 2--> 正在打开 3--> 网卡可用 4--> 位置状态 3. 操作 WIFI 所需要的权限 4. 改变 WIFI 网卡的状态 例 : 1 . 声明控件对象(略) 2 . 获得控件对象(略) 3 . 绑定事件(略) 4 . 创建监听器对象 Public void onClick(View v ) { WifiManager wifiManager = (WifiManager)WifiActivity.this.getSystemService(Serivce.WIFI_SERVICE); wifiManager.setWifiEnabled(true); // 打开 WIfi 网卡 false 关闭 System.out.println("wifi state --->" + wifiManager.getWifiState()); Toast.makeText(WifuActivity.this , " 当 前 的 WIFI 网 卡 状 态 为 " + wifiManager.getWifiState()); } 十八 十八 十八 十八 . . . .Scoket Scoket Scoket Scoket编程 编程 编程 编程 1. 什么是 Socket Socket 英文意为"插座" 所谓 Scoket 通常也称作"套接字",用于描述 IP 地址和端口,是一个通信链的句柄 应用程序通常通过"套接字"向网络发出请求或者应答网络请求 2.Socket 基本通信模型 3. 使用基于 TCP 协议的 Socket ServerSocketActivity 代码 例 : 1 . 声明控件对象(略) 2 . 获得控件对象(略) 3 . 绑定事件(略) 4 . 创建监听器对象 Public void onClick(View v) { New ServerThread().start(); } // TCPserver Class ServerThread extends Thread { Public void run () { // 声明一个 serverSocket 对象 ServerSocket serverSocket = null; Try { // 创建 serverSocket 对象并在 4567 端口监听 serverSocket = new ServerSocket(4567); // 调用 serverSocket 的 accept 方法,接受客户端所发送的请求 Socket socket = serverSocket.accept(); // 阻塞函数 // 从 socket 当中得到 inputstream 对象 InputStream inputStream = socket.getInputStream(); Byte buffer [] new bute [1024 * 4]; Int temp = 0 ; // 从 inputStream 当中读取客户端所发送的数据 While ((temp = inputStream.read(buffer)) != -1) { System.out,println(new String(buffer , 0 ,temp)); } } catch (Execption e) { e.printStackTrace(); } finally { Try { serverSocket.close(); } catch (IOExecption e) { e.printStackTrace(); } } } } TCPClient 代码 例 : Public static void main (String [] args) { Try { // 创建一个 Socket 对象,指定服务器端的 ip 地址和端口号 Socket socket = new Socket("192.168.1.1" , 4567); // 使用 InputStream 读取硬盘上的文件 InputStream inputStream = new FileInputStream("F://file/words.txt"); // 从 Socket 上得到 outputStream outputStream outputStream = socket.getOutputStream(); Byte buffer [] = new byte[4*1024]; Int temp = 0; // 将 inputStream 的数据取出并写入到 outputStream While ((temp = inputStream.read(buffer)) != -1) { outputStream.write(buffer , 0 ,temp); } outpurStream.flush(); } catch (Execption e) { e.printStackTrace(); } } // UDPServer Class ServerThread extends Thread { Public void run () { Try { // 创建一个 DatagramSocket 对象,并制定监听端口号 DatagramSocket socket = new DatagramSocket(4567); Byte data [] = new byte [1024]; // 创建一个空的 DatagramPacket 对象 DatagramPacket packet = new DatagramPacket (data , data.length); // 使用 receive 方法接受客户端所发送的数据 Socket.receive(packet); // 阻塞方法 String result = new String(packet.getData() , packet.getOffset() , packet.getLength()); // 设置数据偏移量 , 得到该次数据的长度 System.out.println("result-->" + result); } catch (Execption e) { e.printStackTrace(); } } } // UDPClient Public static void main (String [] args) { Try { // 创建一个 DatagramSocket 对象,并制定监听端口号 DatagramSocket socket = new DatagramSocket(4567); InetAddress serverAddress = InetAddress.getByName("192.168.1.1"); String str = "hello"; Byte data [] = str.getBytes(); DatagramPacket packet = new DatagramPacket(data , data.length , serverAddress , 4567); Socket.send(packet); } catch (Execption e) { e.printStackTrace(); } } 4 . 使用基于 UDP 协议的 Socket 十九 十九 十九 十九 . . . .Service Service Service Service初步 初步 初步 初步 1 . Service 是什么 是一个应用程序组件 没有图形化界面 通常处理一些耗时较长的操作 可以是使用 service 更新 ContnetProvider.发送 intnet 以及启动系统的通知等等 2 . Service 不是什么 不是一个单独的进程 不是一个线程 3 . Service 生命周期 4 . 启动和停止 Service 的方法 服务 例 : public class FirstService extends Service { @Override Public IBinder onBind(Intent intent) { System.out.println("Service onBind"); Return null; } @Override Public void onCreate() { super.onCreate(); System.out.println("Service onCreate"); } // 启动服务时方法 @Override Public int onStartCommand(Intent intent , int flage , int startId) { System.out.println("flags -->" + flags); System.out.println("startId --> " + startId); System.out.println("service onStartCommand"); Return START_NOT_STICKY; } @Override Public void onDestroy() { System.out.println("Service onDestroy"); super.onDestroy(); } } 在 AndroidMnaifest.xml 中注册服务 : 在 Activity 中调用 Service 例: 1 . 声明控件对象(略) 2 . 获得控件对象(略) 3 . 绑定事件(略) 4 . 创建监听器对象 // 启动服务 Public void onClick(View v) { Intent intent = new Intent(); intent.setClass(Activity.this , FirstService.class); startService(intent); } // 停止服务 Public void onClick(View v) { Intent intent = new Intent(); intent.setClass(Activity.this , FirstService.class); stopService(intent); } 二十 二十 二十 二十 . . . . 项目 项目 项目 项目 ...展开收缩
(系统自动生成,下载前可以参看下载内容)
下载文件列表
相关说明
- 本站资源为会员上传分享交流与学习,如有侵犯您的权益,请联系我们删除.
- 本站是交换下载平台,提供交流渠道,下载内容来自于网络,除下载问题外,其它问题请自行百度。
- 本站已设置防盗链,请勿用迅雷、QQ旋风等多线程下载软件下载资源,下载后用WinRAR最新版进行解压.
- 如果您发现内容无法下载,请稍后再次尝试;或者到消费记录里找到下载记录反馈给我们.
- 下载后发现下载的内容跟说明不相乎,请到消费记录里找到下载记录反馈给我们,经确认后退回积分.
- 如下载前有疑问,可以通过点击"提供者"的名字,查看对方的联系方式,联系对方咨询.