1. 程式人生 > >Android ContentResolver 內容解析者(解析器)----重新認識Android(11)

Android ContentResolver 內容解析者(解析器)----重新認識Android(11)

注意需要申請許可權,否則執行會出現異常:WRITE_CALL_LOG,READ_CALL_LOG
/**  * ContentProvider內容提供者 1.主要用於不同的應用程式之間,共享資料的。 A:ContentProvider:向外提供資料的  * 用於通過Uri向外暴露資料。只要將應用安裝到手機上。無論是否執行,都可以獲取資料。 B:ContentResolver:獲取並解析資料  * 用於解析通過ContentProvider暴露 出來的資料。 A應用暴露出的是Uri,B應用使用該Uri就可以訪問A應用暴露出來的資料了。  * =====================================================
 * 本例用於實現通過ContentResovler來獲取手機中通話記錄  * 通話記錄儲存在內部儲存的系統應用目錄中:data/data/com.android.providers.contacts/contacts2.db  * 對外暴露的Uri:"content://call_log/calls"  * step1:通過getContentResolver()獲取ContentResovler物件  * step2:獲取通話記錄的Uri:"content://call_log/calls"  * step3:執行查詢:ContentResovler物件.query(uri,查詢的欄位, 條件,條件的引數,排序依據);
 * step4:新增許可權:READ_CALL_LOG 讀取通話記錄,WRITE_CALL_LOG 寫通話記錄 通話記錄表的核心欄位"_id",  * "number"電話號碼, "date"時間(毫秒值), "type": 1:呼入 2:撥出 3:未接  */
public class Main3Activity extends AppCompatActivity {

