編輯:關於Android編程
1.ContentProvider簡介
在Android中有些數據(如通訊錄、音頻、視頻文件等)是要供很多應用程序使用的,為了更好地對外提供數據,Android系統給我們提供了Content Provider使用,通過它可以訪問上面所說的數據,例如很多音樂播放器中的掃描功能其實就用到了Content Provider功能(當然,也有的播放器是自己去實現更底層的功能)。這樣的好處是統一管理,比如增加了某個音頻文件,底層就會將這種變化通知Content Provider,從而當應用程序訪問時就可以獲得當前最新的數據。
當然,Android也允許我們定義自己的Content Provider,只要繼承它的基類,並且實現下面的方法即可。
public boolean onCreate()
在創建ContentProvider時調用
public Cursor query(Uri, String[],
String, String[], String):用於查詢指定Uri的ContentProvider,返回一個Cursor
public Uri insert(Uri, ContentValues):根據指定的Uri添加數據到ContentProvider中
public int update(Uri, ContentValues,
String, String[]):用於更新指定Uri的ContentProvider中的數據
public int delete(Uri, String,
String[]):根據Uri刪除指定的數據
public String getType(Uri):用於返回指定的Uri中的數據的MIME類型
*如果操作的數據屬於集合類型,那麼MIME類型字符串應該以vnd.android.cursor.dir/開頭。
例如:要得到所有p1記錄的Uri為content://contacts/p1,那麼返回的MIME類型字符串為"vnd.android.cursor.dir/p1"。
*如果要操作的數據屬於非集合類型數據,那麼MIME類型字符串應該以vnd.android.cursor.item/開頭。
例如:要得到id為100的student記錄的Uri為content://contacts/student/100,那麼返回的MIME類型字符串應為"vnd.android.cursor.item/student"。
2.Uri簡介
一個標准的Uri為content://authority/path可分為以下三部分:
(1)content://:這個部分是ContentProvider規定的,就像http://代表Http這個協議一樣,使用ContentProvider的協議是content://
(2)authorities:它在所在的Android系統必須是唯一的,因為系統就是通過它來決定操作或訪問哪個ContentProvider的,這與互聯網上的網址必須唯一是一樣的道理。
(3)path:資源路徑。
顯然,從上面的分析可以看出ContentProvider雖然也可實現跨進程通信,但是它適用的場景主要是與數據庫相關,有時也可能是文本文件或XML等存儲方式。
3.ContentResolver
如果只是定義一個ContentProvider的話,沒有任何意義,因為ContentProvider只是內容提供者,它要被別的應用(進程)讀取才有價值。與實現ContentProvder的方法相對應,使用ContentResolver相關的方法如下所示:
getContentResolver():Context類提供的,用於獲取ContentResolver對象;
insert(Uri uri,ContentValues values):向Uri對應的ContentProvider中插入values對應的數據;
update(Uri uri,ContentValues values,String where,String[]selectionArgs):更新Uri對應的ContentProvider中where處的數據,其中selectionArgs是篩選參數;
query(Uri uri,String[]projection,String selection,String[]selectionArgs,String sortOrder):查詢Uri對應的ContentProvider中where處的數據,其中selectionArgs是篩選參數,sortOrder是排序方式;
delete(Uri uri,String where,String[]selectionArgs):刪除Uri對應的ContentProvider中where處的數據,其中selectionArgs是篩選參數;
4.UriMatcher
為了確定一個ContentProvider實際能處理的Uri,以及確定每個方法中Uri參數所操作的數據,Android系統提供了UriMatcher工具類。它主要有如下兩個方法:
(1)void addURI(String authority,String path,String code):該方法用於向UriMatcher對象注冊Uri。其中authority和path組合成一個Uri,而code則代表該Uri對應的標識碼;
(2)int match(Uri uri):根據前面注冊的Uri來判斷指定Uri對應的標識碼。如果找不到匹配的標識碼,該方法將會返回-1。
下面通過兩個實例來講解ContentProvider的用法,第一個實例是自己定義了一個ContentProvider並且在另一個應用中讀取它;第二個實例是讀取當前手機中的聯系人。
首先是第一個例子,項目結構如下圖所示:
下面是各個類的代碼,首先是常量的定義:
package com.android.student.utils; import android.net.Uri; /** * 這裡定義了與ContentProvider相關的字符串以及Student對應的數據表中的字段 * @author Bettar * */ public class StudentWords { //注意Manifest文件中的authorities屬性要跟這裡保持一致。 public static final String AUTHORITY="com.android.student.provider"; public static final Uri STUDENT_WITH_ID_URI=Uri.parse("content://"+AUTHORITY+"/student"); public static final Uri STUDENT_URI=Uri.parse("content://"+AUTHORITY+"/student"); public static final String TABLE_NAME="student"; public static final String ID="id"; public static final String NAME="name"; public static final String SCORE="score"; public static final String ADDR="address"; }然後是數據庫幫助類:
import com.android.student.utils.StudentWords; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.widget.Toast; public class StudentDbHelper extends SQLiteOpenHelper{ private Context context; public StudentDbHelper(Context context,String name,int version) { super(context,name,null,version); this.context=context; } @Override public void onCreate(SQLiteDatabase db) { String createSQL="create table "+StudentWords.TABLE_NAME+"("+StudentWords.ID +" integer primary key autoincrement," +StudentWords.NAME+" varchar," +StudentWords.SCORE+" integer," +StudentWords.ADDR+" varchar)"; db.execSQL(createSQL); } @Override public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion) { //升級版本時,可能要執行表結構的修改之類,此處暫時不考慮升級問題,因而只是用Toast提示 Toast.makeText(context, "newVersion:"+newVersion+" will replace oldVersion:"+oldVersion, Toast.LENGTH_LONG).show(); } }最後是ContentProvider類的定義:
package com.android.student.provider; import com.android.student.database.StudentDbHelper; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.provider.UserDictionary.Words; import com.android.student.utils.StudentWords; public class StudentProvider extends ContentProvider{ private static final String TAG="StudentProvider"; private static UriMatcher matcher=new UriMatcher(UriMatcher.NO_MATCH); private static final int STUDENT_WITH_ID=1; private static final int STUDENT=2; private StudentDbHelper dbHelper; static { matcher.addURI(StudentWords.AUTHORITY,"student/#",STUDENT_WITH_ID); //matcher.addURI(StudentWords.AUTHORITY, "student", SINGLE_STUDENT); //注意其中的#為通配符 matcher.addURI(StudentWords.AUTHORITY, "student", STUDENT); } @Override public boolean onCreate() { dbHelper=new StudentDbHelper(this.getContext(),"student.db3",1); return true; } @Override public String getType(Uri uri) { switch(matcher.match(uri)) { case STUDENT_WITH_ID: return "vnd.android.cursor.item/com.android.student"; case STUDENT: return "vnd.android.cursor.dir/com.android.student"; default: throw new IllegalArgumentException("Unknown Uri:"+uri); } } /** * 由單一的selection這一個篩選條件組合成包含id的復雜篩選條件 * @param uri * @param selection * @return */ private String getComplexSelection(Uri uri,String selection) { long id=ContentUris.parseId(uri); String complexSelection=StudentWords.ID+"="+id; if(selection!=null&&!"".equals(selection)) { complexSelection+=" and "+selection; } return complexSelection; } @Override public int delete(Uri uri,String selection,String[]selectionArgs) { SQLiteDatabase db=dbHelper.getReadableDatabase(); int num=0; switch(matcher.match(uri)) { case STUDENT_WITH_ID: String complexSelection=getComplexSelection(uri,selection); num=db.delete(StudentWords.TABLE_NAME, complexSelection, selectionArgs); break; case STUDENT: num=db.delete(StudentWords.TABLE_NAME,selection,selectionArgs); break; default: throw new IllegalArgumentException("Unknown Uri:"+uri); } //通知數據已經改變 getContext().getContentResolver().notifyChange(uri, null); return num; } @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db=dbHelper.getReadableDatabase(); switch(matcher.match(uri)) { case STUDENT_WITH_ID: case STUDENT: long rowId=db.insert(StudentWords.TABLE_NAME, StudentWords.ID,values); if(rowId>0) { Uri studentUri=ContentUris.withAppendedId(uri, rowId); //如果設置了觀察者的話,要通知所有觀察者 getContext().getContentResolver().notifyChange(studentUri, null); return studentUri; } break; default: throw new IllegalArgumentException("Unknow Uri:"+uri); } return null; } /** * 注意其中的projection其實是columns,即列名數組 */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db=dbHelper.getReadableDatabase(); switch(matcher.match(uri)) { //這其實是包含id信息的情況 case STUDENT_WITH_ID: String complexSelection=getComplexSelection(uri,selection); return db.query(StudentWords.TABLE_NAME,projection,complexSelection,selectionArgs,null,null,sortOrder); //這是不帶數字的情況,但是也未必就是好多個,一個也可以。 case STUDENT: return db.query(StudentWords.TABLE_NAME ,projection,selection,selectionArgs,null,null,sortOrder); default: throw new IllegalArgumentException("Unknow Uri"+uri); } } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db=dbHelper.getWritableDatabase(); int num=0; switch(matcher.match(uri)) { case STUDENT_WITH_ID: String complexSelection=getComplexSelection(uri,selection); num=db.update(StudentWords.TABLE_NAME, values, complexSelection, selectionArgs); break; case STUDENT: num=db.update(StudentWords.TABLE_NAME, values, selection,selectionArgs); break; default: throw new IllegalArgumentException("Unknow Uri:"+uri); } getContext().getContentResolver().notifyChange(uri,null); return num; } }當然,要記得在Manifest文件中加入ContentProvider的聲明:
下面是對ContentResolver的例子,首先項目中的文件結構如下:
然後是layout文件 :
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHByZSBjbGFzcz0="brush:java;">
package com.android.student.studentcontentresolver; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.android.student.utils.StudentWords; import android.net.Uri; import android.os.Bundle; import android.app.Activity; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; import android.view.Menu; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import android.view.View; public class MainActivity extends Activity implements View.OnClickListener{ ContentResolver contentResolver; private EditText nameET,scoreET,addressET; private Button insertButton; private EditText inputNameET; private Button searchButton; private EditText inputIdForUpdateET,inputIdForDeleteET; private Button updateButton,deleteButton; private void initView() { nameET=(EditText)findViewById(R.id.nameET); scoreET=(EditText)findViewById(R.id.scoreET); addressET=(EditText)findViewById(R.id.addrET); insertButton=(Button)findViewById(R.id.insertButton); inputNameET=(EditText)findViewById(R.id.inputNameET); searchButton=(Button)findViewById(R.id.searchButton); inputIdForUpdateET=(EditText)findViewById(R.id.inputIdET); inputIdForDeleteET=(EditText)findViewById(R.id.inputIdForDeleteET); updateButton=(Button)findViewById(R.id.updateButton); deleteButton=(Button)findViewById(R.id.deleteButton); insertButton.setOnClickListener(this); searchButton.setOnClickListener(this); updateButton.setOnClickListener(this); deleteButton.setOnClickListener(this); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); contentResolver=getContentResolver(); initView(); } @Override public void onClick(View view) { switch(view.getId()) { case R.id.insertButton: insert(); break; case R.id.searchButton: query(); break; case R.id.updateButton: update(); break; case R.id.deleteButton: delete(); break; default: break; } } private void insert() { String name=nameET.getText().toString(); String score=scoreET.getText().toString(); String addr=addressET.getText().toString(); ContentValues values=new ContentValues(); values.put(StudentWords.NAME, name); values.put(StudentWords.SCORE, new Integer(score)); values.put(StudentWords.ADDR, addr); //contentResolver.insert(StudentWords.SINGLE_STUDENT_URI, values); //一個是多個的特例,所以此處用MANY_STUDENTS_URI即可。 contentResolver.insert(StudentWords.STUDENT_URI, values); Toast.makeText(getBaseContext(), "添加學生信息成功", Toast.LENGTH_SHORT).show(); } private void query() { String name=inputNameET.getText().toString(); //Cursor cursor=contentResolver.query(uri, projection, selection, selectionArgs, sortOrder) Cursor cursor=contentResolver.query(StudentWords.STUDENT_URI, null, "name like ? or address like ?", new String[]{"%"+name+"%","%"+name+"%"}, null); Toast.makeText(getBaseContext(), getResult(cursor), Toast.LENGTH_LONG).show(); } private void update() { //Uri updateUri=StudentWords.SINGLE_STUDENT_URI //更新id值為id的記錄 Integer id=new Integer(inputIdForUpdateET.getText().toString()); Uri updateUri=ContentUris.withAppendedId(StudentWords.STUDENT_WITH_ID_URI,id); ContentValues values=new ContentValues(); values.put(StudentWords.NAME,"VictorWang"); contentResolver.update(updateUri, values, null, null); } private void delete() { //刪除id值為id的記錄 Integer id=new Integer(inputIdForDeleteET.getText().toString()); Uri deleteUri=ContentUris.withAppendedId(StudentWords.STUDENT_WITH_ID_URI, id); contentResolver.delete(deleteUri, null, null); } private List運行結果如下:convertCursor2List(Cursor cursor) { List result=new ArrayList (); while(cursor.moveToNext()) { result.add(cursor.getString(1)+" "); result.add(cursor.getString(2)+" "); result.add(cursor.getString(3)+" "); } return result; } private String getResult(Cursor cursor) { StringBuilder sb=new StringBuilder(); while(cursor.moveToNext()) { sb.append(cursor.getString(1)+" "); sb.append(cursor.getString(2)+" "); sb.append(cursor.getString(3)+"\n"); } return sb.toString(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
今天先寫到這裡,聯系人和ContentObserver的例子後面再添加。
ctrl+shift+N 查找文件,以懸浮窗口的形式搜索 contrl+N 查找類,與ctrl+shift+N相似,但是只能查找類 ctrl + E 最近打開的文件,可
過度繪制(Overdraw)是指在一幀的時間內像素被繪制了多次;理論上一個像素每次只繪制一次是最優的,但是由於層疊的布局導致一些像素會被多次繪制,而每次繪制都會對應到CP
仿微信相冊選擇圖片,查看大圖,寫的不太好,希望評論指出不足,諒解,先介紹一下我的基本思路第一步獲取手機上的所有圖片路徑: Uri
來這實習已經10多天了,今天整理整理學習時的Android筆記。正所謂好記性不如爛筆頭,今天來說說service組件。 service可以在和多