Android知識點(一)

做Android開發(fā)已經(jīng)一兩年了建钥,回首這一兩年的歲月藤韵,雖然學(xué)習(xí)到很多技能點,但是大部分技能用過之后熊经,不久就被遺忘了泽艘,為了防止自己再去踩前面踩過的坑,我決定從今天起镐依,把自己用到的技能點做一個總結(jié)匹涮,日后能夠提高自己的工作效率,同時槐壳,希望能夠幫助到更多的開發(fā)者然低。后面會不斷的完善。

okhttp,retrofit,rxjava,mvp,插件化,熱修復(fù)(近兩年熱點技術(shù)點)

zero雳攘、開發(fā)環(huán)境

1带兜、Android開發(fā)工具集合:http://www.androiddevtools.cn/

小技巧:logt以當(dāng)前的類名做為值自動生成一個TAG常量。

一吨灭、Activity

1刚照、在活動中使用Menu;

第一步:在res目錄下創(chuàng)建一個menu文件夾喧兄;右擊menu文件夾創(chuàng)建一個文件(例如起名為“main”)无畔;

第二步:在main文件中完成下面代碼:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_item"
android:title="Add"/>
<item
android:id="@+id/remove_item"
android:title="Remove"/>
</menu>

第三步:重現(xiàn)回到Activity,重寫onCreateOptionsMenu()方法和onOptionsItemSelected()方法吠冤,例如下面的代碼:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.add_item:
Toast.makeText(this, "You clicked Add", Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(this, "You clicked Remove", Toast.LENGTH_SHORT).show();
break;
default:
}
return true;

}

2檩互、Intent在活動之間穿梭;

(1)顯示Intent:

 Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
 startActivity(intent);

(2)隱式Intent:

<activity
        android:name=".SecondActivity"
        android:launchMode="singleInstance">
         <intent-filter>
             <action android:name="com.example.activitytest.ACTION_START" />
             <category android:name="android.intent.category.DEFAULT" />
             <category android:name="com.example.activitytest.MY_CATEGORY" />
         </intent-filter>
     </activity>

Intent intent = new Intent("com.example.activitytest.ACTION_START");
//intent.addCategory("com.example.activitytest.MY_CATEGORY");
startActivity(intent);

只有<action>和<category>中的內(nèi)容同時能夠匹配上Intent中指定的action和category時咨演,這個活動才能響應(yīng)該Intent闸昨;每個Intent中只能指定一個action,卻能指定多個category薄风;

更多隱式Intent的用法:

(3)如下調(diào)用系統(tǒng)瀏覽器打開一個網(wǎng)頁饵较,

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.baidu.com/"));
startActivity(intent);

(4)撥打電話

    Intent intent = new Intent(Intent.ACTION_DIAL);
    intent.setData(Uri.parse("tel:10086"));
    startActivity(intent);

(5)Intent向下一個活動傳遞數(shù)據(jù)(put和get),具體支持哪些數(shù)據(jù)類型遭赂,自己查看Android API文檔循诉;

(6)返回數(shù)據(jù)給上一個活動

FirstActivity:

     Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
     startActivityForResult(intent,1);

 @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case 1:
                    if (resultCode == RESULT_OK) {
                     String returnedData = data.getStringExtra("data_return");
                     Log.d("FirstActivity", returnedData);
                    }
                    break;
            default:
        }
}

SecondActivity:

    Intent intent = new Intent();
    intent.putExtra("data_return","Hello  FristActivity");
    setResult(RESULT_OK,intent);
    finish();

@Override
public void onBackPressed() {
        Intent intent = new Intent();
        intent.putExtra("data_return", "Hello FirstActivity");
        setResult(RESULT_OK, intent);
        finish();
}

3、Activity的生命周期撇他;

image.png

4茄猫、Activity的啟動模式;

(1)standard模式(任務(wù)棧困肩,先進(jìn)后出)

image.png

(2)singleTop(頂端復(fù)用模式)

image.png

(3)singleTask(單實例模式)

image.png

(4)singleInstance(singleTask的增強版划纽,會單獨開啟一個任務(wù)棧)

image.png

5、動態(tài)更新應(yīng)用Icon

二锌畸、UI開發(fā)

Android 基礎(chǔ):常用布局 介紹 & 使用

1勇劣、常用控件的使用

 所有的Android控件都具有android:visibility屬性,可選值有3種:visible、invisible和gone潭枣。
 visible表示控件是可見的,這個值是默認(rèn)值比默,不指定android:visibility時,控件都是可見的。
 invisible表示控件不可見,但是它仍然占據(jù)著原來的位置和大小,可以理解為控件變成透明狀態(tài)了盆犁。
 gone則表示控件不僅不可見命咐,而且不再占用任何屏幕空間。
 也可以在代碼中設(shè)置,例如:imageView.setVisibility(View.VISIBLE);

(1)TextView

 android:gravity屬性來指定文字(相對于控件本身)的對齊方式,可選值有top谐岁、bottom醋奠、left瓮下、right、center等钝域。
 android:layout_gravity屬性,指控件相對于父控件的對齊方式;

想要掌握更多TextView的屬性讽坏,可以自己去查閱API文檔;

(2)Button

 android:textAllCaps="false",不將Button中的所有英文字母自動轉(zhuǎn)成大寫;

(3)EditText