    // step2:提供要解析資料對應的Uri,就是電話記錄的uri
    private Uri uri_callLog = CallLog.Calls.CONTENT_URI;// 系統提供的常量,表示通話記錄對外暴露的Uri
    // 上面常量的值就是 Uri.parse("content://call_log/calls")得到的結果.
    private ContentResolver contentResolver;
    private ListView lv_listview;
    private MyCursorAdapter adapter;// 自定義的介面卡類物件

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        lv_listview = (ListView) findViewById(R.id.lv_listview);
        // step1:獲取ContentResolver
        contentResolver = getContentResolver();
        queryCallLog();// 呼叫自定義的方法,用於查詢並顯示通話記錄
        // 註冊 上下文選單:可以刪除某個通話記錄
        registerForContextMenu(lv_listview);
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        getMenuInflater().inflate(R.menu.call_menu, menu);// 上下文選單,只有一個"刪除"選項
    }

    // 上下文選單點選時間處理
    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
        int position = menuInfo.position;// 獲得彈出上下文選單時所選中的條目的位置
        Cursor cursor = adapter.getCursor();// 呼叫CursorAdapter的獲取cursor物件的方法
        cursor.moveToPosition(position);// 把cursor作為資料來源,移動到指定位置
        int id = cursor.getInt(cursor.getColumnIndex("_id"));// 通話記錄表calls中的欄位
        switch (item.getItemId()) {
            case R.id.action_delete:
                // 刪除一條記錄
                int count = deleteCallLog(id);// 呼叫自定義的刪除通話記錄的方法
                if (count > 0) {
                    Toast.makeText(Main3Activity.this, "刪除成功", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(Main3Activity.this, "刪除失敗", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
        queryCallLog();// 呼叫自定義的重新查詢的方法
        return super.onContextItemSelected(item);
    }

    /**
     * 刪除一條指定的通話記錄
     *
     * @param id
     * @return
     */
    public int deleteCallLog(int id) {
        int count = contentResolver.delete(uri_callLog, "_id=?", new String[]{id + ""});// 也可以第二個引數傳"_id="+id,第三引數傳null
        return count;
    }

    /**
     * 通過contentResolver,查詢uri所指向的通話記錄資料
     * 第一個引數:要操作的應用暴露出的uri。指向通話記錄的資料
     * 第二個引數:要查詢的欄位
     * 第三個引數:查詢的條件
     * 第四個引數:條件的引數值
     * 第五個引數:排序
     */
    // 查詢資料
    public void queryCallLog() {
        // step3:通過contentResolver獲取資料
        //Uri uri,String[] projection列名陣列,String selection查詢條件,String[] selectionArgs替換佔位符的陣列,String sortOrder
                Cursor cursor = contentResolver.query(uri_callLog, new String[]{"_id", "number", "date", "type"}, null, null, "date desc");
        // SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
        // R.layout.item_listview, cursor, new String[] { "_id", "number",
        // "date", "type" }, new int[] { R.id.tv_id,
        // R.id.tv_number, R.id.tv_date, R.id.tv_type },
        // CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);//這樣填進去日期就只能顯示成毫秒數了,不美觀

        // 因此可以使用繼承CursorAdapter的自定義介面卡來適配Cursor資料
        // 父類CursorAdapter沒有無參的構造方法,必須如此傳參:
        adapter = new MyCursorAdapter(this, cursor, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); // 最後一個引數表示,如果資料來源發生變化則在後面學習的Loader中可以動態更新.
        lv_listview.setAdapter(adapter);
    }

    // 自定義的繼承抽象類CursorAdapter的介面卡
    class MyCursorAdapter extends CursorAdapter {
        // 繼承抽象類,重寫兩個抽象方法
        public MyCursorAdapter(Context context, Cursor c, int flags) {
            super(context, c, flags);// 父類沒有無參的構造方法,必須如此傳參
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            // 指定佈局檔案,生成一個條目的View物件,注意,在內部類中,上下文是MainActivity.this
            return LayoutInflater.from(Main3Activity.this).inflate(R.layout.item_listview, null);
        }

        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            // 填充資料到每個條目的內部元件上,類似於繼承BaseAdapter中重寫getView()方法
            TextView tv_id = (TextView) view.findViewById(R.id.tv_id);
            TextView tv_number = (TextView) view.findViewById(R.id.tv_number);
            TextView tv_date = (TextView) view.findViewById(R.id.tv_date);
            TextView tv_type = (TextView) view.findViewById(R.id.tv_type);
            // 從cursor獲取資料,顯示到textview上
            tv_id.setText("" + cursor.getInt(cursor.getColumnIndex("_id")));
            tv_number.setText(cursor.getString(cursor.getColumnIndex("number")));
            long dateNum = cursor.getLong(cursor.getColumnIndex("date"));// 獲取以毫秒錶示的date資料
            Date date = new Date(dateNum);// 利用毫秒數構建Date物件
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            tv_date.setText(sdf.format(date));
            int typeNum = cursor.getInt(cursor.getColumnIndex("type"));
            if (typeNum == 1) {
                tv_type.setText("呼入");
            } else if (typeNum == 2) {
                tv_type.setText("撥出");
            } else {
                tv_type.setText("未接");
            }
        }
    }
}

/**  * 簡訊息的程式的資料庫檔案:/data/data/com.android.providers.telephony/mmssms.db  * Uri:content://sms  * step1:獲取contentResolver物件  * step2:獲取簡訊息的Uri  * step3:查詢,插入  * step4:新增許可權:READ_SMS,WRITE_SMS  * @author Administrator  * 核心欄位:_id,address電話號碼,body資訊文字,type型別(1.接收;2.傳送),date時間(毫秒)  */ 四、使用ContentResolver 查詢聯絡人 (一)、 [總結]使用ContentResolver 操作資料的步驟: 1、呼叫Context的getContentResolver()方法獲得ContentResolver 物件; 2、呼叫ContentResolver 的query()方法查詢資料。 · Cursor query(Uri uri, String[] projection, String where, String[] whereArgs, String sortOrder) 引數解釋: String[]   projection:表示select語句中需要查詢的所有的欄位組成的字串陣列。 String   where:表示帶有佔位符的where子句組成的字串; String[]   whereArgs:表示替換where引數中佔位符的資料組成的字串陣列; String   sortOrder:表示select語句中的order by子句組成的字串; (二)、 聯絡人中管理ContentProvider的幾個Uri:  1、聯絡人的Uri==>     content://com.android.contacts/raw_contacts   2、電話/郵件地址等資料的Uri==>  content://com.android.contacts/data 資料庫位置:/data/data/com.android.providers.contacts/databases/contacts2.db 用視覺化工具開啟(例如SQLite Expert) 核心表: 1.raw_contacts原始聯絡人表 "_id":聯絡人的id "display_name":聯絡人的姓名  2.data資料表 "raw_contact_id":作為外來鍵參照raw_contacts表的_id欄位 "data1":具體資料,例如手機號,email,姓名等 "mimetype_id":資料的大型別,例如 1:email; 5:電話; 7:姓名; 在mimetypes表中對應於_id欄位 3.mimetypes表 "_id":型別id "mimetype":具體型別,例如_id為7的mimetype是 vnd.android.cursor.item/name 1 電子郵件 2 即時通訊 3 暱稱 4 組織,單位 5 電話號碼 6 郵編 7 名字 8 地址 9 身份證識別號 10 頭像 11 組群 /**  * 操作手機的聯絡人: 應用程式資料所在的位置:/data/data/com.android.providers/contacts/contacts2.db  * step1:獲取ContentResolver物件  * step2:提供Uri 1、聯絡人的Uri==>  * content://com.android.contacts/raw_contacts  * 2、電話/郵件地址等資料的Uri==> content://com.android.contacts/data  * step3:執行查詢  * step4:新增許可權: READ_CONTACTS  *  * @author Administrator  */
public class MainActivity extends Activity implements OnClickListener {
private Uri uri_raw_contact = Uri.parse("content://com.android.contacts/raw_contacts");// raw_contacts表
private Uri uri_data = Uri.parse("content://com.android.contacts/data");
private ContentResolver contentResolver;
private ListView lv_listview;
private Button btn_queryData; 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contentResolver = getContentResolver();
initView();// 自定義的獲取元件引用和註冊監聽器的方法
queryContacts();// 自定義的查詢聯絡人的方法
}
 
public void initView() {
lv_listview = (ListView) findViewById(R.id.lv_listview);
btn_queryData = (Button) findViewById(R.id.btn_queryData);
btn_queryData.setOnClickListener(this);
}
 
/**
 * 獲取聯絡人的資訊,並且顯示到listview上。 用SimpleAdapter進行適配
 */
public void queryContacts() {
List<Map<String, String>> list = getDataContacts();// 自定義的方法,獲取聯絡人的資訊List
// 僅用於展示資訊,可以直接使用SimpleAdapter
SimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.item_listview,
new String[] { "_id", "display_name", "phone", "email" },
new int[] { R.id.tv_id, R.id.tv_display_name, R.id.tv_phone, R.id.tv_email });
lv_listview.setAdapter(adapter);
}
 
