Android ContentResolver 內容解析者(解析器)----重新認識Android(11)
/** * ContentProvider內容提供者 1.主要用於不同的應用程式之間,共享資料的。 A:ContentProvider:向外提供資料的 * 用於通過Uri向外暴露資料。只要將應用安裝到手機上。無論是否執行,都可以獲取資料。 B:ContentResolver:獲取並解析資料 * 用於解析通過ContentProvider暴露 出來的資料。 A應用暴露出的是Uri,B應用使用該Uri就可以訪問A應用暴露出來的資料了。 * =====================================================
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 內容解析者(解析器)----重新認識Android(11)
注意需要申請許可權,否則執行會出現異常: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.