android:hint屬性例证,EditText文本為空時顯示的提示文本;
android:maxLines="2"屬性指定EditText最大行數(shù)為兩行,這樣當(dāng)輸入的內(nèi)容超過兩行時,文本就會向下滾動,而EditText則不會再繼續(xù)拉伸路呜。

(4)ImageView

 可以使用android:src屬性給ImageView指定一張圖片。也可以在代碼中通過
 imageView.setImageResource(R.mipmap.ic_launcher)動態(tài)地更改ImageView中的圖片织咧。

(5)ProgressBar

style="?android:attr/progressBarStyleHorizontal"(水平進(jìn)度條屬性)
android:max="100"(給進(jìn)度條設(shè)置一個最大值)
更新進(jìn)度:
  int progress = this.progressBar.getProgress();
  progress = progress+10;
  progressBar.setProgress(progress);

(6)AlertDialog(對話框)

 小例子:
    AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
    dialog.setTitle("This is Dialog");
    dialog.setMessage("Something important.");
    dialog.setCancelable(false);
    dialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            
        }
    });
    dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            
        }
    });
    dialog.show();

(7)ProgressDialog

 類似于AlertDialog,可以顯示進(jìn)度條胀葱,表示當(dāng)前操作比較耗時,讓用戶耐心等待笙蒙。
小例子:
    ProgressDialog progressDialog = new ProgressDialog(this);
    progressDialog.setTitle("This is ProgressDialog");
    progressDialog.setMessage("Loading...");
    progressDialog.setCancelable(true);
    progressDialog.show();

2抵屿、6種基本布局

第一種,LinearLayout線性布局捅位,注意方向
第二種轧葛,RelativeLayout相對布局,相對于父布局進(jìn)行定位艇搀,或者相對于其他控件進(jìn)行定位;
第三種尿扯,F(xiàn)rameLayout幀布局
LinearLayout支持layout_weight屬性來實現(xiàn)按比例指定控件大小的功能,其他兩個布局都不支持焰雕。
第四種衷笋,百分比布局

使用百分比布局
第一步,在build.gradle文件中添加依賴:
compile 'com.android.support:percent:24.2.1'
第二步矩屁,使用PercentFrameLayout或者PercentRelativeLayout兩種布局(注意要定義一個app的命名空間);
第三步辟宗,在控件中使用app:layout_widthPercent、app:layout_heightPercent等屬性吝秕;

第五種泊脐,AbsoluteLayout(很少使用);
第六種郭膛,TableLayout(很少使用)晨抡;

3氛悬、自定義控件

第一步则剃,引入布局;
第二步如捅,創(chuàng)建自定義控件(初始化棍现,onMeasure,onLayout镜遣,onDraw)己肮;

4士袄、ListVIew

知識點一,使用Android提供的適配器谎僻;
知識點二娄柳,定制ListView的界面(圖文混排),自己寫Adapter艘绍;
知識點三赤拒,ViewHolder的使用和convertView的復(fù)用,提高運行效率诱鞠;
知識點四挎挖,ListView的點擊事件;

5航夺、RecyclerView

知識點一蕉朵,RecyclerView的基本用法:
第一步,build.gradle中添加依賴阳掐;
第二步始衅,寫一個adapter繼承RecyclerView.Adapter(重寫 onCreateViewHolder,onBindViewHolder和getItemCount方法)
第三步缭保,在代碼中使用RecyclerView觅闽;(注意:不要忘了LayoutManager)
知識點二,實現(xiàn)橫向滾動和瀑布流布局

實現(xiàn)橫向布局: 
  LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
  linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
實現(xiàn)瀑布流布局:
GridLayoutManager gridLayoutManager = new GridLayoutManager(this);
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);

知識點三涮俄,RecyclerView點擊事件(即可以實現(xiàn)Item的點擊事件蛉拙,又可以實現(xiàn)item內(nèi)部控件的點擊事件)

6、制作Nine-Patch圖片

第一步彻亲,在Android sdk目錄中有個tools文件夾孕锄,在文件夾中找到draw9patch.bat文件(必須先將JDK的bin目錄配置到環(huán)境變量中)打開;
第二步苞尝,繪制(使用鼠標(biāo)在圖片的邊緣拖動)畸肆,擦除(按住Shirft鍵,拖動鼠標(biāo)就可以進(jìn)行擦除)

三宙址、Fragment

Fragment結(jié)合ViewPager之懶加載

Fragment懶加載和ViewPager的坑

1轴脐、Fragment的使用方式

(1)Fragment的簡單使用方法

第一步,創(chuàng)建Fragment和該Fragment對應(yīng)的布局;(LeftFragment和RightFragment)
第二步抡砂,將創(chuàng)建好的Fragment添加進(jìn)Activity中大咱,具體如下(activity布局代碼)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

<fragment
    android:id="@+id/left_fragment"
    android:name="com.example.fragmenttest.LeftFragment"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1" />

<fragment
    android:id="@+id/right_fragment"
    android:name="com.example.fragmenttest.RightFragment"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="3" />
</LinearLayout>

(2)動態(tài)添加Fragment