// 自定義的用於查詢聯絡人的方法
public List<Map<String, String>> getDataContacts() {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();//初始化結果集
// A:查詢raw_contact表,為了得到_id,display_name.
Cursor cursor = contentResolver.query(uri_raw_contact, new String[] { "_id", "display_name" }, null, null,null);
while (cursor.moveToNext()) {
Map<String, String> map = new HashMap<String, String>();
String _id = cursor.getString(cursor.getColumnIndex("_id"));
String display_name = cursor.getString(cursor.getColumnIndex("display_name"));
map.put("_id", _id);
map.put("display_name", display_name);
// B:根據查詢到_id,查詢data表,獲取到data1, mimetype欄位:
// select data1,mimetype from data where raw_contact_id = _id:
Cursor cursor2 = contentResolver.query(uri_data, new String[] { "data1", "mimetype" }, "raw_contact_id=?",new String[] { _id }, null);
// 儲存的是_id對應的聯絡人的資訊:
String email = "";
String phone = "";
String address = "";
 
while (cursor2.moveToNext()) {
String data = cursor2.getString(cursor2.getColumnIndex("data1"));
String mimetype = cursor2.getString(cursor2.getColumnIndex("mimetype"));// 雖然data表沒有這個欄位,只有mimetype_id欄位,但此處必須這樣獲取,且獲取回來的是一個類似於"vnd.android.cursor.item/email_v2"的字串
if ("vnd.android.cursor.item/email_v2".equals(mimetype)) {
email = email + "|" + data;// 如果mimetype的值為email,表示此處的data中的資料是電子郵箱
} else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {// 電話(有可能有手機的,座機的,家庭的,單位的...)
phone = phone + "|" + data;
} else if ("vnd.android.cursor.item/postal-address_v2".equals(mimetype)) {// 地址
address = address + "|" + data;
}
}
map.put("phone", phone);
map.put("email", email);
map.put("address", address);
 
list.add(map);//把一個聯絡人的所有資訊存入map後,再將map存入list
}
return list;
}
// 點選按鈕,實現查詢功能
@Override
public void onClick(View v) {
queryContacts();//呼叫自定義的方法
}
}
一、自定義ContentProvider:   (一)、操作步驟: 1、自己編寫一個類,必須繼承自ContentProvider類; 2、實現ContentProvider類中所有的抽象方法;     需要實現:onCreate() 、getType() 、query() 、insert() 、update()、delete() 等方法。 【備註:】 ContentProvider暴露出來的資料和方法是給其他應用程式來呼叫。 其他應用程式通過ContentResolver物件呼叫query() 、insert() 、update()、delete() 等。 3、定義ContentProvider的Uri。這個Uri是ContentResolver物件執行CRUD操作時重要的引數; 4、使用UriMatcher物件對映Uri返回程式碼;【超綱】 5、在AndroidMainfest.xml檔案中使用<provider>標籤註冊ContentProvider。 (二)、ContentProvider類中的六個抽象方法: 1、boolean onCreate() 初始化provider 注意沒有ContentResolver試圖訪問你的Provider之前,它不會創建出來. 2、Uri insert(Uri uri, ContentValues values) 插入新資料到ContentProvider 3、int delete(Uri uri, String selection, String[] selectionArgs)從ContentProvider中刪除資料 4、int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)更新ContentProvider已經存在的資料 5、Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 返回資料給呼叫者 6、String getType(Uri uri) 返回ContentProvider資料的MIME型別 (三)、在清單檔案中宣告註冊ContentProvider: <provider android:name=".WordsContentProvider"   android:authorities="com.qf.wordscontentprovider"   android:exported="true"    /> //android:name屬性的值:ContentProvider類的子類的完整路徑; //android:authorities屬性的值:對應於content:URI中的authority部分。 //android:exported屬性是否允許其他應用呼叫。如果是false,則該ContentProvider不允許其他應用呼叫。 【備註:】         ContentProvider是單例模式的,當多個應用程式通過使用ContentResolver 來操作使用ContentProvider 提供的資料時,ContentResolver 呼叫的資料操作會委託給同一個ContentProvider 來處理。這樣就能保證資料的一致性。 資料庫工具類DBHelper.java import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; publicclass DBHelperextendsSQLiteOpenHelper{ public DBHelper(Contextcontext,intversionCode){ super(context,"users.db",null,versionCode); } @Override publicvoid onCreate(SQLiteDatabasedb) { // TODO 初始化建立表 db.execSQL("create table t_user(_id integer primary key ,uname,upass,money)"); db.execSQL("create table t_order(_id integer primary key ,product_name,price,user_id)"); //對於sqlite來說,只要是integer的主鍵,則是自動增長的,無需用autoincrement指定 db.execSQL("insert into t_user(uname,upass,money) values('disen','123',1000)"); db.execSQL("insert into t_user(uname,upass,money) values('jack','234',10000)"); } @Override publicvoid onUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion) { // TODO  升級資料庫(刪除舊錶,建立新表) if(newVersion>oldVersion){ db.execSQL("drop table if exists t_user"); db.execSQL("drop table if exists t_order"); onCreate(db); } } } 在AndroidManifest.xml中的<application>標籤中: <!-- 註冊ContentProvider元件,   android:authorities屬性聲明當前元件的唯一標識,在Resolver中使用uri時,它作為中間部分,後面還要跟著path    android:exported="true" 設定當前元件可以被外部應用訪問 --> <providerandroid:name="com.user.contentprovider.UserContentProvider" android:authorities="com.user.contentprovider.users" android:exported="true"/> UserContentProvider.java publicclassUserContentProviderextends ContentProvider { // 聲明當前ContentProvider元件的唯一標識(Authority),注:必須使用小寫字母 privatestaticfinal StringAUTHORITY ="com.user.contentprovider.users"; // 宣告訪問當前應用下的資料庫中哪些資源,給這些訪問資源宣告code標識 privatestaticfinalintCODE_USER = 0; privatestaticfinalintCODE_ORDER = 6; // 宣告完整的資源訪問Uri的匹配器--UriMatcher,例項化它並增加資源訪問的Uri privatestatic UriMatcheruriMatcher; static { uriMatcher =new UriMatcher(UriMatcher.NO_MATCH);// 值是-1 //UriMatcher.addURI(String authority, String path, int code) // 用Resolver訪問時的Uri // content://com.qf.contentprovider.users/users uriMatcher.addURI(AUTHORITY,"users",CODE_USER); // content://com.qf.contentprovider.users/orders uriMatcher.addURI(AUTHORITY,"orders",CODE_ORDER);//假設是訂單表 } /**  * 自定義的資料庫工具類  */ private DBHelperdbHelper; @Override publicboolean onCreate() { // TODO 初始化ConentProvider元件,例項化資料庫操作工具類 dbHelper =new DBHelper(getContext(), 1);//第二個引數是版本號 returntrue;// 成功返回true } @Override public

