目錄html
第39章偏好
Android帶有一個SharedPreferences接口,它能夠用來管理鍵/值對這樣的應用程序設置。SharedPreferences還負責向一個文件寫入數據。此外,Android還提供了Preference API,它帶有鏈接到默認的SharedPreferences實例的用戶接口類,以即可以很容易地建立一個UI來修改應用程序設置。
39.1SharedPreference
1.android.content.SharedPreferences接口提供了用於排序和讀取應用程序設置的方法。
2.getXXX方法返回了和指定的鍵相關聯的值(若是鍵值對存在的話)。
3.可使用contains方法檢查一個SharePreferences是否包含一個鍵值對。
4.可使用getAll方法將全部的鍵值對獲取爲一個Map。
5.一個SharedPreferences中存儲的值會自動持久化,而且將會在用戶會話中存在。
39.2Preference API
1.要在一個SharedPreferences中存儲一個鍵值對,一般使用Android Preference API來建立一個用戶界面,使得用戶可以編輯設置。
2.如今的Android版本中,一般使用PreferenceFragment來代替偏好xml文件。
39.3 使用Preference
1.代碼清單39.1 AndroidManifest.xml文件java
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.preferencedemo1" > <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.example.preferencedemo1.SettingsActivity" android:parentActivityName=".MainActivity" android:label=""> </activity> </application> </manifest>
2.代碼清單39.2 第一個活動的佈局文件(activity_main.xml)android
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <TextView android:id="@+id/info" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="30sp"/> </RelativeLayout>
3.代碼清單39.3 MainActivity類git
package com.example.preferencedemo1; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onResume() { super.onResume(); SharedPreferences sharedPref = PreferenceManager. getDefaultSharedPreferences(this); boolean allowMultipleUsers = sharedPref.getBoolean( SettingsActivity.ALLOW_MULTIPLE_USERS, false); String envId = sharedPref.getString( SettingsActivity.ENVIRONMENT_ID, ""); String account = sharedPref.getString( SettingsActivity.ACCOUNT, ""); TextView textView = (TextView) findViewById(R.id.info); textView.setText("Allow multiple users: " + allowMultipleUsers + "\nEnvironment Id: " + envId + "\nAccount: " + account); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_settings: startActivity(new Intent(this, SettingsActivity.class)); return true; default: return super.onOptionsItemSelected(item); } } }
4.代碼清單39.4 SettingsActivity類sql
package com.example.preferencedemo1; import android.app.Activity; import android.os.Bundle; import android.view.Menu; public class SettingsActivity extends Activity { public static final String ALLOW_MULTIPLE_USERS = "allowMultipleUsers"; public static final String ENVIRONMENT_ID = "envId"; public static final String ACCOUNT = "account"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getActionBar().setDisplayHomeAsUpEnabled(true); getFragmentManager() .beginTransaction() .replace(android.R.id.content, new SettingsFragment()).commit(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_settings, menu); return true; } }
5.代碼清單39.5 SettingsFragment類數據庫
package com.example.preferencedemo1; import android.os.Bundle; import android.preference.PreferenceFragment; public class SettingsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the preferences from an XML resource addPreferencesFromResource(R.xml.preferences); } }
6.代碼清單39.6 res/xml/preferences.xml文件api
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:title="Category 1"> <CheckBoxPreference android:key="allowMultipleUsers" android:title="Allow multiple users" android:summary="Allow multiple users" /> </PreferenceCategory> <PreferenceCategory android:title="Category 2"> <EditTextPreference android:key="envId" android:title="Environment Id" android:dialogTitle="Environment Id"/> <EditTextPreference android:key="account" android:title="Account"/> </PreferenceCategory> </PreferenceScreen>
第40章操做空間
40.1 概覽
Android設備提供了兩種存儲區域,內部的和外部的。
內部存儲對於應用程序來講是私有的,用戶和其餘的應用程序不能訪問它。
外部存儲中所存儲的文件將會和其餘的應用程序分享,其餘用戶也可以訪問外部存儲。
40.1.1內部存儲
1.Context類提供了各類方法,android-studio
一般使用這些方法來訪問在內部存儲中存儲的文件,並且不該該將內部存儲的位置直接編寫到代碼中。 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.filedemo1" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" /> <android:uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" /> <android:uses-permission android:name="android.permission.READ_PHONE_STATE" /> <android:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.filedemo1.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.example.filedemo1.AddNoteActivity" android:label="@string/title_activity_add_note" > </activity> </application> </manifest>
2.MainActivity類服務器
package com.example.filedemo1; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends Activity { private String selectedItem; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = (ListView) findViewById( R.id.listView1); listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); listView.setOnItemClickListener( new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { readNote(position); } }); } @Override public void onResume() { super.onResume(); refreshList(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle presses on the action bar items switch (item.getItemId()) { case R.id.action_add: startActivity(new Intent(this, AddNoteActivity.class)); return true; case R.id.action_delete: deleteNote(); return true; default: return super.onOptionsItemSelected(item); } } private void refreshList() { ListView listView = (ListView) findViewById( R.id.listView1); String[] titles = fileList(); ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>( this, android.R.layout.simple_list_item_activated_1, titles); listView.setAdapter(arrayAdapter); } private void readNote(int position) { String[] titles = fileList(); if (titles.length > position) { selectedItem = titles[position]; File dir = getFilesDir(); File file = new File(dir, selectedItem); FileReader fileReader = null; BufferedReader bufferedReader = null; try { fileReader = new FileReader(file); bufferedReader = new BufferedReader(fileReader); StringBuilder sb = new StringBuilder(); String line = bufferedReader.readLine(); while (line != null) { sb.append(line); line = bufferedReader.readLine(); } ((TextView) findViewById(R.id.textView1)). setText(sb.toString()); } catch (IOException e) { } finally { if (bufferedReader != null) { try { bufferedReader.close(); } catch (IOException e) { } } if (fileReader != null) { try { fileReader.close(); } catch (IOException e) { } } } } } private void deleteNote() { if (selectedItem != null) { deleteFile(selectedItem); selectedItem = null; ((TextView) findViewById(R.id.textView1)).setText(""); refreshList(); } } }
3.代碼清單40.3 AddNoteActivity類app
package com.example.filedemo1; import java.io.File; import java.io.PrintWriter; import android.app.Activity; import android.app.AlertDialog; import android.os.Bundle; import android.view.View; import android.widget.EditText; public class AddNoteActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_note); } public void cancel(View view) { finish(); } public void addNote(View view) { String fileName = ((EditText) findViewById(R.id.noteTitle)) .getText().toString(); String body = ((EditText) findViewById(R.id.noteBody)) .getText().toString(); File parent = getFilesDir(); File file = new File(parent, fileName); PrintWriter writer = null; try { writer = new PrintWriter(file); writer.write(body); finish(); } catch (Exception e) { showAlertDialog("Error adding note", e.getMessage()); } finally { if (writer != null) { try { writer.close(); } catch (Exception e) { } } } } private void showAlertDialog(String title, String message) { AlertDialog alertDialog = new AlertDialog.Builder(this).create(); alertDialog.setTitle(title); alertDialog.setMessage(message); alertDialog.show(); } }
40.3訪問公共存儲
1.代碼清單40.4 FileDemo2的活動的佈局文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.filedemo2" > <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.filedemo2.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
2.代碼清單40.5 MainActivity類
package com.example.filedemo2; import java.io.File; import java.util.Arrays; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.view.Menu; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.ListView; public class MainActivity extends Activity { class KeyValue { public String key; public String value; public KeyValue(String key, String value) { this.key = key; this.value = value; } @Override public String toString() { return key; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final List<KeyValue> keyValues = Arrays.asList( new KeyValue("Alarms", Environment.DIRECTORY_ALARMS), new KeyValue("DCIM", Environment.DIRECTORY_DCIM), new KeyValue("Downloads", Environment.DIRECTORY_DOWNLOADS), new KeyValue("Movies", Environment.DIRECTORY_MOVIES), new KeyValue("Music", Environment.DIRECTORY_MUSIC), new KeyValue("Notifications", Environment.DIRECTORY_NOTIFICATIONS), new KeyValue("Pictures", Environment.DIRECTORY_PICTURES), new KeyValue("Podcasts", Environment.DIRECTORY_PODCASTS), new KeyValue("Ringtones", Environment.DIRECTORY_RINGTONES) ); ArrayAdapter<KeyValue> arrayAdapter = new ArrayAdapter<KeyValue>(this, android.R.layout.simple_list_item_activated_1, keyValues); ListView listView1 = (ListView) findViewById(R.id.listView1); listView1.setChoiceMode(ListView.CHOICE_MODE_SINGLE); listView1.setAdapter(arrayAdapter); listView1.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { KeyValue keyValue = keyValues.get(position); listDir(keyValue.value); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } private void listDir(String dir) { File parent = Environment .getExternalStoragePublicDirectory(dir); String[] files = null; if (parent == null || parent.list() == null) { files = new String[0]; } else { files = parent.list(); } ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_activated_1, files); ListView listView2 = (ListView) findViewById(R.id.listView2); listView2.setAdapter(arrayAdapter); } }
第41章操做數據庫
Android擁有本身的技術來操做數據庫,它和Java數據庫鏈接(Java Database Connectivity,JDBC)無關,JDBC是Java開發者用來訪問關係數據庫中的數據的一種技術。Android帶有SQLite,這是一個開源的數據庫。
41.1 概覽
1.Android帶有本身的Database API。
2.SQLite中的一項功能是,當插入一行的時候,有一個整數的主鍵自動增長,不須要爲該字段傳入一個值。
41.2 Database API
41.2.1 SQLiteOpenHelper類
1.提供一個構造方法,它調用本身的超類,傳入Context和數據庫名稱以及其餘內容。
2.覆蓋onCreate方法和onUpgrade方法。
3.SQLiteOpenHelper自動管理到底層數據庫的鏈接。
41.2.2 SQLiteDatabase類
1.調用insert或execSQL方法來操做數據庫中的數據。
2.要獲取記錄,使用query方法之一。
41.2.3 Cursor接口
1.在SQLiteDatabase上調用query方法將返回一個Cursor。
41.3 示例
1.代碼清單41.1 AndroidManifest.xml文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.databasedemo1" android:versionCode="1" android:versionName="1.0" > <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".AddContactActivity" android:parentActivityName=".MainActivity" android:label="@string/title_activity_add_contact"> </activity> <activity android:name=".ShowContactActivity" android:parentActivityName=".MainActivity" android:label="@string/title_activity_show_contact" > </activity> </application> </manifest>
2.代碼清單41.2 Contact類
package com.example.databasedemo1; public class Contact { private long id; private String firstName; private String lastName; private String phone; private String email; public Contact() { } public Contact(String firstName, String lastName, String phone, String email) { this.firstName = firstName; this.lastName = lastName; this.phone = phone; this.email = email; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
3.代碼清單41.3 DatabaseManager類
package com.example.databasedemo1; import java.util.ArrayList; import java.util.List; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; public class DatabaseManager extends SQLiteOpenHelper { public static final String TABLE_NAME = "contacts"; public static final String ID_FIELD = "_id"; public static final String FIRST_NAME_FIELD = "first_name"; public static final String LAST_NAME_FIELD = "last_name"; public static final String PHONE_FIELD = "phone"; public static final String EMAIL_FIELD = "email"; public DatabaseManager(Context context) { super(context, /*db name=*/ "contacts_db2", /*cursorFactory=*/ null, /*db version=*/1); } @Override public void onCreate(SQLiteDatabase db) { Log.d("db", "onCreate"); String sql = "CREATE TABLE " + TABLE_NAME + " (" + ID_FIELD + " INTEGER, " + FIRST_NAME_FIELD + " TEXT," + LAST_NAME_FIELD + " TEXT," + PHONE_FIELD + " TEXT," + EMAIL_FIELD + " TEXT," + " PRIMARY KEY (" + ID_FIELD + "));"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) { Log.d("db", "onUpdate"); db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); // re-create the table onCreate(db); } public Contact addContact(Contact contact) { Log.d("db", "addContact"); SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(FIRST_NAME_FIELD, contact.getFirstName()); values.put(LAST_NAME_FIELD, contact.getLastName()); values.put(PHONE_FIELD, contact.getPhone()); values.put(EMAIL_FIELD, contact.getEmail()); long id = db.insert(TABLE_NAME, null, values); contact.setId(id); db.close(); return contact; } // Getting single contact Contact getContact(long id) { SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.query(TABLE_NAME, new String[] { ID_FIELD, FIRST_NAME_FIELD, LAST_NAME_FIELD, PHONE_FIELD, EMAIL_FIELD }, ID_FIELD + "=?", new String[] { String.valueOf(id) }, null, null, null, null); if (cursor != null) { cursor.moveToFirst(); Contact contact = new Contact( cursor.getString(1), cursor.getString(2), cursor.getString(3), cursor.getString(4)); contact.setId(cursor.getLong(0)); return contact; } return null; } // Getting All Contacts public List<Contact> getAllContacts() { List<Contact> contacts = new ArrayList<Contact>(); String selectQuery = "SELECT * FROM " + TABLE_NAME; SQLiteDatabase db = this.getWritableDatabase(); Cursor cursor = db.rawQuery(selectQuery, null); while (cursor.moveToNext()) { Contact contact = new Contact(); contact.setId(Integer.parseInt(cursor.getString(0))); contact.setFirstName(cursor.getString(1)); contact.setLastName(cursor.getString(2)); contact.setPhone(cursor.getString(3)); contact.setEmail(cursor.getString(4)); contacts.add(contact); } return contacts; } public Cursor getContactsCursor() { String selectQuery = "SELECT * FROM " + TABLE_NAME; SQLiteDatabase db = this.getWritableDatabase(); return db.rawQuery(selectQuery, null); } public int updateContact(Contact contact) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(FIRST_NAME_FIELD, contact.getFirstName()); values.put(LAST_NAME_FIELD, contact.getLastName()); values.put(PHONE_FIELD, contact.getPhone()); values.put(EMAIL_FIELD, contact.getEmail()); return db.update(TABLE_NAME, values, ID_FIELD + " = ?", new String[] { String.valueOf(contact.getId()) }); } public void deleteContact(long id) { SQLiteDatabase db = this.getWritableDatabase(); db.delete(TABLE_NAME, ID_FIELD + " = ?", new String[] { String.valueOf(id) }); db.close(); } }
4.代碼清單41.4 MainActivity類
package com.example.databasedemo1; import android.app.Activity; import android.content.Intent; import android.database.Cursor; import android.os.Bundle; import android.widget.CursorAdapter; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.SimpleCursorAdapter; public class MainActivity extends Activity { DatabaseManager dbMgr; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = (ListView) findViewById( R.id.listView); dbMgr = new DatabaseManager(this); Cursor cursor = dbMgr.getContactsCursor(); startManagingCursor(cursor); ListAdapter adapter = new SimpleCursorAdapter( this, android.R.layout.two_line_list_item, cursor, new String[] {DatabaseManager.FIRST_NAME_FIELD, DatabaseManager.LAST_NAME_FIELD}, new int[] {android.R.id.text1, android.R.id.text2}, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); listView.setAdapter(adapter); listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); listView.setOnItemClickListener( new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { Intent intent = new Intent( getApplicationContext(), ShowContactActivity.class); intent.putExtra("id", id); startActivity(intent); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_add: startActivity(new Intent(this, AddContactActivity.class)); return true; default: return super.onOptionsItemSelected(item); } } }
5.代碼清單41.5 AddContactActivity類
package com.example.databasedemo1; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.widget.TextView; public class AddContactActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_contact); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.add_contact, menu); return true; } public void cancel(View view) { finish(); } public void addContact(View view) { DatabaseManager dbMgr = new DatabaseManager(this); String firstName = ((TextView) findViewById( R.id.firstName)).getText().toString(); String lastName = ((TextView) findViewById( R.id.lastName)).getText().toString(); String phone = ((TextView) findViewById( R.id.phone)).getText().toString(); String email = ((TextView) findViewById( R.id.email)).getText().toString(); Contact contact = new Contact(firstName, lastName, phone, email); dbMgr.addContact(contact); finish(); } }
6.代碼清單41.6 ShowContactActivity類
package com.example.databasedemo1; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; public class ShowContactActivity extends Activity { long contactId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_show_contact); getActionBar().setDisplayHomeAsUpEnabled(true); Bundle extras = getIntent().getExtras(); if (extras != null) { contactId = extras.getLong("id"); DatabaseManager dbMgr = new DatabaseManager(this); Contact contact = dbMgr.getContact(contactId); if (contact != null) { ((TextView) findViewById(R.id.firstName)) .setText(contact.getFirstName()); ((TextView) findViewById(R.id.lastName)) .setText(contact.getLastName()); ((TextView) findViewById(R.id.phone)) .setText(contact.getPhone()); ((TextView) findViewById(R.id.email)) .setText(contact.getEmail()); } else { Log.d("db", "contact null"); } } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.show_contact, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_delete: deleteContact(); return true; default: return super.onOptionsItemSelected(item); } } private void deleteContact() { new AlertDialog.Builder(this) .setTitle("Please confirm") .setMessage( "Are you sure you want to delete " + "this contact?") .setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialog, int whichButton) { DatabaseManager dbMgr = new DatabaseManager( getApplicationContext()); dbMgr.deleteContact(contactId); dialog.dismiss(); finish(); } }) .setNegativeButton("No", new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialog, int which) { dialog.dismiss(); } }) .create() .show(); } }
第42章獲取圖片
Android爲獲取靜態圖像的應用程序提供了兩個選項,使用一個內建的意圖來啓動Camera或者使用Camera API。第一個選項很容易使用,可是缺少Camera API所提供的功能。
42.1 概覽
1.要告訴Camera把獲取的圖片存儲在哪裏,能夠給Intent傳入一個Uri實例。
2.系統經過傳入3個參數來調用onActivityResult方法。第一個參數是requestCode,是調用startActivityForResult方法的時候傳入的請求代碼。第二個參數是結果代碼。第三個參數包含了來自被調用的活動的數據。
42.2 使用相機
CameraDemo應用程序展現瞭如何使用內建的意圖來激活Camera應用程序來使用它來拍照。
1.代碼清單42.1 清單
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.camerademo" > <uses-feature android:name="android.hardware.camera"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.camerademo.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
2.代碼清單42.2 菜單文件(menu_main.xml)
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/action_camera" android:orderInCategory="100" android:showAsAction="ifRoom" android:title="@string/action_show_camera"/> <item android:id="@+id/action_email" android:orderInCategory="200" android:showAsAction="ifRoom" android:title="@string/action_email"/> </menu>
3.代碼清單42.3 activity_main.xml文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
4.代碼清單42.4 MainActivity類
package com.example.camerademo; import java.io.File; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.ImageView; import android.widget.Toast; public class MainActivity extends Activity { private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100; File pictureDir = new File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), "CameraDemo"); private static final String FILE_NAME = "image01.jpg"; private Uri fileUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (!pictureDir.exists()) { pictureDir.mkdirs(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_camera: showCamera(); return true; case R.id.action_email: emailPicture(); return true; default: return super.onContextItemSelected(item); } } private void showCamera() { Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE); File image = new File(pictureDir, FILE_NAME); fileUri = Uri.fromFile(image); intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // check if the device has a camera: if (intent.resolveActivity(getPackageManager()) != null) { startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) { if (resultCode == RESULT_OK) { ImageView imageView = (ImageView) findViewById(R.id.imageView); File image = new File(pictureDir, FILE_NAME); fileUri = Uri.fromFile(image); imageView.setImageURI(fileUri); } else if (resultCode == RESULT_CANCELED) { Toast.makeText(this, "Action cancelled", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "Error", Toast.LENGTH_LONG).show(); } } } private void emailPicture() { Intent emailIntent = new Intent( android.content.Intent.ACTION_SEND); emailIntent.setType("application/image"); emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{"me@example.com"}); emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "New photo"); emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "From My App"); emailIntent.putExtra(Intent.EXTRA_STREAM, fileUri); startActivity(Intent.createChooser(emailIntent, "Send mail...")); } }
42.3 Camera API
42.3.1 管理相機
使用takePicture方法能夠肯定從相機獲得的最終的原始圖像和JPEG圖像作些什麼。takePicture方法的四個參數介紹以下:
1.shutter。圖像捕獲瞬間的回調。
2.raw。解壓縮圖像數據的回調。
3.postview。預覽圖像數據的回調。
4.jpeg。JPEG圖像數據的回調。
42.4 使用Camera API
1.代碼清單42.5 佈局文件(activity_main.xml)
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.cameraapidemo" > <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.cameraapidemo.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
2.代碼清單42.6 MainActivity類
package com.example.cameraapidemo; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.app.Activity; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.ShutterCallback; import android.media.AudioManager; import android.media.SoundPool; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.provider.Settings; import android.util.Log; import android.view.Menu; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity implements SurfaceHolder.Callback { private Camera camera; SoundPool soundPool; int beepId; File pictureDir = new File(Environment .getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), "CameraAPIDemo"); private static final String TAG = "camera"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); pictureDir.mkdirs(); soundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0); Uri uri = Settings.System.DEFAULT_RINGTONE_URI; beepId = soundPool.load(uri.getPath(), 1); SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceview); surfaceView.getHolder().addCallback(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public void onResume() { super.onResume(); try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { camera = Camera.open(0); } else { camera = Camera.open(); } } catch (Exception e) { e.printStackTrace(); } } @Override public void onPause() { super.onPause(); if (camera != null) { try { camera.release(); camera = null; } catch (Exception e) { e.printStackTrace(); } } } private void enableButton(boolean enabled) { Button button = (Button) findViewById(R.id.button1); button.setEnabled(enabled); } public void takePicture(View view) { enableButton(false); camera.takePicture(shutterCallback, null, pictureCallback); } private ShutterCallback shutterCallback = new ShutterCallback() { @Override public void onShutter() { // play sound soundPool.play(beepId, 1.0f, 1.0f, 0, 0, 1.0f); } }; private PictureCallback pictureCallback = new PictureCallback() { @Override public void onPictureTaken(byte[] data, final Camera camera) { Toast.makeText(MainActivity.this, "Saving image", Toast.LENGTH_LONG) .show(); File pictureFile = new File(pictureDir, System.currentTimeMillis() + ".jpg"); try { FileOutputStream fos = new FileOutputStream( pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { Log.d(TAG, e.getMessage()); } catch (IOException e) { Log.d(TAG, e.getMessage()); } Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { try { enableButton(true); camera.startPreview(); } catch (Exception e) { Log.d("camera", "Error starting camera preview: " + e.getMessage()); } } }, 2000); } }; @Override public void surfaceCreated(SurfaceHolder holder) { try { camera.setPreviewDisplay(holder); camera.startPreview(); } catch (Exception e){ Log.d("camera", e.getMessage()); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int w, int h3) { if (holder.getSurface() == null){ Log.d(TAG, "surface does not exist, return"); return; } try { camera.setPreviewDisplay(holder); camera.startPreview(); } catch (Exception e){ Log.d("camera", e.getMessage()); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.d(TAG, "surfaceDestroyed"); } }
1.字符串「dxxxdxxd」,表達式 (d)(\w+)(d)對應的應該是dxxxdxxd,而不是xxxdxx。
錯誤緣由:\w+將匹配第一個d和最後一個d之間的全部字符,(d)是兩端的d,不能缺。
https://gitee.com/EvelynYang/tenth_weeks
在新建的AndroidProjects文件夾中運行腳本,第六週及以前都是在IdeaProjects文件夾裏運行。
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 200/200 | 2/2 | 20/20 | |
第二週 | 300/500 | 1/3 | 18/38 | |
第三週 | 500/1000 | 1/4 | 38/76 | |
第四周 | 1000/2000 | 1/5 | 20/96 | |
第五週 | 1000/3000 | 1/6 | 25/121 | |
第六週 | 1000/4000 | 1/7 | 25/146 | |
第七週 | 1000/5000 | 1/8 | 25/171 | |
第八週 | 1000/6000 | 1/9 | 15/186 | |
第九周 | 1000/7000 | 1/10 | 20/206 | |
第十週 | 1000/8000 | 1/11 | 20/226 |