第一步,創(chuàng)建待添加的碎片實例注益;
例如:
replaceFragment(new RightFragment());
replaceFragment(new AnotherRightFragment());
第二步碴巾,獲取FragmentManager;
FragmentManager fragmentManager = getSupportFragmentManager();
第三步丑搔,開啟一個事務(wù)厦瓢;
FragmentTransaction transaction = fragmentManager.beginTransaction();
第四步提揍,向容器內(nèi)添加或替換碎片;
transaction.replace(R.id.right_layout, fragment);
第五步煮仇,提交事務(wù)
transaction.commit();

(3)在Fragment中模擬返回棧

上面的事務(wù)提交之前劳跃,調(diào)用transaction.addToBackStack(null);將RightFragment和AnotherRightFragment添加到活動中,然后按下Back鍵浙垫,程序并沒有退出售碳,而是回到了RightFragment界面,繼續(xù)按下Back鍵绞呈,RightFragment界面消失贸人,再次按下Back鍵,程序才會退出佃声。

(4)Fragment和活動之間通信

在活動中調(diào)用Fragment碎片的方法:
RightFragment rightFragment = (RightFragment)getFragmentManager();

在Fragment碎片中調(diào)用活動的方法:
MainActivity activity = (Activity)getActivity();

在AnotherRightFragment碎片中調(diào)用另一個RightFragment碎片的方法:
MainActivity activity = (Activity)getActivity();
RightFragment rightFragment = (RightFragment)getFragmentManager();

2艺智、Fragment的生命周期

fragment_lifecycle.png

3、動態(tài)加載布局

在res目錄下新建layout-large文件夾圾亏,手機(jī)上加載單頁模式十拣,平板上加載雙頁模式
單頁模式:顯示layout/activity_main,只包含一個Fragment碎片的布局志鹃;
雙頁模式:顯示layout-large/activity_main夭问,包含了兩個碎片的布局;
最小寬度限定符:在res目錄下新建layout-sw600dp文件夾曹铃,然后在這個文件夾下新建activity_main.xml布局缰趋。當(dāng)設(shè)備屏幕寬度小于600dp時,加載layout/activity_main布局陕见,當(dāng)設(shè)備屏幕寬度大于600dp時秘血,會加載layout-sw600dp/activity_main布局。

四评甜、廣播機(jī)制(Broadcast Receiver)

1灰粮、廣播機(jī)制簡介

(1)標(biāo)準(zhǔn)廣播

異步、無序忍坷、效率高粘舟,但是無法被截斷(終止);

(2)有序廣播

同步、有序(優(yōu)先級高的廣播接收器先收到廣播消息)佩研、效率低柑肴,但是可以被截斷,截斷后韧骗,后面的廣播接收器就無法收到廣播消息了嘉抒。

2、接收系統(tǒng)廣播

(1)動態(tài)注冊監(jiān)聽網(wǎng)絡(luò)變化

第一步袍暴,寫一個類繼承BroadcastReceiver些侍,然后實現(xiàn)onReceive方法授瘦;

   class NetworkChangeReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        ConnectivityManager connectionManager = (ConnectivityManager)
                getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();
        if (networkInfo != null && networkInfo.isAvailable()) {
            Toast.makeText(context, "network is available",
                    Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(context, "network is unavailable",
                    Toast.LENGTH_SHORT).show();
        }
    }
}

第二步逗宜,注冊廣播接收器

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
NetworkChangeReceiver networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver, intentFilter);

第三步碍粥,取消注冊

 unregisterReceiver(networkChangeReceiver);

最后月杉,不要忘了聲明權(quán)限(為了更好的保證用戶設(shè)備的安全和隱式蚤霞,Android6.0系統(tǒng)中引入了更加嚴(yán)格的運行時權(quán)限)

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

(2)靜態(tài)注冊實現(xiàn)開機(jī)啟動

第一步嘹悼,創(chuàng)建BootCompleteReceiver繼承BroadcastReceiver

public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
  }
}

第二步昔馋,在AndroidMannifest清單文件中注冊該廣播

<receiver
        android:name=".BootCompleteReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
</receiver>

第三步五芝,聲明權(quán)限

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

這樣開機(jī)就能收到一條Boot Complete的Toast趁猴;

3刊咳、發(fā)送自定義廣播

(1)發(fā)送標(biāo)準(zhǔn)廣播

第一步,新建一個MyBroadcastReceiver廣播接收器儡司,代碼如下:

public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show();
   }
}

第二步娱挨,修改注冊該廣播接收器,代碼如下:

<receiver
        android:name=".MyBroadcastReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
        </intent-filter>
</receiver>

第三步捕犬,發(fā)送廣播跷坝,代碼如下:

Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);

(2)發(fā)送有序廣播

第一步,接著上面的項目碉碉,新建一個新的項目并且新建AnotherBroadcastReceiver柴钻,代碼如下:

public class AnotherBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    Toast.makeText(context, "received in AnotherBroadcastReceiver",
            Toast.LENGTH_SHORT).show();
   }
}

第二步,AndroidMannifest清單文件中注冊該廣播垢粮,代碼如下:

<receiver
        android:name=".AnotherBroadcastReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.example.broadcasttest.MY_BROADCAST" />
        </intent-filter>
</receiver>

第三步贴届,重新回到上個項目,重新發(fā)送廣播蜡吧,代碼如下:

Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);

這樣能夠看到兩個Toast(received in MyBroadcastReceiver和received in AnotherBroadcastReceiver)