相關推薦

Android ContentResolver 內容解析(解析)----重新認識Android11

注意需要申請許可權,否則執行會出現異常:WRITE_CALL_LOG,READ_CALL_LOG /**  * ContentProvider內容提供者 1.主要用於不同的應用程式之間,共享資料的。 A:ContentProvider:向外提供資料的  * 用於通過Uri向外暴露資料。只要將應用安裝

Spring Cloud:服務閘道Zuul高階篇11

時間過的很快,寫springcloud(十):服務閘道器zuul初級篇還在半年前,現在已經是2018年了,我們繼續探討Zuul更高階的使用方式。 上篇文章主要介紹了Zuul閘道器使用模式,以及自動轉發機制,但其實Zuul還有更多的應用場景,比如:鑑權、流量轉發、請求統計等等,這些功能都可以使用Z

重新認識java ---- Enum列舉類

有的人說,不推薦使用列舉。有的人說,列舉很好用。究竟怎麼使用,如何使用,仁者見仁智者見智。總之,先學會再說~ 為什麼要引入列舉類 一個小案例 你寫了一個小程式,不過好久不用了,突然有一天,你想使用一下它。程式要想正確執行,需要將今天星期幾存

重新認識java ---- 面向物件之繼承!

學習一個新知識的第一步,就是要知道它是什麼,然後要知道為什麼要用它,最後要知道如何使用它。這篇文章,我們重新認識一下java中的繼承。 繼承是個什麼東西 我們先來看一下上一篇文章中的程式碼: 你會發現,這兩個類中都有name屬性,都有

重新認識java ---- 萬物皆物件

如果你現實中沒有物件,至少你在java世界裡會有茫茫多的物件,聽起來是不是很激動呢? 物件,引用,類與現實世界 現實世界裡有許許多多的生物,非生物,跑的跳的飛的,過去的現在的未來的,令人眼花繚亂。我們程式設計的目的,就是解決現實生活中的問題。所以

重新認識java --- 不積跬步無以至千里

好高騖遠,眼高手低,是你前進路上最大的絆腳石 — 致走在學習道路上的人 p.s. 本篇文章沒有技術含量。 關於自己 先說說我自己吧。目前是一名軟體工程的大三學生。前幾天一直在迷茫:究竟是技多不壓身還是貪多嚼不爛。 大一的一年,我沒有好好學

重新認識java ---- java中的另類:static關鍵字附程式碼塊知識

你知道麼,static的用法至少有五種? 初識static static是“靜態”的意思,這個大家應該都清楚,靜態變數,靜態方法大家也都能隨口道來。但是,你真的理解靜態變數和靜態方法麼?除了這些static還有什麼用處? 事實上,static大

重新認識java ---- 內部類

注意注意!!!前排提示!!!本篇文章過長,最好收藏下來慢慢看,如果你之前對內部類不是很熟悉,一次性看完,大概你會懵逼。。。 1. 內部類概述 一個類的定義放在另一個類的內部,這個類就叫做內部類。內部類是一種非常有用的特性,因為它允許你把一些邏輯相

Android-Observer(內容觀察)

內容提供者應用暴露的資料,是被多個其他應用訪問(insert,update,delete,query),但如果L應用要查詢(內容提供者應用暴露的資料),難道要開啟子執行緒一直迴圈去查詢 ? 答:開啟子執行緒一直迴圈去查詢是不合理的(是嚴重的錯誤),所以Android提供了Observer(內容觀察者)這種機

Android 網路資料解析實現一個簡單的新聞例項

      一般安卓在學到非同步任務AsyncTask之後都會有個安卓小專案的任務。得到(荔枝新聞,茶百科等)新聞網路介面來解析網路圖片或文字到ListView元件上顯示。其中要使用到的知識大概有:獲取網路資料(HttpUtil),解析網路資料(NewsParse),防止因

基於逆波蘭表示式的公式解析-演算法和思路

背景:        最近專案需要自己完成Excel的公式解析和求值,在Java中可以使用POI解析Excel公式然後求值。但是專案需要JS端和Java後端均需要支援公式解析,所以就需要自己寫一套了。

Android內容觀察

有個很常見的需求就是當有新的簡訊來的時候,把內容顯示在介面上。這裡就要用到內容觀察者。就是讓你的程式監視簡訊,如果他內容發生變化的時候,你去獲取。而簡訊那邊做的情況就 是,當他自己的資料變化時,他告訴有個公共簡訊記憶體區,他說,我資料變化了!然後通過簡訊的內容提供者把簡訊的

聊聊高並發二十四解析java.util.concurrent各個組件 深入理解AQS

sar 成功 通知 ati help write ng- ads 同步 近期總體過了下AQS的結構。也在網上看了一些講AQS的文章,大部分的文章都是泛泛而談。又一次看了下AQS的代碼,把一些新的要點拿出來說一說。 AQS是一個管程。提供了一個主要的同步器的

MVVM模式解析和在WPF中的實現

開發 特點 還需 如果 情況下 依次 顯示 尋找 這也 MVVM模式簡介 MVVM是Model、View、ViewModel的簡寫,這種模式的引入就是使用ViewModel來降低View和Model的耦合,說是降低View和Model的耦合。也可以說是是降低界面和邏輯的耦合

[java源碼解析]對HashMap源碼的分析

具體實現 修改 ring 數組大小 inflate 大小 transient misc ear 上文我們講了HashMap那騷騷的邏輯結構,這一篇我們來吹吹它的實現思想,也就是算法層面。有興趣看下或者回顧上一篇HashMap邏輯層面的,可以看下HashMap源碼解析(一)。

Android應用--簡 美音樂播放獲取專輯圖片自定義列表介面卡

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Android系統播放MediaPlayer原始碼分析

前言 對於MediaPlayer播放器的原始碼分析內容相對來說比較多,會從Java->JNI->C/C++慢慢分析,後面會慢慢更新。另外,部落格只作為自己學習記錄的一種方式,對於其他的不過多的評論。 MediaPlayerDemo public class MainA

C++深度解析 布林型別bool 和 引用 &3

C++深度解析 布林型別和引用(3)     1 布林型別 bool 在C++中,bool型別只有true(非0)和false(0)兩個值,且bool型別只佔用了一個位元組 true:非0 false:0  示例一: #include &

爬蟲入門,爬蟲簡單的入門庫Beautifulsoup庫,解析網頁,簡單用法-案例篇5

           BeautifulSoup 庫是一個非常流行的Python的模組。通過BeautifulSoup 庫可以輕鬆的解析請求庫請求的網頁,並把網頁原始碼解析為湯文件,以便過濾提取資料

Java原始碼解析之可重入鎖ReentrantLock

上文接Java原始碼解析之可重入鎖ReentrantLock(一)。 接下來是tryLock方法。程式碼如下。從註釋中我們可以理解到,只有當呼叫tryLock時鎖沒有被別的執行緒佔用,tryLock才會獲取鎖。如果鎖沒有被另一個執行緒佔用,那麼就獲取鎖,並立刻返回true,並把鎖計數設定為1.