Android數據存儲方式:java
SharedPreferences存儲mysql
手機內部文件存儲android
手機外部文件存儲sql
sqlite數據庫存儲shell
遠程服務器存儲數據庫
2. 數據存儲開發apache
SP存儲專門用來存儲一些單一的小數據瀏覽器
存儲數據的類型:boolean,float,int,long,String服務器
數據保存的路徑:/data/data/packageName/shared_prefs/yyy.xml網絡
能夠設置數據只能是當前應用讀取,而別的應用不能夠
應用卸載時會刪除數據
SharedPrefences:對應sp文件的接口
context.getSharedPreferences(String name,int mode)
:獲得SP對象
name:文件名(不帶.xml)
mode:生成的文件模式(是不是私有的,即其它應用是否能夠訪問)
Editor sp.edit()
:獲得Editor對象
Xxx sp.getXxx(name, defaultValue)
:根據name獲得對應的數據
Editor:能更新SP文件的接口
Editor put(name, value)
:保存一個鍵值對,沒有真正保存到文件中
Editor remove(name)
commit()
:提交,數據真正保存到文件中
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <EditText android:id="@+id/et_sp_key" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="存儲的key" /> <EditText android:id="@+id/et_sp_value" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="存儲的value" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="save" android:text="保 存" /> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="read" android:text="讀 取" /> </LinearLayout> </LinearLayout>
/** * 測試sp存儲的界面 */ public class SpActivity extends Activity { private EditText et_sp_key; private EditText et_sp_value; private SharedPreferences sp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sp); et_sp_key = (EditText) findViewById(R.id.et_sp_key); et_sp_value = (EditText) findViewById(R.id.et_sp_value); //1. 獲得sp對象 sp = getSharedPreferences("atguigu", Context.MODE_PRIVATE); } public void save(View v) { //2. 獲得editor對象 SharedPreferences.Editor edit = sp.edit(); //3. 獲得輸入的key/value String key = et_sp_key.getText().toString(); String value = et_sp_value.getText().toString(); //4. 使用editor保存key-value edit.putString(key, value).commit(); //5. 提示 Toast.makeText(this, "保存完成!", 0).show(); } public void read(View v) { //1. 獲得輸入的key String key = et_sp_key.getText().toString(); //2. 根據key讀取對應的value String value = sp.getString(key, null); //3. 顯示 if(value==null) { Toast.makeText(this, "沒有找到對應的value", 0).show(); } else { et_sp_value.setText(value); } } }
package com.atguigu.l04_datastorage; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } // 測試sp存儲 public void onClickSP(View v) { startActivity(new Intent(this, SpActivity.class)); } // 測試手機內部文件存儲 public void onClickIF(View v) { startActivity(new Intent(this, IFActivity.class)); } // 測試手機外部文件存儲 public void onClickOF(View v) { startActivity(new Intent(this, OFActivity.class)); } public void onClickDB(View v) { } public void onClickNW(View v) { } }
應用運行須要的一些較大的數據或圖片能夠用文件保存在手機內部
文件類型:任意
數據保存的路徑:/data/data/projectPackage/files/
能夠設置數據只能是當前應用讀取,而別的應用不能夠
應用卸載時會刪除此數據
讀取文件
FileInputStream fis = openFileInput("logo.png");
FileOutputStream fos = openFileOutput("logo.png",MODE_PRIVATE);
File filesDir = getFilesDir();
context.getAssets();
InputStream open(filename);
Bitmap BitmapFactory.decodeFile(String pathName)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/textView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="5dp" android:text="1. 將asserts下的logo.png保存到手機內部\n2. 讀取手機內部圖片文件顯示" android:textColor="#ff0000" android:textSize="15sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <Button android:id="@+id/btn_if_save" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="save" android:text="保 存" /> <Button android:id="@+id/btn_if_read" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="read" android:text="讀 取" /> </LinearLayout> <ImageView android:id="@+id/iv_if" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" /> </LinearLayout>
package com.atguigu.l04_datastorage; import android.app.Activity; import android.content.Context; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.Toast; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; /** * 測試手機內部文件存儲 */ public class IFActivity extends Activity { private ImageView iv_if; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_if); iv_if = findViewById(R.id.iv_if); } public void save(View view) throws IOException { //1.獲得InputStream ->讀取assets下的logo.png //獲得AssetManager AssetManager manager = getAssets(); //讀取文件 InputStream is = manager.open("logo.png"); //2.獲得OutputStream->/data/data/packageName/files/logo.png FileOutputStream fos = openFileOutput("logo.png", Context.MODE_PRIVATE); //3.邊讀邊寫 byte[] buffer = new byte[1024]; int len = 1; while((len = is.read(buffer)) != -1){ fos.write(buffer,0,len); } fos.close(); is.close(); //4.提示 Toast.makeText(this,"保存完成",Toast.LENGTH_SHORT).show(); } // /data/data/packageName/files/logo.png public void read(View view){ //1. 獲得圖片文件的路徑 /data/data/packageName/files String filesPath = getFilesDir().getAbsolutePath(); String imagePath = filesPath + "/logo.png"; //2.讀取加載圖片文件獲得bitmap對象 Bitmap bitmap = BitmapFactory.decodeFile(imagePath); //3.將其設置到imageView中顯示 iv_if.setImageBitmap(bitmap); } }
應用運行用到的數據文件(如圖片)能夠保存到sd卡中
文件類型:任意
數據保存的路徑:
路徑1:/storage/sdcard/Android/data/packageName/files/
路徑2:/storage/sdcard/xx/
路徑1:其它應用能夠訪問,應用卸載時刪除
路徑2:共它應用能夠訪問,應用卸載時不會刪除
必須保證sd卡掛載在手機上才能讀寫,不然不能操做
獲得SD卡的狀態:Environment.getExternalStorageState()
提到SD卡的路徑:Environment.getExternalStorageDirectory()
SD卡可讀寫的掛載狀態值:Enviroment.MEDIA_MOUNTED
context.getExternalFilesDir():
獲得/mnt/sdcard/Android/data/package_name/files/xxx.txt
操做SD卡的權限:
android.permission.WRITE_EXTERNAL_STORAGE
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <EditText android:id="@+id/et_of_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="存儲的文件名" /> <EditText android:id="@+id/et_of_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="存儲的文件內容" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="save" android:text="保 存" /> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="read" android:text="讀 取" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="save2" android:text="保 存2" /> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="read2" android:text="讀 取2" /> </LinearLayout> </LinearLayout>
package com.atguigu.l04_datastorage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.view.View; import android.widget.EditText; import android.widget.Toast; /** * 測試手機外部文件存儲 */ public class OFActivity extends Activity { private EditText et_of_name; private EditText et_of_content; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_of); et_of_name = (EditText) findViewById(R.id.et_of_name); et_of_content = (EditText) findViewById(R.id.et_of_content); } public void save(View v) throws IOException { //1. 判斷sd卡狀態, 若是是掛載的狀態才繼續, 不然提示 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { //2. 讀取輸入的文件名/內容 String fileName = et_of_name.getText().toString(); String content = et_of_content.getText().toString(); //3. 獲得指定文件的OutputStream //1).獲得sd卡下的files路徑 String filesPath = getExternalFilesDir(null).getAbsolutePath(); //2).組成完整路徑 String filePath = filesPath+"/"+fileName; //3). 建立FileOutputStream FileOutputStream fos = new FileOutputStream(filePath); //4. 寫數據 fos.write(content.getBytes("utf-8")); fos.close(); //5. 提示 Toast.makeText(this, "保存完成", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "sd卡沒有掛載", Toast.LENGTH_SHORT).show(); } } public void read(View v) throws Exception { // 1. 判斷sd卡狀態, 若是是掛載的狀態才繼續, 不然提示 if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { // 2. 讀取輸入的文件名 String fileName = et_of_name.getText().toString(); // 3. 獲得指定文件的InputStream // 1).獲得sd卡下的files路徑 String filesPath = getExternalFilesDir(null).getAbsolutePath(); // 2).組成完整路徑 String filePath = filesPath + "/" + fileName; // 3). 建立FileInputStream FileInputStream fis = new FileInputStream(filePath); // 4. 讀取數據, 成String ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while((len=fis.read(buffer))!=-1) { baos.write(buffer, 0, len); } String content = baos.toString(); // 5. 顯示 et_of_content.setText(content); } else { Toast.makeText(this, "sd卡沒有掛載", Toast.LENGTH_SHORT).show(); } } // /storage/sdcard/atguigu/xxx.txt public void save2(View v) throws IOException { //1. 判斷sd卡狀態, 若是是掛載的狀態才繼續, 不然提示 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { //2. 讀取輸入的文件名/內容 String fileName = et_of_name.getText().toString(); String content = et_of_content.getText().toString(); //3. 獲得指定文件的OutputStream //1). /storage/sdcard/ String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath(); //2). /storage/sdcard/atguigu/(建立文件夾) File file = new File(sdPath+"/atguigu"); if(!file.exists()) { file.mkdirs();//建立文件夾 } //3). /storage/sdcard/atguigu/xxx.txt String filePath = sdPath+"/atguigu/"+fileName; //4). 建立輸出流 FileOutputStream fos = new FileOutputStream(filePath); //4. 寫數據 fos.write(content.getBytes("utf-8")); fos.close(); //5. 提示 Toast.makeText(this, "保存完成", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "sd卡沒有掛載", Toast.LENGTH_SHORT).show(); } } public void read2(View v) throws Exception { // 1. 判斷sd卡狀態, 若是是掛載的狀態才繼續, 不然提示 if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { // 2. 讀取輸入的文件名 String fileName = et_of_name.getText().toString(); // 3. 獲得指定文件的InputStream String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath(); String filePath = sdPath+"/atguigu/"+fileName; FileInputStream fis = new FileInputStream(filePath); // 4. 讀取數據, 成String ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while((len=fis.read(buffer))!=-1) { baos.write(buffer, 0, len); } String content = baos.toString(); fis.close(); // 5. 顯示 et_of_content.setText(content); } else { Toast.makeText(this, "sd卡沒有掛載", Toast.LENGTH_SHORT).show(); } } }
是不是私有的
應用卸載是否自動刪除
應用運行須要保存一系列有必定結構的數據,好比說公司員工信息
文件類型:db
數據保存的路徑 :/data/data/projectPackage/databases/xxx.db
默認狀況下其它應用不能訪問,當前應用能夠經過ContentProvider提供其它應用操做
應用卸載時會刪除此數據
SQLite(http://www.sqlite.org),是一款輕型的關係型數據庫服務器,移動設備的數據庫存儲都使用SQLite,它的特色:
安裝文件小:最小隻有幾百K,Android系統已經安裝
支持多操做系統:Android,WP,IOS,Windows,Linux等
支持多語言:好比Java、PHP、C#等
處理速度快:處理速度比Mysql,Oracle,SQLServer都要快(數據量不是特別大)
SQLite中的一個數據庫就是一個.db文件(本質上.db的後綴均可以不指定)
adb shell 進入系統根目錄
cd data/data/…/databases:進入包含數據庫文件的文件夾下
sqlite3 contacts2.db:使用sqlite3命令鏈接指定的數據庫文件,進入鏈接模式
help:查看命令列表
tables:查看全部表的列表
執行 insert/delete/update/select語句
exit:退出數據庫鏈接模式
Ctrl+C:直接退出shell模式
INT/INTEGER:整數
FLOAT/DOUBLE:小數
CHAR/VARCHAR/TEXT:字符串文本
BLOB:文件
DATE/DATETIME:日期/日期時間
SQLite操做數據庫的sql語句基本與mysql同樣,但須要注意下面2點:
最大的不一樣在於建立表時能夠不用指定字段類型,sqlite能夠適時的自動轉換,但除varchar類型外最好指定類型
sqlite中的主鍵名稱建議使用_id
create table employee( _id integer primary key autoincrement,/*主鍵,自增加*/ name varchar, /* 字符串*/ salary double, /* 小數 */ birthday date /* 日期,可直接插入日期格式字符串*/ )
/*插入*/ INSERT INTO employee(name,salary,birthday) VALUES('Tom',8000,'1988-09-21'); /*刪除*/ DELETE FROM employee WHERE _id=2 /*更新*/ UPDATE employee SET name='Jack',salary=salary+1000 WHERE _id=1 /*查找*/ SELECT * FROM employee WHERE _id=3
SQLiteOpenHelper(Context context,String name, CursorFactory
factory, int version):構造方法,指定數據庫文件名和版本號
abstract void onCreate(SQLiteDatabases db):用於建立表
abstract void onUpgrade():用於版本更新
SqliteDatabase getReadableDatabase():獲得數據庫鏈接
sqliteDatabase:表明與數據庫的鏈接的類
long insert():用於執行insert SQL,返回id值
int update():用於執行update SQL
int delete():用於執行delete SQL
Cursor query():用於執行select SQL,返回包含查詢結果數據的Cursor
void execSql(sql):執行sql語句
beginTransaction():開啓事務
setTransactionSuccessful():設置事務是成功的
endTransaction():結束事務,可能提交事務或回滾事務
openDatabase(String path, CursorFactory factory, int flags):獲得數據庫鏈接
Cursor:包含全部查詢結果記錄的結果集對象(光標,遊標)
int getCount():匹配的總記錄數
boolean moveToNext():將遊標移動到下一條記錄的前面
Xxx getXxx(columnIndex):根據字段下標獲得對應值
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="testCreateDB" android:text="Create DB" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="testUpdateDB" android:text="Update DB" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="testInsert" android:text="Insert" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="testUpdate" android:text="Update" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="testDelete" android:text="Delete" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="testQuery" android:text="query" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="testTransaction" android:text="Test Transaction" /> </LinearLayout>
package com.atguigu.l04_datastorage; import android.app.Activity; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Toast; /** * 測試Sqlite數據庫存儲 * */ public class DBActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_db); } /* * 建立庫 */ public void testCreateDB(View v) { DBHelper dbHelper = new DBHelper(this, 1); //獲取鏈接 SQLiteDatabase database = dbHelper.getReadableDatabase(); Toast.makeText(this, "建立數據庫", 0).show(); } /* * 更新庫 */ public void testUpdateDB(View v) { DBHelper dbHelper = new DBHelper(this, 2); //獲取鏈接 SQLiteDatabase database = dbHelper.getReadableDatabase(); Toast.makeText(this, "更新數據庫", 0).show(); } /* * 添加記錄 */ public void testInsert(View v) { //1. 獲得鏈接 DBHelper dbHelper = new DBHelper(this, 2); SQLiteDatabase database = dbHelper.getReadableDatabase(); //2. 執行insert insert into person(name, age) values('Tom', 12) ContentValues values = new ContentValues(); values.put("name", "Tom"); values.put("age", 12); long id = database.insert("person", null, values); //3. 關閉 database.close(); //4. 提示 Toast.makeText(this, "id="+id, 1).show(); } /* * 更新 */ public void testUpdate(View v) { DBHelper dbHelper = new DBHelper(this, 2); SQLiteDatabase database = dbHelper.getReadableDatabase(); //執行update update person set name=Jack, age=13 where _id=4 ContentValues values = new ContentValues(); values.put("name", "jack"); values.put("age", 13); int updateCount = database.update("person", values , "_id=?", new String[]{"4"}); database.close(); Toast.makeText(this, "updateCount="+updateCount, 1).show(); } /* * 刪除 */ public void testDelete(View v) { // 1. 獲得鏈接 DBHelper dbHelper = new DBHelper(this, 2); SQLiteDatabase database = dbHelper.getReadableDatabase(); // 2. 執行delete delete from person where _id=2 int deleteCount = database.delete("person", "_id=2", null); // 3. 關閉 database.close(); // 4. 提示 Toast.makeText(this, "deleteCount=" + deleteCount, 1).show(); } /* * 查詢 */ public void testQuery(View v) { // 1. 獲得鏈接 DBHelper dbHelper = new DBHelper(this, 2); SQLiteDatabase database = dbHelper.getReadableDatabase(); // 2. 執行query select * from person Cursor cursor = database.query("person", null, null, null, null, null, null); //cursor = database.query("person", null, "_id=?", new String[]{"3"}, null, null, null); //獲得匹配的總記錄數 int count = cursor.getCount(); //取出cursor中全部的數據 while(cursor.moveToNext()) { //_id int id = cursor.getInt(0); //name String name = cursor.getString(1); //age int age = cursor.getInt(cursor.getColumnIndex("age")); Log.e("TAG", id+"-"+name+"-"+age); } // 3. 關閉 cursor.close(); database.close(); // 4. 提示 Toast.makeText(this, "count=" + count, 1).show(); } /* * 測試事務處理 * update person set age=16 where _id=1 * update person set age=17 where _id=3 * * 一個功能中對數據庫進行的多個操做: 要就是都成功要就都失敗 * 事務處理的3步: * 1. 開啓事務(獲取鏈接後) * 2. 設置事務成功(在所有正常執行完後) * 3. 結束事務(finally中) */ public void testTransaction(View v) { SQLiteDatabase database = null; try{ DBHelper dbHelper = new DBHelper(this, 2); database = dbHelper.getReadableDatabase(); //1. 開啓事務(獲取鏈接後) database.beginTransaction(); //執行update update person set age=16 where _id=1 ContentValues values = new ContentValues(); values.put("age", 16); int updateCount = database.update("person", values , "_id=?", new String[]{"1"}); Log.e("TAG", "updateCount="+updateCount); //出了異常 boolean flag = true; if(flag) { throw new RuntimeException("出異常啦!!!"); } //執行update update person set age=17 where _id=3 values = new ContentValues(); values.put("age", 17); int updateCount2 = database.update("person", values , "_id=?", new String[]{"3"}); Log.e("TAG", "updateCount2="+updateCount2); //2. 設置事務成功(在所有正常執行完後) database.setTransactionSuccessful(); } catch(Exception e) { e.printStackTrace(); Toast.makeText(this, "出異常啦!!!", 1).show(); } finally { //3. 結束事務(finally中) if(database!=null) { database.endTransaction(); database.close(); } } } }
package com.atguigu.l04_datastorage; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; /** * 數據庫操做的幫助類 */ public class DBHelper extends SQLiteOpenHelper { public DBHelper(Context context,int version) { super(context, "atguigu.db", null, version); } /** * 何時纔會建立數據庫文件? * 1). 數據庫文件不存在 * 2). 鏈接數據庫 * * 何時調用? * 當數據庫文件建立時調用(1次) * 在此方法中作什麼? * 建表 * 插入一些初始化數據 */ @Override public void onCreate(SQLiteDatabase db) { Log.e("TAG", "DBHelper onCreate()"); //建表 String sql = "create table person(_id integer primary key autoincrement, name varchar,age int)"; db.execSQL(sql); //插入一些初始化數據 db.execSQL("insert into person (name, age) values ('Tom1', 11)"); db.execSQL("insert into person (name, age) values ('Tom2', 12)"); db.execSQL("insert into person (name, age) values ('Tom3', 13)"); } //當傳入的版本號大於數據庫的版本號時調用 @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.e("TAG", "DBHelper onUpgrade()"); } }
1. 添加配置信息
<application> <!-- 使用android測試包 --> <uses-library android:name="android.test.runner" /> </application> <!-- android:targetPackage的值應與manifest的package的值一致 --> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.atguigu.app04_sqlite" />
2. 編寫測試類
class StudentTest extends AndroidTestCase
- JDK內置的原生API
HttpUrlConnection
- Android內置的包裝API
HttpClient 瀏覽器
- 異步網絡請求框架
URL : 包含請求地址的類
URL(path) : 包含請求路徑的構造方法
openConnection() : 獲得鏈接對象
HttpURLConnection : 表明與服務器鏈接的類
setMethod(「GET/POST」) : 設置請求方式
setConnectTimeout(time) : 設置鏈接超時時間, 單位爲ms
setReadTimeout(time): 設置讀取服務器返回數據的時間
connect() : 鏈接服務器
int getResponseCode(): 獲得服務器返回的結果碼
Int getContentLength() : 獲得服務器返回數據的長度(字節)
getOutputStream() : 返回一個指向服務器端的數據輸出流
getInputStream() : 返回一個從服務器端返回的數據輸入流
disconnect() : 斷開鏈接
HttpClient/DefaultHttpClient : 能提交請求的客戶端對象
HttpResponse execute (HttpUriRequest request) 執行包含請求數據的請求對象, 返回包含響應數據的響應對象
HttpParams getParams() 獲得包含請求參數的對象
HttpConnectionParams : 設置請求參數的工具類
static setConnectionTimeout(params, time) : 設置獲取鏈接的超時時間
static setSoTimeout(params, time): 設置讀取數據的超時時間
HttpGet : Get請求
HttpGet(String path) : 包含請求路徑的構造方法
HttpPost : Post請求
HttpPost(String path) : 包含請求路徑的構造方法
setEntity(HttpEntity entity) : 設置請求體
NameValuePair/BasicNameValuePair : 包含參數鍵值對
BasicNameValuePair (String name, String value)
HttpResponse : 服務器返回的響應
getStatusLine() : 獲得響應狀態行, 從而獲得狀態碼
getEntity() : 獲得響應體數據對象
EntityUtils : 解析HttpEntity的工具類
toString(httpEntity): 解析響應體, 得其內容字符串
關閉鏈接, 釋放資源:
client.getConnectionManager().shutdown();
Volley是Google 2013年的 I/O大會 上,發佈了的一個框架
Volley是Android上的網絡通訊庫,能使網絡通訊更快,更簡單,更健壯
Volley特別適合數據量不大可是通訊頻繁的場景: 帶圖片的列表
RequestQueue : 請求隊列, 會自動執行隊列中的請求
Volley. newRequestQueue(context) : 建立一個請求隊列
addReqeust(Request reqeust) : 將請求添加到請求隊列
Request<T>: 表明請求的接口
JsonRequest : 獲取Json數據結果的請求
ImageRequest : 獲取圖片結果的請求
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <EditText android:id="@+id/et_network_url" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textUri" android:text="@string/url" > </EditText> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="1. 測試HttpUrlConnection" android:textSize="20dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="testConnectionGet" android:text="GET請求" /> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="testConnectionPost" android:text="POST請求" /> </LinearLayout> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="2. 測試HttpClient" android:textSize="20dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="testClientGet" android:text="GET請求" /> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="testClientPost" android:text="POST請求" /> </LinearLayout> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="3. 測試Volley框架" android:textSize="20dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="testVolleyGet" android:text="GET請求" /> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="testVolleyPost" android:text="POST請求" /> </LinearLayout> <EditText android:id="@+id/et_network_result" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:hint="用來顯示網絡請求返回的結果數據" > </EditText> </LinearLayout>
package com.atguigu.l04_datastorage; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.util.EntityUtils; import com.android.volley.Request.Method; import com.android.volley.AuthFailureError; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.Volley; import android.app.Activity; import android.app.ProgressDialog; import android.os.Bundle; import android.view.View; import android.widget.EditText; public class NetworkActivity extends Activity { private EditText et_network_url; private EditText et_network_result; private RequestQueue queue; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_network); et_network_url = (EditText) findViewById(R.id.et_network_url); et_network_result = (EditText) findViewById(R.id.et_network_result); queue = Volley.newRequestQueue(this); } /* * 使用httpUrlConnection提交get請求 */ /* 1. 顯示ProgressDialog 2. 啓動分線程 3. 在分線程, 發送請求, 獲得響應數據 1). 獲得path, 並帶上參數name=Tom1&age=11 2). 建立URL對象 3). 打開鏈接, 獲得HttpURLConnection對象 4). 設置請求方式,鏈接超時, 讀取數據超時 5). 鏈接服務器 6). 發請求, 獲得響應數據 獲得響應碼, 必須是200纔讀取 獲得InputStream, 並讀取成String 7). 斷開鏈接 4. 在主線程, 顯示獲得的結果, 移除dialog */ public void testConnectionGet(View v) { //1. 顯示ProgressDialog final ProgressDialog dialog = ProgressDialog.show(this, null, "正在請求中..."); //2. 啓動分線程 new Thread(){ //3. 在分線程, 發送請求, 獲得響應數據 public void run() { try { //1). 獲得path, 並帶上參數name=Tom1&age=11 String path = et_network_url.getText().toString()+"?name=Tom1&age=11"; //2). 建立URL對象 URL url = new URL(path); //3). 打開鏈接, 獲得HttpURLConnection對象 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //4). 設置請求方式,鏈接超時, 讀取數據超時 connection.setRequestMethod("GET"); connection.setConnectTimeout(5000); connection.setReadTimeout(6000); //5). 鏈接服務器 connection.connect(); //6). 發請求, 獲得響應數據 //獲得響應碼, 必須是200纔讀取 int responseCode = connection.getResponseCode(); if(responseCode==200) { //獲得InputStream, 並讀取成String InputStream is = connection.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while((len=is.read(buffer))!=-1) { baos.write(buffer, 0, len); } final String result = baos.toString(); baos.close(); is.close(); //4. 在主線程, 顯示獲得的結果, 移除dialog runOnUiThread(new Runnable() { @Override public void run() { et_network_result.setText(result); dialog.dismiss(); } }); } //7). 斷開鏈接 connection.disconnect(); } catch (Exception e) { e.printStackTrace(); //若是出了異常要移除dialog dialog.dismiss(); } } }.start(); } /* * 使用httpUrlConnection提交post請求 */ /* 1. 顯示ProgressDialog 2. 啓動分線程 3. 在分線程, 發送請求, 獲得響應數據 1). 獲得path 2). 建立URL對象 3). 打開鏈接, 獲得HttpURLConnection對象 4). 設置請求方式,鏈接超時, 讀取數據超時 5). 鏈接服務器 6). 發請求, 獲得響應數據 獲得輸出流, 寫請求體:name=Tom1&age=11 獲得響應碼, 必須是200纔讀取 獲得InputStream, 並讀取成String 7). 斷開鏈接 4. 在主線程, 顯示獲得的結果, 移除dialog */ public void testConnectionPost(View v) { //1. 顯示ProgressDialog final ProgressDialog dialog = ProgressDialog.show(this, null, "正在加載中..."); //2. 啓動分線程 new Thread(new Runnable() { //3. 在分線程, 發送請求, 獲得響應數據 @Override public void run() { try { //1). 獲得path String path = et_network_url.getText().toString(); //2). 建立URL對象 URL url = new URL(path); //3). 打開鏈接, 獲得HttpURLConnection對象 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //4). 設置請求方式,鏈接超時, 讀取數據超時 connection.setRequestMethod("POST"); connection.setConnectTimeout(5000); connection.setReadTimeout(5000); //5). 鏈接服務器 connection.connect(); //6). 發請求, 獲得響應數據 //獲得輸出流, 寫請求體:name=Tom1&age=11 OutputStream os = connection.getOutputStream(); String data = "name=Tom2&age=12"; os.write(data.getBytes("utf-8")); //獲得響應碼, 必須是200纔讀取 int responseCode = connection.getResponseCode(); if(responseCode==200) { //獲得InputStream, 並讀取成String InputStream is = connection.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while((len=is.read(buffer))!=-1) { baos.write(buffer, 0, len); } final String result = baos.toString(); baos.close(); is.close(); //4. 在主線程, 顯示獲得的結果, 移除dialog runOnUiThread(new Runnable() { @Override public void run() { et_network_result.setText(result); dialog.dismiss(); } }); } os.close(); //7). 斷開鏈接 connection.disconnect(); } catch (Exception e) { e.printStackTrace(); dialog.dismiss(); } } }).start(); } /* * 使用httpClient提交get請求 */ public void testClientGet(View v) { //1. 顯示ProgressDialog final ProgressDialog dialog = ProgressDialog.show(this, null, "正在請求中..."); //2. 啓動分線程 new Thread(){ //3. 在分線程, 發送請求, 獲得響應數據 public void run() { try { //1). 獲得path, 並帶上參數name=Tom1&age=11 String path = et_network_url.getText().toString()+"?name=Tom3&age=13"; //2). 建立HttpClient對象 HttpClient httpClient = new DefaultHttpClient(); //3). 設置超時 HttpParams params = httpClient.getParams(); HttpConnectionParams.setConnectionTimeout(params, 5000); HttpConnectionParams.setSoTimeout(params, 5000); //4). 建立請求對象 HttpGet request = new HttpGet(path); //5). 執行請求對象, 獲得響應對象 HttpResponse response = httpClient.execute(request); int statusCode = response.getStatusLine().getStatusCode(); if(statusCode==200) { //6). 獲得響應體文本 HttpEntity entity = response.getEntity(); final String result = EntityUtils.toString(entity); //4. 要主線程, 顯示數據, 移除dialog runOnUiThread(new Runnable() { @Override public void run() { et_network_result.setText(result); dialog.dismiss(); } }); } //7). 斷開鏈接 httpClient.getConnectionManager().shutdown(); } catch (Exception e) { e.printStackTrace(); //若是出了異常要移除dialog dialog.dismiss(); } } }.start(); } /* * 使用httpClient提交post請求 */ public void testClientPost(View v) { //1. 顯示ProgressDialog final ProgressDialog dialog = ProgressDialog.show(this, null, "正在請求中..."); //2. 啓動分線程 new Thread(){ //3. 在分線程, 發送請求, 獲得響應數據 public void run() { try { //1). 獲得path String path = et_network_url.getText().toString(); //2). 建立HttpClient對象 HttpClient httpClient = new DefaultHttpClient(); //3). 設置超時 HttpParams params = httpClient.getParams(); HttpConnectionParams.setConnectionTimeout(params, 5000); HttpConnectionParams.setSoTimeout(params, 5000); //4). 建立請求對象 HttpPost request = new HttpPost(path); //設置請求體 List<BasicNameValuePair> parameters = new ArrayList<BasicNameValuePair>(); parameters.add(new BasicNameValuePair("name", "Tom4")); parameters.add(new BasicNameValuePair("age", "14")); HttpEntity entity = new UrlEncodedFormEntity(parameters); request.setEntity(entity); //5). 執行請求對象, 獲得響應對象 HttpResponse response = httpClient.execute(request); int statusCode = response.getStatusLine().getStatusCode(); if(statusCode==200) { //6). 獲得響應體文本 entity = response.getEntity(); final String result = EntityUtils.toString(entity); //4. 要主線程, 顯示數據, 移除dialog runOnUiThread(new Runnable() { @Override public void run() { et_network_result.setText(result); dialog.dismiss(); } }); } //7). 斷開鏈接 httpClient.getConnectionManager().shutdown(); } catch (Exception e) { e.printStackTrace(); //若是出了異常要移除dialog dialog.dismiss(); } } }.start(); } /* * 使用Volley提交get請求 */ /* 1. 建立請求隊列對象(一次) 2. 建立請求對象StringRequest 3. 將請求添加到隊列中 */ public void testVolleyGet(View v) { final ProgressDialog dialog = ProgressDialog.show(this, null, "正在請求中..."); //建立請求對象StringRequest String path = et_network_url.getText().toString()+"?name=Tom5&age=15"; StringRequest request = new StringRequest(path, new Response.Listener<String>() { @Override public void onResponse(String response) {//在主線程執行 et_network_result.setText(response); dialog.dismiss(); } }, null); //將請求添加到隊列中 queue.add(request); } /* * 使用Volley提交post請求 */ public void testVolleyPost(View v) { final ProgressDialog dialog = ProgressDialog.show(this, null, "正在請求中..."); //建立請求對象StringRequest String path = et_network_url.getText().toString(); StringRequest request = new StringRequest(Method.POST, path, new Response.Listener<String>() { @Override public void onResponse(String response) { et_network_result.setText(response); dialog.dismiss(); } }, null){ //重寫此方法返回參數的map做爲請求體 @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); map.put("name", "Tom6"); map.put("age", "16"); return map; } }; //將請求添加到隊列中 queue.add(request); } }
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">L04_DataStorage</string> <string name="hello_world">Hello world!</string> <string name="title_activity_sp">SpActivity</string> <string name="title_activity_if">IFActivity</string> <string name="title_activity_of">OFActivity</string> <string name="title_activity_db">DBActivity</string> <string name="title_activity_network">NetworkActivity</string> <string name="url">http://192.168.10.165:8080/Web_Server/index.jsp</string> </resources>
長按手機防盜, 顯示修改的Dialog
經過dialog修改手機防盜名稱
關鍵技術點:
SharedPreferences的使用
AlertDialog的使用
GridView+BaseAdapter的使用
功能描述:
黑名單添加
顯示全部黑名單列表
刪除指定黑名單
修改黑名單
關鍵技術點:
SQLite數據庫的操做
ListView列表顯示
AlertDialog的使用
1. 界面佈局 ListView 2. DBHelper 數據庫 表 3. 實體類 4. DAO並單元測試 5. 顯示列表 6. 添加 1. 顯示添加的dialog(帶輸入框) 2. 在肯定的回調方法實現: 1). 保存數據表中 2). 保存數據到List 3). 通知更新列表 問題1: 新添加的沒有顯示在第一行 add到集合中的第一位 問題2: 初始顯示的列表順序不對 查詢根據_id倒序 7. 刪除 1. 顯示ContextMenu 2. 響應對item的選擇 1). 刪除數據表對應的數據 2). 刪除List對應的數據 3). 通知更新列表 問題: 如何獲得長按的position? 8. 更新 1. 顯示更新的Dialog 2. 點擊肯定的響應 1). 更新數據表對應的數據 2). 更新List對應的數據 3). 通知更新列表 9. 使用ListActivity優化功能 1. extends ListActivity 2. 佈局文件中的<ListView>的id必須是系統定義的id: list 3. 若是想在沒有數據時顯示一個提示文本, 能夠在佈局中定義 一個<TextView>(id必須爲empty) /* 一個功能的主要工做 */ 1. 內存的操做(集合) 2. 存儲的操做(sp/數據庫/文件) 3. 界面的操做(列表)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> </ListView> <TextView android:id="@android:id/empty" android:layout_width="fill_parent" android:layout_height="0dp" android:layout_weight="1" android:text="尚未一個黑名單" android:gravity="center"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="添 加" android:onClick="add"/> </LinearLayout>
package com.atguigu.app04_sqlite; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; /** * 數據庫操做的幫助類 * */ public class DBHelper extends SQLiteOpenHelper { public DBHelper(Context context) { super(context, "atguigu.db", null, 1); } @Override public void onCreate(SQLiteDatabase db) { Log.i("TAG", "DBHelper onCreate()"); //建立表 db.execSQL("create table black_number(_id integer primary key autoincrement, number varchar)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
實體類BlackNumber.java
package com.atguigu.app04_sqlite; /** * black_number表對應的實體類 */ public class BlackNumber { private int id; private String number; public BlackNumber(int id, String number) { super(); this.id = id; this.number = number; } public BlackNumber() { super(); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } @Override public String toString() { return "BlackNumber [id=" + id + ", number=" + number + "]"; } }
package com.atguigu.app04_sqlite; import java.util.ArrayList; import java.util.List; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.util.Log; /** * 操做black_number表的DAO類 * */ public class BlackNumberDao { private DBHelper dbHelper; public BlackNumberDao(Context context) { dbHelper = new DBHelper(context); } /** * 添加一條記錄 * @param blackNumber */ public void add(BlackNumber blackNumber) { //1. 獲得鏈接 SQLiteDatabase database = dbHelper.getReadableDatabase(); //2. 執行insert insert into black_number (number) values(xxx) ContentValues values = new ContentValues(); values.put("number", blackNumber.getNumber()); long id = database.insert("black_number", null, values); Log.i("TAG", "id="+id); //設置id blackNumber.setId((int) id); //3. 關閉 database.close(); } /** * 根據id刪除一條記錄 */ public void deleteById(int id) { //1. 獲得鏈接 SQLiteDatabase database = dbHelper.getReadableDatabase(); //2. 執行delete delete from black_number where _id=id int deleteCount = database.delete("black_number", "_id=?", new String[]{id+""}); Log.i("TAG", "deleteCount="+deleteCount); //3. 關閉 database.close(); } /** * 更新一條記錄 */ public void update(BlackNumber blackNumber) { //1. 獲得鏈接 SQLiteDatabase database = dbHelper.getReadableDatabase(); //2. 執行update update black_number set number=xxx where _id=id ContentValues values = new ContentValues(); values.put("number", blackNumber.getNumber()); int updateCount = database.update("black_number", values , "_id="+blackNumber.getId(), null); Log.i("TAG", "updateCount="+updateCount); //3. 關閉 database.close(); } /** * 查詢全部記錄封裝成List<BLackNumber> */ public List<BlackNumber> getAll() { List<BlackNumber> list = new ArrayList<BlackNumber>(); //1. 獲得鏈接 SQLiteDatabase database = dbHelper.getReadableDatabase(); //2. 執行query select * from black_number Cursor cursor = database.query("black_number", null, null, null, null, null, "_id desc"); //3. 從cursor中取出全部數據並封裝到List中 while(cursor.moveToNext()) { //id int id = cursor.getInt(0); //number String number = cursor.getString(1); list.add(new BlackNumber(id, number)); } //4. 關閉 cursor.close(); database.close(); return list; } }
配置android測試包
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.atguigu.app04_sqlite" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <!-- 使用android測試包 --> <uses-library android:name="android.test.runner" /> <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <!-- android:targetPackage的值應與manifest的package的值一致 --> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.atguigu.app04_sqlite" /> </manifest>
測試用例
package com.atguigu.app04_sqlite.test; import java.util.List; import com.atguigu.app04_sqlite.BlackNumber; import com.atguigu.app04_sqlite.BlackNumberDao; import android.test.AndroidTestCase; import android.util.Log; /** * BlackNumberDao的單元測試類 * */ public class BlackNumberDaoTest extends AndroidTestCase { public void testAdd() { // 建立dao對象 BlackNumberDao dao = new BlackNumberDao(getContext()); // 調用方法 dao.add(new BlackNumber(-1, "123")); } public void testGetAll() { // 建立dao對象 BlackNumberDao dao = new BlackNumberDao(getContext()); // 調用方法 List<BlackNumber> list = dao.getAll(); Log.i("TAG", list.toString()); } public void testUpdate() { // 建立dao對象 BlackNumberDao dao = new BlackNumberDao(getContext()); // 調用方法 dao.update(new BlackNumber(2, "321")); } public void testDeleteById() { // 建立dao對象 BlackNumberDao dao = new BlackNumberDao(getContext()); // 調用方法 dao.deleteById(2); } }
package com.atguigu.app04_sqlite; import java.util.List; import android.app.AlertDialog; import android.app.ListActivity; import android.content.DialogInterface; import android.os.Bundle; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.BaseAdapter; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends ListActivity { private ListView lv_main; private BlackNumberAdapter adapter; private BlackNumberDao dao; private List<BlackNumber> data; private int position; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv_main = getListView(); adapter = new BlackNumberAdapter(); dao = new BlackNumberDao(this); data = dao.getAll(); lv_main.setAdapter(adapter); //給listView設置建立contextMenu的監聽 lv_main.setOnCreateContextMenuListener(this); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); //添加2個item menu.add(0, 1, 0, "更新"); menu.add(0, 2, 0, "刪除"); //獲得長按的position AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; position = info.position; } @Override public boolean onContextItemSelected(MenuItem item) { //獲得對應的BlackNumber對象 BlackNumber blackNumber = data.get(position); switch (item.getItemId()) { case 1://更新 //1. 顯示更新的Dialog showUpdateDialog(blackNumber); break; case 2://刪除 //1). 刪除數據表對應的數據 dao.deleteById(blackNumber.getId()); //2). 刪除List對應的數據 data.remove(position); //3). 通知更新列表 adapter.notifyDataSetChanged(); break; default: break; } return super.onContextItemSelected(item); } /** * 顯示更新的Dialog * @param blackNumber */ private void showUpdateDialog(final BlackNumber blackNumber) { final EditText editText = new EditText(this); editText.setHint(blackNumber.getNumber()); new AlertDialog.Builder(this) .setTitle("更新黑名單") .setView(editText) .setPositiveButton("更新", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //1). 更新List對應的數據 String newNumber = editText.getText().toString(); blackNumber.setNumber(newNumber); //2). 更新數據表對應的數據 dao.update(blackNumber); //3). 通知更新列表 adapter.notifyDataSetChanged(); } }) .setNegativeButton("取消", null) .show(); } public void add(View v) { //1. 顯示添加的dialog(帶輸入框) final EditText editText = new EditText(this); editText.setHint("輸入黑名單號"); new AlertDialog.Builder(this) .setTitle("添加黑名單") .setView(editText) .setPositiveButton("添加", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //1). 保存數據表中 String number = editText.getText().toString(); BlackNumber blackNumber = new BlackNumber(-1, number); dao.add(blackNumber); //2). 保存數據到List //data.add(blackNumber);//已經有id了 data.add(0, blackNumber); //3). 通知更新列表 adapter.notifyDataSetChanged(); } }) .setNegativeButton("取消", null) .show(); } class BlackNumberAdapter extends BaseAdapter { @Override public int getCount() { return data.size(); } @Override public Object getItem(int position) { return data.get(position); } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView==null) { convertView = View.inflate(MainActivity.this, android.R.layout.simple_list_item_1, null); } BlackNumber blackNumber = data.get(position); TextView textView = (TextView) convertView.findViewById(android.R.id.text1); textView.setText(blackNumber.getNumber()); return convertView; } } }
package com.atguigu.app04_sqlite; import java.util.List; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; import android.view.ContextMenu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.ContextMenu.ContextMenuInfo; import android.widget.BaseAdapter; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.widget.AdapterView.AdapterContextMenuInfo; public class MainActivity1 extends Activity { private ListView lv_main; private BlackNumberAdapter adapter; private BlackNumberDao dao; private List<BlackNumber> data; private int position; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //lv_main = (ListView) findViewById(R.id.lv_main); adapter = new BlackNumberAdapter(); dao = new BlackNumberDao(this); data = dao.getAll(); lv_main.setAdapter(adapter); //給listView設置建立contextMenu的監聽 lv_main.setOnCreateContextMenuListener(this); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); //添加2個item menu.add(0, 1, 0, "更新"); menu.add(0, 2, 0, "刪除"); //獲得長按的position AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; position = info.position; } @Override public boolean onContextItemSelected(MenuItem item) { //獲得對應的BlackNumber對象 BlackNumber blackNumber = data.get(position); switch (item.getItemId()) { case 1://更新 //1. 顯示更新的Dialog showUpdateDialog(blackNumber); break; case 2://刪除 //1). 刪除數據表對應的數據 dao.deleteById(blackNumber.getId()); //2). 刪除List對應的數據 data.remove(position); //3). 通知更新列表 adapter.notifyDataSetChanged(); break; default: break; } return super.onContextItemSelected(item); } /** * 顯示更新的Dialog * @param blackNumber */ private void showUpdateDialog(final BlackNumber blackNumber) { final EditText editText = new EditText(this); editText.setHint(blackNumber.getNumber()); new AlertDialog.Builder(this) .setTitle("更新黑名單") .setView(editText) .setPositiveButton("更新", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //1). 更新List對應的數據 String newNumber = editText.getText().toString(); blackNumber.setNumber(newNumber); //2). 更新數據表對應的數據 dao.update(blackNumber); //3). 通知更新列表 adapter.notifyDataSetChanged(); } }) .setNegativeButton("取消", null) .show(); } public void add(View v) { //1. 顯示添加的dialog(帶輸入框) final EditText editText = new EditText(this); editText.setHint("輸入黑名單號"); new AlertDialog.Builder(this) .setTitle("添加黑名單") .setView(editText) .setPositiveButton("添加", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //1). 保存數據表中 String number = editText.getText().toString(); BlackNumber blackNumber = new BlackNumber(-1, number); dao.add(blackNumber); //2). 保存數據到List //data.add(blackNumber);//已經有id了 data.add(0, blackNumber); //3). 通知更新列表 adapter.notifyDataSetChanged(); } }) .setNegativeButton("取消", null) .show(); } class BlackNumberAdapter extends BaseAdapter { @Override public int getCount() { return data.size(); } @Override public Object getItem(int position) { return data.get(position); } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView==null) { convertView = View.inflate(MainActivity1.this, android.R.layout.simple_list_item_1, null); } BlackNumber blackNumber = data.get(position); TextView textView = (TextView) convertView.findViewById(android.R.id.text1); textView.setText(blackNumber.getNumber()); return convertView; } } }
下載遠程服務器端的APK文件
同步顯示下載進度
下載完成自動安裝
關鍵技術點:
SD卡文件讀寫
ProgressDialog的使用
分線程請求網絡
安裝APK