發(fā)送有序廣播
第一步粱腻,發(fā)送有序廣播,

Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendOrderedBroadcast(intent,null);

第二步斩跌,將AnotherBroadcastReceiver的AndroidMannifest清單文件中將優(yōu)先級設(shè)置成100绍些;

android:priority="100"

第三步,在MyBroadcastReceiver截斷廣播

abortBroadcast();

這樣AnotherBroadcastReceiver就收不到廣播了耀鸦。

4柬批、使用本地廣播

前面這些廣播屬于系統(tǒng)全局廣播,可以被其他應(yīng)用程序接收到袖订,也可以接收來自其他任何應(yīng)用程序的廣播氮帐。這樣很容易引起安全性的問題,攜帶關(guān)健型數(shù)據(jù)的廣播可能被其他的應(yīng)用程序截獲洛姑,其他的程序可以不停的向我們的廣播接收器里發(fā)送各種垃圾廣播上沐。因此Android引入一套本地廣播機(jī)制。
第一步楞艾,獲取到LocalBroadcastManager實例参咙,

LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this); // 獲取實例

第二步龄广,注冊廣播接收器,代碼如下:

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver, intentFilter); // 注冊本地廣播監(jiān)聽器

class LocalReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show();
    }
}

第三步蕴侧,發(fā)送本地廣播择同,代碼如下:

Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast(intent); // 發(fā)送本地廣播

第四步,注銷本地廣播净宵,代碼如下:

localBroadcastManager.unregisterReceiver(localReceiver);

image.png

廣播的最佳實踐之強制下線功能敲才。

五、數(shù)據(jù)存儲

1择葡、文件存儲

(1)將數(shù)據(jù)存儲到文件中

Context類中提供了一個openFileOutput(String name, int mode)方法紧武,
Open a private file associated with this Context's application package for writing.
可以用于將數(shù)據(jù)存儲到指定的文件中。方法中第一個參數(shù)是文件名敏储,這里指定的文件名不可以包含路徑阻星,所有的文件都是默認(rèn)存儲到/data/data/<packagename>/files目錄下的。第二個參數(shù)是文件的操作模式虹曙,主要有兩種模式可選迫横,MODE_PRIVATE是默認(rèn)的操作模式,表示當(dāng)指定同樣文件名的時候酝碳,所寫入的內(nèi)容將會覆蓋原文件中的內(nèi)容矾踱;MODE_APPEND則表示如果該文件已存在,就往文件中追加內(nèi)容疏哗,不存在就創(chuàng)建新文件呛讲。

小示例:

    String inputText = edit.getText().toString();
    FileOutputStream out = null;
    BufferedWriter writer = null;
    try {
        out = openFileOutput("data", Context.MODE_PRIVATE);
        writer = new BufferedWriter(new OutputStreamWriter(out));
        writer.write(inputText);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (writer != null) {
                writer.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

(2)從文件中讀取數(shù)據(jù)

Context類中還提供了一個openFileInput(String name)方法,
Open a private file associated with this Context's application package for reading.
參數(shù)功能類似于openFileOutput(String name, int mode)方法返奉,

小示例:

    FileInputStream in = null;
    BufferedReader reader = null;
    StringBuilder content = new StringBuilder();
    try {
        in = openFileInput("data");
        reader = new BufferedReader(new InputStreamReader(in));
        String line = "";
        while ((line = reader.readLine()) != null) {
            content.append(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return content.toString();

2贝搁、SharedPreferences存儲

SharedPreferences是使用鍵值對的方式來存儲數(shù)據(jù)的,根據(jù)鍵來存取數(shù)據(jù)芽偏。

(1)將數(shù)據(jù)存儲到SharedPreferences中

Android中提供了3種方法用于得到SharedPreferences對象雷逆。

第一種,Context類中的getSharedPreferences(String name, int mode)方法污尉,
Retrieve and hold the contents of the preferences file 'name', returning a SharedPreferences through which you can retrieve and modify its values.
該方法中第一個參數(shù)用于指定SharedPreferences文件的名稱膀哲,如果指定的文件不存在則會創(chuàng)建一個,SharedPreferences文件都是存在/data/data/<packagename>/shared_prefs/目錄下的被碗。第二個參數(shù)用于指定操作模式某宪,目前只有MODE_PRIVATE這一種模式可選。

第二種锐朴,Activity類中的getPreferences(int mode)方法兴喂,
Retrieve a SharedPreferences object for accessing preferences that are private to this activity.
此方法只接收一個操作模式參數(shù),使用這個方法時會自動將當(dāng)前活動的類名作為SharedPreferences的文件名。

第三種衣迷,PreferenceManager類中的getDefaultSharedPreferences(Context context)方法畏鼓,
Gets a SharedPreferences instance that points to the default file that is used by the preference framework in the given context.
自動使用當(dāng)前應(yīng)用程序的包名作為前綴來命名SharedPreferences文件。

向SharedPreferences文件中存儲數(shù)據(jù)

第一步蘑险,調(diào)用SharedPreferences對象edit()方法來獲取一個SharedPreferences.Editor對象滴肿。

第二步岳悟,向SharedPreferences.Editor對象中添加數(shù)據(jù)佃迄,putBoolean(),putString()等方法贵少。

第三步呵俏,調(diào)用apply()方法將添加的數(shù)據(jù)提交,從而完成數(shù)據(jù)存儲操作滔灶。

小例子:

SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
            editor.putString("name", "Tom");
            editor.putInt("age", 28);
            editor.putBoolean("married", false);
            editor.apply();

(2)從SharedPreferences中讀取數(shù)據(jù)

小例子:

SharedPreferences pref = getSharedPreferences("data", MODE_PRIVATE);
            String name = pref.getString("name", "");
            int age = pref.getInt("age", 0);
            boolean married = pref.getBoolean("married", false);

3普碎、SQLite數(shù)據(jù)庫存儲

(1)創(chuàng)建數(shù)據(jù)庫

第一步,寫一個類繼承SQLiteOpenHelper類录平,并實現(xiàn)onCreate()和onUpgrade()方法麻车,然后分別在這兩個方法中去實現(xiàn)創(chuàng)建、升級數(shù)據(jù)庫的邏輯斗这。(在onCreate()方法中執(zhí)行建表語句)

第二步动猬,創(chuàng)建繼承SQLiteOpenHelper類的對象,執(zhí)行g(shù)etReadableDatabase()
Create and/or open a database.或getWritableDatabase()方法表箭,
Create and/or open a database that will be used for reading and writing.
這兩個方法都可以創(chuàng)建或打開一個現(xiàn)有的數(shù)據(jù)庫(如果數(shù)據(jù)庫已存在則直接打開赁咙,否則創(chuàng)建一個新的數(shù)據(jù)庫),并返回一個可對數(shù)據(jù)庫進(jìn)行讀寫操作的對象免钻。不同的是彼水,當(dāng)數(shù)據(jù)庫不可寫入的時候(如磁盤空間已滿),getReadableDatabase()方法返回的對象將以只讀的方式去打開數(shù)據(jù)庫极舔,而getWritableDatabase()方法則將出現(xiàn)異常凤覆。

這樣在/data/data/<package name>/databases/目錄下就會創(chuàng)建一個數(shù)據(jù)庫文件。

小示例:

public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table Book ("
        + "id integer primary key autoincrement, "
        + "author text, "
        + "price real, "
        + "pages integer, "
        + "name text)";

private Context mContext;

public MyDatabaseHelper(Context context, String name,
                        SQLiteDatabase.CursorFactory factory, int version) {
    super(context, name, factory, version);
    mContext = context;
}

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(CREATE_BOOK);
    Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  }
}

MainActivity.class

public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
    Button createDatabase = (Button) findViewById(R.id.create_database);
    createDatabase.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            dbHelper.getWritableDatabase();
        }
    });
  }
}

