編輯:關於Android編程
public class BroadcastReceiverTest extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //拿到我們注冊的廣播類型 String action = intent.getAction(); Log.d("TAG",action); //TODO 處理自己邏輯... } }注意:Android對廣播接受者中的onReceive()方法執行時間有限制,因此我們在onReceive中不能做一些非常耗時的操作,如果超過了規定的時間,會自動跳出onReceive方法的執行。 自定義好了BroadcastReceiver之後,為了讓我們自定義的BroadcastReceiver能夠接收到廣播,我們就需要注冊我們感興趣的廣播類型。注冊廣播分為下面兩種: (1)靜態注冊: 靜態注冊是在AndroidManifest.xml文件中進行配置,如下:
其中這個“com.scu.lly.action.MyBROADCAST”是我們自定義的一個廣播類型,以後只要有地方通過sendBroadcast(Intent)發送出該類型的廣播,我們的BroadcastReceiverTest就能夠接收到。當然,我們也可以訂閱一些Android系統內置的廣播,比如開機啟動廣播,如下:
我們訂閱了兩個感興趣的廣播,不論發出了哪一個廣播我們都能夠接收到,此時,只需要在onReceive()判斷一下,當前是哪種廣播類型即可,如下:
public class BroadcastReceiverTest extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //拿到我們注冊的廣播類型 String action = intent.getAction(); Log.d("TAG",action); if("com.scu.lly.action.MyBROADCAST".equals(action)){//處理我們接收到的自定義的廣播 //TODO }else if("android.intent.action.BOOT_COMPLETED".equals(action)){//處理開機廣播 //TODO } } }注意:靜態注冊這種方式是常駐型的,即使我們的應用程序退出了,如果系統中有注冊的廣播類型發出,我們自定義的BroadcastReceiverTest 也會被系統調用自動運行。比如,開機廣播,當我們重啟手機時,雖然此時我們的應用還未啟動,但是BroadcastReceiverTest 也能夠接收到該廣播。 (2)動態注冊 動態注冊是直接在代碼中,注冊我們感興趣的廣播類型,一般在Activity、Service、或傳入了Context的自定義View中注冊,如下:
BroadcastReceiverTest receiver = new BroadcastReceiverTest(); IntentFilter filter = new IntentFilter(); filter.addAction("com.scu.lly.action.MyBROADCAST"); registerReceiver(receiver, filter);注意:動態注冊的廣播接收者不是常駐型的,它會跟隨Activity或Service的生命周期,因此,在Activity或Service的onDestroy()方法中需要解除注冊。否則,系統會提示異常信息。如下:
@Override public void onDestroy() { super.onDestroy(); unregisterReceiver(receiver); }兩種注冊方式的區別: (1)注冊方式不一樣,靜態注冊是在AndroidMnifest.xml中配置,動態注冊是在代碼中設置; (2)生命周期不同,靜態注冊是常駐型的,即使應用程序退出,也能夠收到發出的廣播,而動態注冊會跟隨所依附的Activity或Service的生命周期,需要在onDestroy()中解除注冊。因此,靜態注冊適合注冊一些系統廣播,而代碼注冊適合注冊一些開發者自定義的一些廣播; (3)功能受限方面,有些系統廣播只能夠通過靜態注冊的方式注冊該廣播類型,通過動態注冊不能夠接收到廣播信息,比如,監聽電池電量的廣播、網絡狀態變化的廣播...。 發送廣播: 在通過上面兩種方式任意一種注冊完廣播之後,我們的BroadcastReceiverTest 就能夠接收到廣播了,此時,在需要的地方,我們就可以通過以下形式發出廣播:
Intent intent = new Intent("com.scu.lly.action.MyBROADCAST");//發送指定類型的廣播 intent.putExtra("name", "lly");//在發送廣播的同時,還可以攜帶一些參數過去 sendBroadcast(intent);廣播的種類: 一個廣播,可以被多個注冊了該廣播的廣播接收者接收,通過sendBoroadcast()方式發送出的廣播,多個廣播接收者之間都可以接收到該廣播,並且不會相互影響。如果要定義這些廣播接收者之間的接收順序,可以使用有序廣播。 (1)普通廣播 普通廣播對於所有訂閱該廣播的接收者來說是異步的,每個廣播接收者幾乎同時接收到廣播,相互之間也不會影響,因此,某個廣播接收者也就無法終止廣播的傳遞。 通過sendBroadcast()方式發出的廣播為普通廣播。 (2)有序廣播 有序廣播,通過sendOrderedBroadcast()方式發送,會根據廣播接收者的優先級來傳遞廣播,廣播首先傳遞到優先級最高的廣播接收者中,處理完之後,會傳遞到優先級低一級的廣播接收者中。 在傳遞過程中, <1>優先級較高的可以通過abortBroadcast()終止廣播的傳遞,廣播也就不會繼續往下傳播了; <2>傳遞過程中可以通過setResultExtras(Bundle)的方式往下一級傳遞處理結果信息。 我們先定義兩個廣播接收者,如下:
public class BroadcastReceiverTest extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //拿到我們注冊的廣播類型 String action = intent.getAction(); Log.d("TAG",action); if("com.scu.lly.action.MyBROADCAST".equals(action)){//處理我們接收到的自定義的廣播 //往下一級傳遞時,將這裡的處理結果傳過去 Bundle bundle = new Bundle(); bundle.putString("result", "resultinfo"); setResultExtras(bundle); // abortBroadcast(); } } } public class BroadcastReceiverTest2 extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //拿到我們注冊的廣播類型 String action = intent.getAction(); Log.d("TAG",action); if("com.scu.lly.action.MyBROADCAST".equals(action)){//處理我們接收到的自定義的廣播 //拿到上一級接收者的處理結果 Bundle bundle = getResultExtras(true); String res = bundle.getString("result"); Log.d("TAG", res); } } }上面我們通過setResultExtras和getResultExtras的方式,在廣播接收者之間傳遞了參數,根據具體需求可要可不要。 在廣播注冊的地方,我們再定義廣播接收者之間的優先級:
注冊好了之後,我們通過sendOrderedBroadcast方式發送有序廣播,如下:
Intent intent = new Intent("com.scu.lly.action.MyBROADCAST"); intent.putExtra("name", "lly");//在發送廣播的同時,還可以攜帶一些參數過去 sendOrderedBroadcast(intent, "com.scu.lly.permission.MyBROADCAST_PERMISSION");通過sendOrderedBroadcast方式發送有序廣播,第二個參數為permission權限參數, <1>可以為null,表示注冊該廣播時不需要在AndroidManifest.xml中聲明指定權限; <2>不為null,那麼,我們在注冊該廣播時,需要在AndroidManifest.xml中聲明該指定的權限;這種方式更加安全,特別是針對一些隱私廣播,比如我們在注冊監聽電話來電,讀取短信的廣播時,都需要在AndroidManifest.xml中聲明相應的權限。 上面我們的“com.scu.lly.permission.MyBROADCAST_PERMISSION”就為自定義的一條權限,因此我們需要在AndroidManifest.xml中先自定義,再聲明使用,如下: 如果我們想在BroadcastReceiverTest 終止廣播的發送,只需要把BroadcastReceiverTest 中的注釋去掉,使用abortBroadcast();來終止即可,這時,BroadcastReceiverTest2 就不能再收到該廣播了。
SharedPreferences settings = context.getSharedPreferences(APP_Prefs_Name, Context.MODE_PRIVATE);//第一步 SharedPreferences.Editor editor = settings.edit();//第二步 editor.putString("name", "lly");//第三步 editor.commit();//第四步SharedPreference的使用主要就是上面四步: 第一步,通過Context拿到SharedPreferences對象,其中getSharedPreferences(String fileName,int mode),第一個參數是SharedPreferences文件保存在手機中的文件名稱,SharedPreferences文件保存在手機中是以.xml格式保存的,系統首先會去判斷是否有這個文件,沒有就回去創建;第二個參數是這個文件的訪問權限,有下面幾種權限:
Context.MODE_PRIVATE: 指定該SharedPreferences數據只能被本應用程序讀、寫。
Context.MODE_WORLD_READABLE:指定該SharedPreferences數據能被其他應用程序讀,但不能寫。
Context.MODE_WORLD_WRITEABLE:指定該SharedPreferences數據能被其他應用程序讀,寫
第二步,通過SharedPreferences 獲取Editor 第三步,拿到Editor之後,就可以保存數據了,主要方法有putInt(),putString()... 第四步,在通過Editor寫入數據之後,一定要記得調用commit(),這樣提交了數據的更改才會生效。 其實,在我們的程序中可能會經常用到SharedPreferences來保存數據,如果在每個需要保存數據的類裡面使用上面四個步驟,就會感覺有一點點冗余,這個時候,我們就可以使用一個統一的SharedPreferences管理類來進行SharedPreferences數據的保存,推薦一個SharedPreferences管理類如下:/** * SharedPreferences參數管理類 */ public class PrefsUtils { // 本APP保存SharedPreferences參數的文件名 private static final String APP_Prefs_Name = "roadheadline"; /** * 保存字符串 * * @param context * @param key * @param value * @return 保存成功返回true */ public static boolean putString(Context context, String key, String value) { return context.getSharedPreferences(APP_Prefs_Name, Context.MODE_PRIVATE).edit().putString(key, value).commit(); } /** * 獲取字符串 * * @param context * @param key * @return 若不存在該key值對應的value,返回null */ public static String getString(Context context, String key) { return getString(context, key, null); } /** * 獲取字符串 * * @param context * @param key * @param defValue * @return 若不存在該key值對應的value,返回用戶傳入的defValue */ public static String getString(Context context, String key, String defValue) { return context.getSharedPreferences(APP_Prefs_Name, Context.MODE_PRIVATE).getString(key, defValue); } /** * 保存int數據 * * @param context * @param key * @param value * @return 保存成功返回true */ public static boolean putInt(Context context, String key, int value) { SharedPreferences settings = context.getSharedPreferences(APP_Prefs_Name, Context.MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor.putInt(key, value); return editor.commit(); } /** * 獲取int數據 * @param context * @param key * @return 不存在返回-1 */ public static int getInt(Context context, String key) { return getInt(context, key, -1); } /** * 獲取int數據 * * @param context * @param key * @param defaultValue * @return */ public static int getInt(Context context, String key, int defaultValue) { SharedPreferences settings = context.getSharedPreferences(APP_Prefs_Name, Context.MODE_PRIVATE); return settings.getInt(key, defaultValue); } /** * 保存long類型數據 * * @param context * @param key * @param value * @return */ public static boolean putLong(Context context, String key, long value) { SharedPreferences settings = context.getSharedPreferences(APP_Prefs_Name, Context.MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor.putLong(key, value); return editor.commit(); } /** * 獲取long類型數據 * * @param context * @param key The name of the preference to retrieve * @return 不存在返回-1 */ public static long getLong(Context context, String key) { return getLong(context, key, -1); } /** * 獲取long類型數據 * * @param context * @param key * @param defaultValue * @return */ public static long getLong(Context context, String key, long defaultValue) { SharedPreferences settings = context.getSharedPreferences(APP_Prefs_Name, Context.MODE_PRIVATE); return settings.getLong(key, defaultValue); } /** * 保存float類型數據 * * @param context * @param key * @param value * @return */ public static boolean putFloat(Context context, String key, float value) { SharedPreferences settings = context.getSharedPreferences(APP_Prefs_Name, Context.MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor.putFloat(key, value); return editor.commit(); } /** * 獲取float類型數據 * * @param context * @param key * @return 不存在返回-1 */ public static float getFloat(Context context, String key) { return getFloat(context, key, -1); } /** * 獲取float類型數據 * * @param context * @param key * @param defaultValue * @return */ public static float getFloat(Context context, String key, float defaultValue) { SharedPreferences settings = context.getSharedPreferences(APP_Prefs_Name, Context.MODE_PRIVATE); return settings.getFloat(key, defaultValue); } /** * 保存boolean類型數據 * * @param context * @param key * @param value * @return */ public static boolean putBoolean(Context context, String key, boolean value) { SharedPreferences settings = context.getSharedPreferences(APP_Prefs_Name, Context.MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor.putBoolean(key, value); return editor.commit(); } /** * 獲取boolean類型數據 * * @param context * @param key * @return 不存在返回false */ public static boolean getBoolean(Context context, String key) { return getBoolean(context, key, false); } /** * 獲取boolean類型數據 * * @param context * @param key * @param defaultValue * @return */ public static boolean getBoolean(Context context, String key, boolean defaultValue) { SharedPreferences settings = context.getSharedPreferences(APP_Prefs_Name, Context.MODE_PRIVATE); return settings.getBoolean(key, defaultValue); } }有了這個管理類之後,我們在需要保存數據的類裡面,直接調用PrefsUtils.putString(Contextcontext,Stringkey,Stringvalue);或其他相應的方法即可,獲取保存的數據也是調用裡面相應方法即可。 (2)使用文件存儲數據 <1>保存在內部存儲器中
文件被保存在內部存儲中時,默認情況下,文件是應用程序私有的,其他應用不能訪問。當用戶卸載應用程序時這些文件也跟著被刪除。
文件默認存儲位置:/data/data/包名/files/文件名。
Android系統默認提供了兩個方法openFileOutput()、openFileInput()將數據保存到內部存儲器中。使用方法如下: (1)往文件中寫入數據String text = "my name is lly"; try { FileOutputStream fos = openFileOutput("lly.txt", Context.MODE_PRIVATE); fos.write(text.getBytes()); fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); }其中openFileOutput(String fileName,int mode),第一個參數指定要打開的文件名稱(不需要寫路徑,因為文件默認存儲位置:/data/data/包名/files/文件名),如果沒有這個文件,則自動創建一個; 第二個參數指定文件訪問權限,有下面四種權限:
Context.MODE_PRIVATE = 0
為默認操作模式,代表該文件是私有數據,只能被應用本身訪問,在該模式下,寫入的內容會覆蓋原文件的內容。
Context.MODE_APPEND = 32768
該模式會檢查文件是否存在,存在就往文件追加內容,否則就創建新文件。
Context.MODE_WORLD_READABLE = 1
表示當前文件可以被其他應用讀取。
MODE_WORLD_WRITEABLE
表示當前文件可以被其他應用寫入。
(2)讀取文件內容try { FileInputStream fis = openFileInput("lly.txt"); byte[] buf = new byte[1024]; StringBuilder sb = new StringBuilder(); int len = 0; while((len = fis.read(buf)) != -1 ){ sb.append(new String(buf,0,len)); } fis.close(); System.out.println(sb.toString()); } catch (Exception e) { e.printStackTrace(); }當然,除了使用Android系統提供的這兩個方法外,我們可以指定保存到其他自定義路徑,這個時候就需要自己創建FileOutputStream或FileInputStream了,此時我們自定義的路徑就需要通過下面方法獲取: * getFileDir(),通過此方法可以獲取到你的APP內部存儲的文件,路徑為/data/data/pacgage_name/files,此方法獲得的路徑和openFileOutput的輸出流路徑一致; * getCacheDir(),通過此方法可以獲取到你的APP內部存儲的文件,路徑為/data/data/package_name/cache, 上面的方法獲得的都是內部存儲路徑,內部存儲在你的APP卸載的時候,會一塊被刪除。因此,我們可以在cache目錄裡面放置我們的圖片緩存,而且cache與files的差別在於,如果手機的內部存儲控件不夠了,會自行選擇cache目錄進行刪除,因此,不要把重要的文件放在cache文件裡面,可以放置在files裡面,因為這個文件只有在APP被卸載的時候才會被刪除。 <2>保存在外部存儲器 >數據保存外部存儲器時,首先需要在AndroidManifest.xml中加入訪問權限: >判斷外部存儲器的可用性 在使用外部存儲器存儲之前,一定要判斷外部存儲是否可用,判斷方法如下:
//獲取外存儲的狀態 String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { // 可讀可寫 mExternalStorageAvailable = mExternalStorageWriteable =true; } elseif ( Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { // 可讀 } else { // 可能有很多其他的狀態,但是我們只需要知道,不能讀也不能寫 }>獲取自定義路徑 1)外部私有存儲路徑 就像我們在前面獲取內部存儲的方法一樣,我們使用Context.getExternalCacheDir()和Context.getExternalFilesDir()(API >= 8)就可以獲取到外部存儲的私有文件,我們以下面的代碼為例。
File file3 = new File(getExternalCacheDir().getAbsolutePath(), "getExternalCacheDir.txt"); try { OutputStream outputStream1 = new FileOutputStream(file3); outputStream1.write("getExternalCacheDir".getBytes()); outputStream1.close(); } catch (Exception e) { e.printStackTrace(); } Log.d("TAG", "file3=" + file3); File file4 = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "getExternalFilesDir.txt"); try { OutputStream outputStream1 = new FileOutputStream(file4); outputStream1.write("getExternalFilesDir".getBytes()); outputStream1.close(); } catch (Exception e) { e.printStackTrace(); }運行結果如下:
如果我們想緩存圖片等比較耗空間的文件,推薦放在getExternalCacheDir()所在的文件下面,這個文件和getCacheDir()很像,都可以放緩存文件,在APP被卸載的時候,都會被系統刪除,而且緩存的內容對其他APP是相對私有的。
在使用getExternalFilesDir(int filetype)時,我們指定了這個文件的類型,不同的類型,在路徑下會放到不同的文件夾下(如上面的運行結果例子),這樣,Android系統的文件掃面器在掃描文件時就可以明確知道這是什麼類型文件了。 2)外部共享存儲路徑如果你的APP產生的文件不需要隱藏,即對用戶是可見的,那麼你可以把文件放在外部的公共存儲文件下面。我們可以通過下面的代碼獲取到公共存儲目錄:
Environment.getExternalStorageDirectory()
Environment.getExternalStoragePublicDirectory() 這兩個方法都是Environment的,而不是Context的。第一個方法獲取到的其實是外部存儲的根目錄,而第二個方法獲取到得則是外部存儲的公共目錄。其實在訪問權限上是沒有區別的,不同點是getExternalStoragePublicDirectory()在運行的時候,會需要你帶有一個特定的參數來指定這些public的文件類型,以便於與其他public文件進行分類,類型和上面的類似。 (3)使用SQLite存儲數據 SQLite是Android系統內置的一個小型數據庫,如果我們的APP需要保存一些表結構類的數據,可以考慮使用SQLite數據庫保存數據。 SQLite的使用方法如下: 第一步:實現一個繼承SQLiteOpenHelper的子類,裡面進行數據庫的創建工作。如下:public class DBOpenHelper extends SQLiteOpenHelper { private static final String DATABASENAME = "itcast.db"; //數據庫名稱 private static final int DATABASEVERSION = 2;//數據庫版本 public DBOpenHelper(Context context) { super(context, DATABASENAME, null, DATABASEVERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE person (personid integer primary key autoincrement, name varchar(20), amount integer)");//執行有更改的sql語句 } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS person"); onCreate(db); } }第二步:編寫業務邏輯處理類 按照MVC模型,我們在處理數據時最好編寫一個業務邏輯處理類,進行數據的增刪改查操作,在這裡面,當我們第一次調用getWritableDatabase()或getReadableDatabase()時,數據庫會被創建。如下例子:
public class PersonService { private DBOpenHelper dbOpenHelper; public PersonService(Context context) { this.dbOpenHelper = new DBOpenHelper(context); } public void payment(){ SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); db.beginTransaction();//事啟事務 try{ db.execSQL("update person set amount=amount-10 where personid=?", new Object[]{1}); db.execSQL("update person set amount=amount+10 where personid=?", new Object[]{2}); db.setTransactionSuccessful();//設置事務標志為成功,當結束事務時就會提交事務 }finally{ db.endTransaction(); } } public void save(Person person){ //如果要對數據進行更改,就調用此方法得到用於操作數據庫的實例,該方法以讀和寫方式打開數據庫 SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); db.execSQL("insert into person (name,amount) values(?,?)", new Object[]{person.getName(),person.getAmount()}); } public void update(Person person){ SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); db.execSQL("update person set name=? where personid=?", new Object[]{person.getName(),person.getId()}); } public void delete(Integer id){ SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); db.execSQL("delete from person where personid=?", new Object[]{id.toString()}); } public Person find(Integer id){ //如果只對數據進行讀取,建議使用此方法 SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); Cursor cursor = db.rawQuery("select * from person where personid=?", new String[]{id.toString()}); if(cursor.moveToFirst()){ int personid = cursor.getInt(cursor.getColumnIndex("personid")); String name = cursor.getString(cursor.getColumnIndex("name")); int amount = cursor.getInt(cursor.getColumnIndex("amount")); Person person = new Person(personid, name); person.setAmount(amount); return person; } return null; } public List可以看到,和我們平常使用的SQL非常類似。 第三步:保存數據 有了數據庫、業務邏輯處理類之後,就可以進行數據的我保存操作了,如下:getScrollData(Integer offset, Integer maxResult){ List persons = new ArrayList (); SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); Cursor cursor = db.rawQuery("select * from person limit ?,?", new String[]{offset.toString(), maxResult.toString()}); while(cursor.moveToNext()){ int personid = cursor.getInt(cursor.getColumnIndex("personid")); String name = cursor.getString(cursor.getColumnIndex("name")); int amount = cursor.getInt(cursor.getColumnIndex("amount")); Person person = new Person(personid, name); person.setAmount(amount); persons.add(person); } cursor.close(); return persons; } public Cursor getCursorScrollData(Integer offset, Integer maxResult){ SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); return db.rawQuery("select personid as _id, name, amount from person limit ?,?", new String[]{offset.toString(), maxResult.toString()}); } public long getCount() { SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); Cursor cursor = db.rawQuery("select count(*) from person", null); cursor.moveToFirst(); return cursor.getLong(0); } }
PersonService personService = new PersonService(this.getContext()); Person person = new Person(); person.setName("xiaoxiao"); person.setAmount(100); personService.save(person);(4)使用ContentProvider共享數據 嚴格來說,ContentProvider並不是保存數據的一種方法,而是不同APP之間進行數據共享的一種方式。比如,我們可以通過ContentProvider來獲取通訊錄APP中的聯系人的數據。當一個APP想讓該APP中的某些數據共享時,就可以通過ContentProvider來實現,所謂共享,就是另一個APP可以通過ContentProvider對另一個APP中的數據進行增刪改查操作。如下面這個實例: 第一步:當我們的APP准備共享一些數據時,可以編寫一個ContentProvider的子類,在子類中提供對需要共享數據的操作的方法。
public class PersonProvider extends ContentProvider { private DBOpenHelper dbOpenHelper; private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH); private static final int PERSONS = 1; private static final int PERSON = 2; //對外公布兩種對共享數據的操作方式:集合操作方式(批量方式)、單條記錄操作方式 static{ MATCHER.addURI("cn.itcast.providers.personprovider", "person", PERSONS);//以集合方式進行操作(批量操作) MATCHER.addURI("cn.itcast.providers.personprovider", "person/#", PERSON);//單條記錄操作 } @Override public boolean onCreate() { this.dbOpenHelper = new DBOpenHelper(this.getContext()); return false; } @Override public String getType(Uri uri) {//返回當前操作的數據的mimeType switch (MATCHER.match(uri)) { case PERSONS: return "vnd.android.cursor.dir/person";//對集合的操作 case PERSON: return "vnd.android.cursor.item/person";//對單條記錄的操作 default: throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString()); } } //刪除person表中的所有記錄 /person //刪除person表中指定id的記錄 /person/10 @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); int count = 0; switch (MATCHER.match(uri)) { case PERSONS: count = db.delete("person", selection, selectionArgs); return count; case PERSON: long id = ContentUris.parseId(uri); String where = "personid="+ id; if(selection!=null && !"".equals(selection)){ where = selection + " and " + where; } count = db.delete("person", where, selectionArgs); return count; default: throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString()); } } @Override public Uri insert(Uri uri, ContentValues values) {// /person SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); switch (MATCHER.match(uri)) { case PERSONS: long rowid = db.insert("person", "name", values); Uri insertUri = ContentUris.withAppendedId(uri, rowid);//得到代表新增記錄的Uri this.getContext().getContentResolver().notifyChange(uri, null); return insertUri; default: throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString()); } } //查詢person表中的所有記錄 /person //查詢person表中指定id的記錄 /person/10 @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); switch (MATCHER.match(uri)) { case PERSONS: return db.query("person", projection, selection, selectionArgs, null, null, sortOrder); case PERSON: long id = ContentUris.parseId(uri); String where = "personid="+ id; if(selection!=null && !"".equals(selection)){ where = selection + " and " + where; } return db.query("person", projection, where, selectionArgs, null, null, sortOrder); default: throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString()); } } //更新person表中的所有記錄 /person //更新person表中指定id的記錄 /person/10 @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); int count = 0; switch (MATCHER.match(uri)) { case PERSONS: count = db.update("person", values, selection, selectionArgs); return count; case PERSON: long id = ContentUris.parseId(uri); String where = "personid="+ id; if(selection!=null && !"".equals(selection)){ where = selection + " and " + where; } count = db.update("person", values, where, selectionArgs); return count; default: throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString()); } } }可以看到,一個ContentProvider主要有三部分: (1)onCreate()數據初始化 在這裡面進行數據的初始化,比如創建出數據庫... (2)對外提供操作共享數據的路徑機制 一個APP想要對另外一個APP進行共享數據的操作功能,首先要能夠拿到訪問操作方法的URI,類似於我們訪問WEN服務器的接口地址一樣。Android系統內部對共享數據的操作模式有集合形式的操作(批量操作)、單條記錄的操作模式,分別用“vnd.android.cursor.dir/自定義”和“vnd.android.cursor.item/自定義”來區分。在對共享數據進行操作之前,ContentProvider首先會判斷是哪種操作模式。因此,我們自定義的eContentProvider裡面需要進行如下工作: > 首先,在我們實現的ContentProvider子類中,對外提供這個共享數據能夠被操作的方式,如: //對外公布兩種對共享數據的操作方式:集合操作方式(批量方式)、單條記錄操作方式 static{ MATCHER.addURI("cn.itcast.providers.personprovider","person",PERSONS);//以集合方式進行操作(批量操作) MATCHER.addURI("cn.itcast.providers.personprovider","person/#",PERSON);//單條記錄操作 } > 在使用ContentProvider進行數據操作前,默認會進行getType(Uri uri)方法,在這裡面,拿到外部APP傳進來的Uri進行匹配,判斷出操作類別。 (3)調用相應的操作方法 在執行完第二步後,根據第三方的請求調用的方法,調用ContentProvider中相應的方法。 第二步:在AndroidManifest.xml中進行注冊 ContentProvider屬於Android四大控件之一,需要在AndroidManifest.xml中進行注冊,如下: 其中,android:authorities="cn.itcast.providers.personprovider"中的值“cn.itcast.providers.personprovider”需要與ContentProvider中的MATCHER.addURI("cn.itcast.providers.personprovider","person",PERSONS)第一個參數相同。 第三步:外部APP訪問另一個APP通過ContentProvider共享的數據 當一個APP通過ContentProvider提供好了共享數據的操作方法之後,另一個APP就可以進行誇APP訪問了,如下: ContentResolvercontentResolver=getContentResolver(); UriinsertUri=Uri.parse("content://cn.itcast.providers.personprovider/person"); ContentValuesvalues=newContentValues(); values.put("name","itcastliming"); values.put("amount",100); Uriuri=contentResolver.insert(insertUri,values); Toast.makeText(MainActivity.this,"添加完成",1).show(); (5)使用網絡存儲數據 當我們的APP需要將數據保存到服務器時,就需要通過網絡請求的方式,訪問服務器,並保存傳遞過來的數據,這是一種非常常用的數據保存方式。 關於網絡請求這一塊,我們可以自己去封裝一些簡單的請求框架,也可以使用現成的網絡請求框架。 現在比較好用的網絡請求框架有:Volley、OkHttp、Afinal、XUtils、android-async-http等 具體框架的使用可以搜索相關知識。
用安卓手機也有一段時間了,買來手機後,最常去的地方就是去電子市場安裝軟件,和買來新電腦一樣,我比較喜歡折騰的是軟件。在電子市場安裝了許多軟件以後,我統計了一
一個仿微信朋友圈和QQ空間的九宮格圖片展示自定義控件。GitHub:https://github.com/HMY314/NineGridLayout  
本節引言: 本節我們來把剩下的四種Drawable也學完,他們分別是: LayerDrawable,TransitionDrawable,Leve
有多少人,在糾結SDK老是更新出問題,打開Android開發者網站等半天,不能上google,facebook,youtube等國外網站而煩惱呢, 如果不巧你正好看到了這