使用adb shell來對數(shù)據(jù)庫和表的創(chuàng)建情況進(jìn)行檢查拆魏。

第一步盯桦,在系統(tǒng)變量里找到Path并點擊編輯,將platform-tools目錄配置進(jìn)去稽揭。(如果使用的是Linux或Mac系統(tǒng)俺附,可以在home路徑下編輯.bash_文件,將platform-tools目錄配置進(jìn)去即可溪掀。)

第二步事镣,打開命令行,輸入adb shell;

第三步,使用cd命令進(jìn)入到/data/data/<package name>/databases/目錄下璃哟,并使用ls命令查看改目錄里的文件(BookStore.db-journal則是為了讓數(shù)據(jù)庫能夠支持事務(wù)而產(chǎn)生的臨時日志文件)氛琢;

第三步,鍵入sqlite3 + 數(shù)據(jù)庫名 打開數(shù)據(jù)庫随闪;

第四步阳似,鍵入.table命令打開數(shù)據(jù)庫;(.help命令列出所有的命令清單進(jìn)行查看)铐伴。

第五步撮奏,可以通過.schema命令來查看它們的建表語句。之后鍵入.exit或.quit命令可以退出數(shù)據(jù)庫的編輯当宴,再鍵入exit命令就可以退出設(shè)備控制臺了畜吊。

(2)升級數(shù)據(jù)庫

在上面創(chuàng)建數(shù)據(jù)庫的代碼上進(jìn)行如下更改:

public static final String CREATE_CATEGORY = "create table Category ("
        + "id integer primary key autoincrement, "
        + "category_name text, "
        + "category_code integer)";
@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(CREATE_BOOK);
    db.execSQL(CREATE_CATEGORY);//添加
    Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("drop table if exists Book");
    db.execSQL("drop table if exists Category");
    onCreate(db);
}

MainActivity中的代碼:

public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);//版本號改為2
    Button createDatabase = (Button) findViewById(R.id.create_database);
    createDatabase.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            dbHelper.getWritableDatabase();
        }
    });
  }
}

(3)添加數(shù)據(jù)

小示例:

SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
// 開始組裝第一條數(shù)據(jù)
values.put("name", "The Da Vinci Code");
values.put("author", "Dan Brown");
values.put("pages", 454);
values.put("price", 16.96);
db.insert("Book", null, values); // 插入第一條數(shù)據(jù),該方法第二個參數(shù)用于在未指定添加數(shù)據(jù)的情況下給某些可為空的列自動賦值NULL户矢,一般用不到玲献,直接傳入null即可。
values.clear();
// 開始組裝第二條數(shù)據(jù)
values.put("name", "The Lost Symbol");
values.put("author", "Dan Brown");
values.put("pages", 510);
values.put("price", 19.95);
db.insert("Book", null, values); // 插入第二條數(shù)據(jù)

(4)更新數(shù)據(jù)

  SQLiteDatabase db = dbHelper.getWritableDatabase();
  ContentValues values = new ContentValues();
  values.put("price", 10.99);
  db.update("Book", values, "name = ?", new String[] { "The Da Vinci Code" });//第三梯浪、第四個參數(shù)用于約束更新某一行或某幾行中的數(shù)據(jù)捌年,不指定的話默認(rèn)就是更新所有行。

(5)刪除數(shù)據(jù)

SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("Book", "pages > ?", new String[] { "500" });//第二挂洛、第三個參數(shù)又是用于約束刪除某一行或某幾行的數(shù)據(jù)礼预,不指定的話默認(rèn)就是刪除所有行。

(6)查詢數(shù)據(jù)

image.png
 SQLiteDatabase db = dbHelper.getWritableDatabase();
 // 查詢Book表中所有的數(shù)據(jù)
 Cursor cursor = db.query("Book", null, null, null, null, null, null);
       if (cursor.moveToFirst()) {
            do {
                    // 遍歷Cursor對象抹锄,取出數(shù)據(jù)并打印
                    String name = cursor.getString(cursor.getColumnIndex("name"));
                    String author = cursor.getString(cursor.getColumnIndex("author"));
                    int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                    double price = cursor.getDouble(cursor.getColumnIndex("price"));
                    Log.d("MainActivity", "book name is " + name);
                    Log.d("MainActivity", "book author is " + author);
                    Log.d("MainActivity", "book pages is " + pages);
                    Log.d("MainActivity", "book price is " + price);
                } while (cursor.moveToNext());
            }
  cursor.close();

(7)使用SQL操作數(shù)據(jù)庫

image.png

4逆瑞、使用LitePal操作數(shù)據(jù)庫

github上關(guān)于LitePal的使用
或者看第二行代碼中的介紹

六、跨程序共享數(shù)據(jù)(內(nèi)容提供者Content Provider)

1伙单、運行時權(quán)限

(1)Android權(quán)限機(jī)制詳解

比如一款相機(jī)應(yīng)用在運行時申請了地理位置定位權(quán)限获高,就算我拒絕了這個權(quán)限,但是我應(yīng)該仍然可以使用這個應(yīng)用的其他功能吻育,不像之前那樣不授權(quán)就無法安裝念秧。只有涉及到用戶隱私的情況下才需要申請運行時權(quán)限,下面是所有需要申請運行時權(quán)限的權(quán)限(危險權(quán)限)

image.png

(2)在程序運行時申請權(quán)限

Android6.0及以上系統(tǒng)在使用危險權(quán)限時都必須進(jìn)行運行時權(quán)限處理布疼。
小示例:

if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE)!= PackageManager.PERMISSION_GRANTED){
         ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.CALL_PHONE},1);
}else {
                call();
       }

private void call() {
    try {
        Intent intent = new Intent(Intent.ACTION_CALL);
        intent.setData(Uri.parse("tel:10086"));
        startActivity(intent);
    } catch (SecurityException e) {
        e.printStackTrace();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode){
        case 1:
            if (grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
                call();
            }else {
                Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
            }
            break;
        default:
    }
}

2摊趾、訪問其他程序中的數(shù)據(jù)

(1)ContentResolver的基本用法

URI:
content://com.example.app.provider/table1
協(xié)議 | authority | path
authority用于區(qū)分不同應(yīng)用程序,一般用包名 ;path則是用于對同一應(yīng)用程序中不同的表做區(qū)分的游两。

查詢一條數(shù)據(jù):


image.png

添加一條數(shù)據(jù):

ContentValues values = new ContentValues();
values.put("column1", "text");
values.put("column2", 1);
getContentResolver().insert(uri, values);

更新一條數(shù)據(jù):

ContentValues values = new ContentValues();
values.put("column1", "");
getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new String[]{"text","1"});

刪除(一條)數(shù)據(jù):

getContentResolver().delete(uri, "column2 = ?", new String[]{"1"});

(2)讀取系統(tǒng)聯(lián)系人

小示例:

public class MainActivity extends AppCompatActivity {
ArrayAdapter<String> adapter;

List<String> contactsList = new ArrayList<>();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ListView contactsView = (ListView) findViewById(R.id.contacts_view);
    adapter = new ArrayAdapter<String>(this, android.R.layout. simple_list_item_1, contactsList);
    contactsView.setAdapter(adapter);
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.READ_CONTACTS }, 1);
    } else {
        readContacts();
    }
}

private void readContacts() {
    Cursor cursor = null;
    try {
        // 查詢聯(lián)系人數(shù)據(jù)
        cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
        if (cursor != null) {
            while (cursor.moveToNext()) {
                // 獲取聯(lián)系人姓名
                String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                // 獲取聯(lián)系人手機(jī)號
                String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                contactsList.add(displayName + "\n" + number);
            }
            adapter.notifyDataSetChanged();
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case 1:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                readContacts();
            } else {
                Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
            }
            break;
        default:
    }
}
}

最后砾层,不要忘了在AndroidManifest中申明權(quán)限
<uses-permission android:name="android.permission.READ_CONTACTS" />

3、創(chuàng)建自己的內(nèi)容提供器

(1)創(chuàng)建內(nèi)容提供器的步驟

第一步贱案,新建一個類MyProvider繼承ContentProvider并實現(xiàn)6個抽象方法(onCreate肛炮、query、insert、update侨糟、delete和getType方法)


image.png

(2)實現(xiàn)跨程序數(shù)據(jù)共享

小示例:
提供數(shù)據(jù):

public class DatabaseProvider extends ContentProvider {
public static final int BOOK_DIR = 0;

public static final int BOOK_ITEM = 1;

public static final int CATEGORY_DIR = 2;

public static final int CATEGORY_ITEM = 3;

public static final String AUTHORITY = "com.example.databasetest.provider";

private static UriMatcher uriMatcher;

private MyDatabaseHelper dbHelper;

static {
    uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
    uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
    uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
    uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
}

@Override
public boolean onCreate() {
    dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2);
    return true;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    // 查詢數(shù)據(jù)
    SQLiteDatabase db = dbHelper.getReadableDatabase();
    Cursor cursor = null;
    switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
            break;
        case BOOK_ITEM:
            String bookId = uri.getPathSegments().get(1);
            cursor = db.query("Book", projection, "id = ?", new String[] { bookId }, null, null, sortOrder);
            break;
        case CATEGORY_DIR:
            cursor = db.query("Category", projection, selection, selectionArgs, null, null, sortOrder);
            break;
        case CATEGORY_ITEM:
            String categoryId = uri.getPathSegments().get(1);
            cursor = db.query("Category", projection, "id = ?", new String[] { categoryId }, null, null, sortOrder);
            break;
        default:
            break;
    }
    return cursor;
}

@Override
public Uri insert(Uri uri, ContentValues values) {
    // 添加數(shù)據(jù)
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    Uri uriReturn = null;
    switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
        case BOOK_ITEM:
            long newBookId = db.insert("Book", null, values);
            uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
            break;
        case CATEGORY_DIR:
        case CATEGORY_ITEM:
            long newCategoryId = db.insert("Category", null, values);
            uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);
            break;
        default:
            break;
    }
    return uriReturn;
}

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    // 更新數(shù)據(jù)
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    int updatedRows = 0;
    switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            updatedRows = db.update("Book", values, selection, selectionArgs);
            break;
        case BOOK_ITEM:
            String bookId = uri.getPathSegments().get(1);
            updatedRows = db.update("Book", values, "id = ?", new String[] { bookId });
            break;
        case CATEGORY_DIR:
            updatedRows = db.update("Category", values, selection, selectionArgs);
            break;
        case CATEGORY_ITEM:
            String categoryId = uri.getPathSegments().get(1);
            updatedRows = db.update("Category", values, "id = ?", new String[] { categoryId });
            break;
        default:
            break;
    }
    return updatedRows;
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    // 刪除數(shù)據(jù)
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    int deletedRows = 0;
    switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            deletedRows = db.delete("Book", selection, selectionArgs);
            break;
        case BOOK_ITEM:
            String bookId = uri.getPathSegments().get(1);
            deletedRows = db.delete("Book", "id = ?", new String[] { bookId });
            break;
        case CATEGORY_DIR:
            deletedRows = db.delete("Category", selection, selectionArgs);
            break;
        case CATEGORY_ITEM:
            String categoryId = uri.getPathSegments().get(1);
            deletedRows = db.delete("Category", "id = ?", new String[] { categoryId });
            break;
        default:
            break;
    }
    return deletedRows;
}

@Override
public String getType(Uri uri) {
    switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            return "vnd.android.cursor.dir/vnd.com.example.databasetest. provider.book";
        case BOOK_ITEM:
            return "vnd.android.cursor.item/vnd.com.example.databasetest. provider.book";
        case CATEGORY_DIR:
            return "vnd.android.cursor.dir/vnd.com.example.databasetest. provider.category";
        case CATEGORY_ITEM:
            return "vnd.android.cursor.item/vnd.com.example.databasetest. provider.category";
    }
    return null;
}
}

public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
    Button createDatabase = (Button) findViewById(R.id.create_database);
    createDatabase.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            dbHelper.getWritableDatabase();
        }
    });
    Button addData = (Button) findViewById(R.id.add_data);
    addData.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            ContentValues values = new ContentValues();
            // 開始組裝第一條數(shù)據(jù)
            values.put("name", "The Da Vinci Code");
            values.put("author", "Dan Brown");
            values.put("pages", 454);
            values.put("price", 16.96);
            db.insert("Book", null, values); // 插入第一條數(shù)據(jù)
            values.clear();
            // 開始組裝第二條數(shù)據(jù)
            values.put("name", "The Lost Symbol");
            values.put("author", "Dan Brown");
            values.put("pages", 510);
            values.put("price", 19.95);
            db.insert("Book", null, values); // 插入第二條數(shù)據(jù)
        }
    });
    Button updateData = (Button) findViewById(R.id.update_data);
    updateData.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            ContentValues values = new ContentValues();
            values.put("price", 10.99);
            db.update("Book", values, "name = ?", new String[] { "The Da Vinci Code" });
        }
    });
    Button deleteButton = (Button) findViewById(R.id.delete_data);
    deleteButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            db.delete("Book", "pages > ?", new String[] { "500" });
        }
    });
    Button queryButton = (Button) findViewById(R.id.query_data);
    queryButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            // 查詢Book表中所有的數(shù)據(jù)
            Cursor cursor = db.query("Book", null, null, null, null, null, null);
            if (cursor.moveToFirst()) {
                do {
                    // 遍歷Cursor對象碍扔,取出數(shù)據(jù)并打印
                    String name = cursor.getString(cursor.getColumnIndex("name"));
                    String author = cursor.getString(cursor.getColumnIndex("author"));
                    int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                    double price = cursor.getDouble(cursor.getColumnIndex("price"));
                    Log.d("MainActivity", "book name is " + name);
                    Log.d("MainActivity", "book author is " + author);
                    Log.d("MainActivity", "book pages is " + pages);
                    Log.d("MainActivity", "book price is " + price);
                } while (cursor.moveToNext());
            }
            cursor.close();
        }
    });
}
}

public class MyDatabaseHelper extends SQLiteOpenHelper {

public static final String CREATE_BOOK = "create table Book ("
        + "id integer primary key autoincrement, "
        + "author text, "
        + "price real, "
        + "pages integer, "
        + "name text)";

public static final String CREATE_CATEGORY = "create table Category ("
        + "id integer primary key autoincrement, "
        + "category_name text, "
        + "category_code integer)";

private Context mContext;

public MyDatabaseHelper(Context context, String name,
                        SQLiteDatabase.CursorFactory factory, int version) {
    super(context, name, factory, version);
    mContext = context;
}

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(CREATE_BOOK);
    db.execSQL(CREATE_CATEGORY);
   // Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("drop table if exists Book");
    db.execSQL("drop table if exists Category");
    onCreate(db);
}
}

注冊


image.png

第二個應(yīng)用操作數(shù)據(jù):

public class MainActivity extends AppCompatActivity {
private String newId;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button addData = (Button) findViewById(R.id.add_data);
    addData.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // 添加數(shù)據(jù)
            Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
            ContentValues values = new ContentValues();
            values.put("name", "A Clash of Kings");
            values.put("author", "George Martin");
            values.put("pages", 1040);
            values.put("price", 55.55);
            Uri newUri = getContentResolver().insert(uri, values);
            newId = newUri.getPathSegments().get(1);
        }
    });
    Button queryData = (Button) findViewById(R.id.query_data);
    queryData.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // 查詢數(shù)據(jù)
            Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
            Cursor cursor = getContentResolver().query(uri, null, null, null, null);
            if (cursor != null) {
                while (cursor.moveToNext()) {
                    String name = cursor.getString(cursor. getColumnIndex("name"));
                    String author = cursor.getString(cursor. getColumnIndex("author"));
                    int pages = cursor.getInt(cursor.getColumnIndex ("pages"));
                    double price = cursor.getDouble(cursor. getColumnIndex("price"));
                    Log.d("MainActivity", "book name is " + name);
                    Log.d("MainActivity", "book author is " + author);
                    Log.d("MainActivity", "book pages is " + pages);
                    Log.d("MainActivity", "book price is " + price);
                }
                cursor.close();
            }
        }
    });
    Button updateData = (Button) findViewById(R.id.update_data);
    updateData.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // 更新數(shù)據(jù)
            Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
            ContentValues values = new ContentValues();
            values.put("name", "A Storm of Swords");
            values.put("pages", 1216);
            values.put("price", 24.05);
            getContentResolver().update(uri, values, null, null);
        }
    });
    Button deleteData = (Button) findViewById(R.id.delete_data);
    deleteData.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // 刪除數(shù)據(jù)
            Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
            getContentResolver().delete(uri, null, null);
        }
    });
}
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市秕重,隨后出現(xiàn)的幾起案子不同,更是在濱河造成了極大的恐慌,老刑警劉巖溶耘,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件二拐,死亡現(xiàn)場離奇詭異,居然都是意外死亡汰具,警方通過查閱死者的電腦和手機(jī)卓鹿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門菱魔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來留荔,“玉大人,你說我怎么就攤上這事澜倦【鄣” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵藻治,是天一觀的道長碘勉。 經(jīng)常有香客問我,道長桩卵,這世上最難降的妖魔是什么验靡? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮雏节,結(jié)果婚禮上胜嗓,老公的妹妹穿的比我還像新娘。我一直安慰自己钩乍,他們只是感情好辞州,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著寥粹,像睡著了一般变过。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上涝涤,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天媚狰,我揣著相機(jī)與錄音,去河邊找鬼阔拳。 笑死崭孤,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播裳瘪,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼土浸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了彭羹?” 一聲冷哼從身側(cè)響起黄伊,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎派殷,沒想到半個月后还最,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡毡惜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年拓轻,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片经伙。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡扶叉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出帕膜,到底是詐尸還是另有隱情枣氧,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布垮刹,位于F島的核電站达吞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏荒典。R本人自食惡果不足惜酪劫,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望寺董。 院中可真熱鬧覆糟,春花似錦、人聲如沸螃征。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盯滚。三九已至踢械,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間魄藕,已是汗流浹背内列。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留背率,地道東北人话瞧。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓嫩与,卻偏偏與公主長得像,于是被迫代替她去往敵國和親交排。 傳聞我的和親對象是個殘疾皇子划滋,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容