一、Android的狀態欄通知(Notification)javascript
通知用於在狀態欄顯示消息,消息到來時以圖標方式表示,以下:php
//獲取通知管理器css
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);html
int icon = android.R.drawable.stat_notify_chat;java
long when = System.currentTimeMillis();android
//新建一個通知,指定其圖標和標題c++
Notification notification = new Notification(icon, null, when);//第一個參數爲圖標,第二個參數爲短暫提示標題,第三個爲通知時間程序員
notification.defaults = Notification.DEFAULT_SOUND;//發出默認聲音web
Intent openintent = new Intent(this, OtherActivity.class);算法
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, openintent, 0);//當點擊消息時就會向系統發送openintent意圖
notification.setLatestEventInfo(this, 「標題」, 「我是內容", contentIntent);
mNotificationManager.notify(0, notification);//第一個參數爲自定義的通知惟一標識
二、對話框通知(Dialog Notification)
當你的應用須要顯示一個進度條或須要用戶對信息進行確認時,可使用對話框來完成。
下面代碼將打開一個如右圖所示的對話框:
new AlertDialog.Builder(context)
.setTitle("java培訓")
.setCancelable(false) //設置不能經過「後退」按鈕關閉對話框
.setMessage("瀏覽傳智播客網站?")
.setPositiveButton("確認",
new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialoginterface, int i){
Uri uri = Uri.parse("http://www.itcast.cn/");//打開連接
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
})
.show();//顯示對話框
上面代碼採用的是一個鏈式調用,像setTitle()、setMessage()這些方法,他們的返回值都是當前對話框對象。
三、建立帶單選項列表的對話框
下面代碼將打開一個如右上圖所示的選項列表對話框:
final String[] items = {"java", ".net", "php"};
new AlertDialog.Builder(SenderNotificationActivity.this).setTitle("選擇語言")
.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
Toast.makeText(getApplicationContext(), items[item],
Toast.LENGTH_SHORT).show();
}
}).show();//顯示對話框
下面代碼將打開一個如右下圖所示的帶單選框的列表對話框:
final String[] items = {"java", ".net", "php"};
new AlertDialog.Builder(SenderNotificationActivity.this).setTitle("選擇語言")
.setSingleChoiceItems(items, 1, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
Toast.makeText(getApplicationContext(), items[item],
Toast.LENGTH_SHORT).show();
dialog.cancel();
}
}).show();//顯示對話框
setSingleChoiceItems()的第二個參數是設置默認選項,
選項索引從0開始,-1表明不選擇任何選項。
四、建立帶多選項列表的對話框
下面代碼將打開一個如右下圖所示的多選項列表對話框:
final String[] items = {"java", ".net", "php"};
new AlertDialog.Builder(SenderNotificationActivity.this).setCancelable(false)
.setTitle("選擇語言")
.setMultiChoiceItems(items, new boolean[]{false,true,false}, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
if(isChecked){
Toast.makeText(getApplicationContext(), items[which],
Toast.LENGTH_SHORT).show();
}
}
})
.setPositiveButton("確認",
new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialoginterface, int i){
dialoginterface.dismiss();
}
})
.show();//顯示對話框
5、進度對話框(ProgressDialog)
使用代碼ProgressDialog.show(ProgressDialogActivity.this, "請稍等", "數據正在加載中...", true);建立並顯示一個進度對話框。
調用setProgressStyle()方法設置進度對話框風格。有兩種風格:
ProgressDialog.STYLE_SPINNER 旋體進度條風格 (爲默認風格)
ProgressDialog.STYLE_HORIZONTAL 橫向進度條風格
public class ProgressDialogActivity extends Activity {
private ProgressDialog progressDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menu);
//開始一條專門處理耗時工做的線程
new Thread(new Runnable(){
@Override
public void run() {
try {
Thread.sleep(5*1000);//假設這項工做須要5秒才能完成
progressDialog.dismiss();//關閉進程對話框
//runOnUiThread(finishDialog);//要求運行在UI線程
} catch (InterruptedException e) {}
}
}).start();
progressDialog = ProgressDialog.show(ProgressDialogActivity.this, "請稍等", "數據正在加載中...", true);
}
private Runnable finishDialog = new Runnable() {
@Override
public void run() {
progressDialog.dismiss();
}
};
}
六、單選框(RadioButton)
要完成單選框顯示,咱們須要使用到RadioGroup和RadioButton(單選框),RadioGroup用於對單選框進行分組,相同組內的單選框只有一個單選框能被選中。(例子代碼請見下方備註欄)
RadioGroup.check(R.id.dotNet);將id名爲dotNet的單選框設置成選中狀態。
(RadioButton) findViewById(radioGroup.getCheckedRadioButtonId());//獲取被選中的單選框。
RadioButton.getText();//獲取單選框的值
調用setOnCheckedChangeListener()方法,處理單選框被選擇事件,把RadioGroup.OnCheckedChangeListener實例做爲參數傳入
界面設計:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<RadioGroup android:id="@+id/radioGroup"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RadioButton android:id="@+id/java"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="java" />
<RadioButton android:id="@+id/dotNet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="dotNet" />
<RadioButton android:id="@+id/php"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PHP" />
</RadioGroup>
</LinearLayout>
處理程序:
public void onCreate(Bundle savedInstanceState) {
......
RadioGroup radioGroup = (RadioGroup) findViewById(R.id.radioGroup);
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
public void onCheckedChanged(RadioGroup group, int checkedId) {
RadioButton radioButton = (RadioButton) findViewById(checkedId);
Log.i(TAG, String.valueOf(radioButton.getText()));
}
});
}
七、多選框(CheckBox)
每一個多選框都是獨立的,能夠經過迭代全部多選框,而後根據其狀態是否被選中再獲取其值。
CheckBox.setChecked(true);//設置成選中狀態。
CheckBox.getText();//獲取多選框的值
調用setOnCheckedChangeListener()方法,處理多選框被選擇事件,把CompoundButton.OnCheckedChangeListener實例做爲參數傳入
界面設計:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="fill_parent">
<CheckBox android:id="@+id/checkboxjava"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="java" />
<CheckBox android:id="@+id/checkboxdotNet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="dotNet" />
<CheckBox android:id="@+id/checkboxphp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PHP" />
<Button android:id="@+id/checkboxButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="獲取值" />
</LinearLayout>
代碼處理:
public class CheckBoxActivity extends Activity {
private static final String TAG = "CheckBoxActivity";
private List<CheckBox> checkboxs = new ArrayList<CheckBox>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.checkbox);
checkboxs.add((CheckBox) findViewById(R.id.checkboxdotNet));
checkboxs.add((CheckBox) findViewById(R.id.checkboxjava));
checkboxs.add((CheckBox) findViewById(R.id.checkboxphp));
checkboxs.get(1).setChecked(true);//設置成選中狀態
for(CheckBox box : checkboxs){
box.setOnCheckedChangeListener(listener);
}
Button button = (Button)findViewById(R.id.checkboxButton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<String> values = new ArrayList<String>();
for(CheckBox box : checkboxs){
if(box.isChecked()){
values.add(box.getText().toString());
}
}
Toast.makeText(CheckBoxActivity.this, values.toString(), 1).show();
}
});
}
CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() {@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
CheckBox checkBox = (CheckBox) buttonView;
Log.i(TAG, "isChecked="+ isChecked +",value="+ checkBox.getText());//輸出單選框的值
}
};
}
八、下拉列表框(Spinner)
Spinner.getItemAtPosition(Spinner.getSelectedItemPosition());獲取下拉列表框的值
調用setOnItemSelectedListener()方法,處理下拉列表框被選擇事件,把AdapterView.OnItemSelectedListener實例做爲參數傳入
界面設計:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Spinner android:id="@+id/spinner"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
</LinearLayout>
代碼處理:
public class SpinnerActivity extends Activity {
private static final String TAG = "SpinnerActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spinner);
//第二個參數爲下拉列表框每一項的界面樣式,該界面樣式由Android系統提供,固然您也能夠自定義
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
adapter.add("java");
adapter.add("dotNet");
adapter.add("php");
Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
Spinner spinner = (Spinner)adapterView;
String itemContent = (String)adapterView.getItemAtPosition(position);
}
@Override
public void onNothingSelected(AdapterView<?> view) {
Log.i(TAG, view.getClass().getName());
}
});
}
}
9、下拉列表框—採用javabean做爲Adapter元素
不少時候顯示在下拉列表框的值並非但願獲得的值,若是要作一個聯繫人下拉列表框,列表框列出的是聯繫人的姓名,由於姓名有可能相同,因此咱們但願獲得的值應該爲該聯繫人的id,要實現這種需求咱們須要自定義Adapter,固然自定義Adapter須要咱們編寫一小段代碼,若是咱們不想編寫Adapter,又能實現咱們的需求,那是最好不過的了。經過觀察ArrayAdapter中getView(int position, View convertView, ViewGroup parent)的內部代碼發現,若是爲ArrayAdapter指定的實際泛型參數類型沒有實現CharSequence(字符串)接口,將會調用該類型對象的toString()向下拉列表框輸出顯示值。利用這個特色咱們能夠重寫javaBean的toString()向下拉列表框提供顯示值。
界面設計:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Spinner android:id="@+id/spinner"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
</LinearLayout>
代碼處理:
public class SpinnerActivity extends Activity {
private static final String TAG = "SpinnerActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spinner);
ArrayAdapter<Person> adapter = new ArrayAdapter<Person>(this, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
adapter.add(new Person(12, "李明"));
adapter.add(new Person(100, "李明"));
adapter.add(new Person(62, "張天"));
Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
Spinner spinner = (Spinner)adapterView;
Person person = (Person)adapterView.getItemAtPosition(position);
}
@Override
public void onNothingSelected(AdapterView<?> view) {
Log.i(TAG, view.getClass().getName());
}
});
}
}
Person.java:
public class Person {
private Integer id;
private String name;
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
十、下拉列表框--自定義選項界面樣式
Spinner.getItemAtPosition(Spinner.getSelectedItemPosition());獲取下拉列表框的值
調用setOnItemSelectedListener()方法,處理下拉列表框被選擇事件,把AdapterView.OnItemSelectedListener實例做爲參數傳入
主界面設計:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Spinner android:id="@+id/spinner"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
</LinearLayout>
下拉列表框每一項的界面樣式:stylespinner.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contentTextView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#F4FDFF"
/>
代碼處理:
public class SpinnerActivity extends Activity {
private static final String TAG = "SpinnerActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spinner);
//第二個參數爲layout文件在R文件的id,第三個參數爲TextView在layout文件的id
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.stylespinner, R.id.contentTextView);
adapter.add("java");
adapter.add("dotNet");
adapter.add("php");
Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
Spinner spinner = (Spinner)adapterView;
String itemContent = (String)adapterView.getItemAtPosition(position);
}
@Override
public void onNothingSelected(AdapterView<?> view) {
Log.i(TAG, view.getClass().getName());
}
});
}
}
十一、拖動條(SeekBar)
SeekBar.getProgress()獲取拖動條當前值
調用setOnSeekBarChangeListener()方法,處理拖動條值變化事件,把SeekBar.OnSeekBarChangeListener實例做爲參數傳入
主界面設計:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<SeekBar
android:id="@+id/seekBar"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
<Button android:id="@+id/seekBarButton"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="獲取值"
/>
</LinearLayout>
代碼處理:
public class SeekBarActivity extends Activity {
private SeekBar seekBar;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.seekbar);
seekBar = (SeekBar) findViewById(R.id.seekBar);
seekBar.setMax(100);//設置最大刻度
seekBar.setProgress(30);//設置當前刻度
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
Log.v("onProgressChanged()", String.valueOf(progress) + ", " + String.valueOf(fromTouch));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {//開始拖動
Log.v("onStartTrackingTouch()", String.valueOf(seekBar.getProgress()));
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {//結束拖動
Log.v("onStopTrackingTouch()", String.valueOf(seekBar.getProgress()));
}
});
Button button = (Button)this.findViewById(R.id.seekBarButton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(SeekBarActivity.this, String.valueOf(seekBar.getProgress()), 1).show();
}
});
}
}
十二、菜單(Menu)
重寫Activity的onCreateOptionsMenu(Menu menu)方法,該方法用於建立選項菜單,在用戶按下手機的「Menu」按鈕時就會顯示建立好的菜單,在onCreateOptionsMenu(Menu menu)方法內部能夠調用Menu.add()方法實現菜單的添加。
重寫Activity的onMenuItemSelected()方法,該方法用於處理菜單被選擇事件
經過手機上提供的「MENU」按鈕能夠打開菜單,若是但願經過代碼打開菜單,能夠調用Activity的openOptionsMenu()方法。
public class MenuActivity extends Activity {
private static final String TAG = "MenuActivity";
private static final int MENU_ADD = Menu.FIRST;
private static final int MENU_UPDATE = Menu.FIRST + 1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menu);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(Menu.NONE, MENU_ADD, Menu.NONE, "添加");
menu.add(Menu.NONE, MENU_UPDATE, Menu.NONE, "更新");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch (item.getItemId()) {
case MENU_ADD:
Log.i(TAG, "add was selected");
return true;
case MENU_UPDATE:
Log.i(TAG, "update was selected");
return true;
default:
return super.onMenuItemSelected(featureId, item);
}
}
}
1三、進度條(ProgressBar)
在佈局xml文件中添加進度條代碼:
<ProgressBar
android:layout_width="fill_parent"
android:layout_height="20px"
style="?android:attr/progressBarStyleHorizontal"
android:id="@+id/downloadbar"/>
在代碼中操做進度條:
ProgressBar.setMax(100);//設置最大刻度
ProgressBar.setProgress(0);//設置進度條的當前刻度,若是進度條的最大刻度爲100,當前刻度爲50,進度條將進行到一半。
1四、輸入內容自動完成文本框(AutoCompleteTextView )
AutoCompleteTextView和EditText組件相似,均可以輸入文本。
但AutoCompleteTextView組件能夠和一個字符串數組或List對象
綁定,當用戶輸入兩個及以上字符時,系統將在
AutoCompleteTextView組件下方列出字符串數組中全部以輸入
字符開頭的字符串,這一點和www.google.com的搜索框很是類似,
當輸入某一個要查找的字符串時,google搜索框就會列出以這個
字符串開頭的最熱門的搜索字符串列表。
<AutoCompleteTextView
android:layout_width="fill_parent「 android:layout_height="wrap_content「
<!– completionThreshold 指定至少輸入幾個字符後纔會出現自動提示功能 à
android:completionThreshold="1「
android:id="@+id/name" />
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String[] names = {"老張", "老方", "老畢", "李明" , "李麗", "陳江", "abc", "acc"};
AutoCompleteTextView nameText = (AutoCompleteTextView)this.findViewById(R.id.name);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, names);
nameText.setAdapter(adapter);
}
1五、屢次輸入-內容自動完成文本框(MultiAutoCompleteTextView)
除了AutoCompleteTextView控件外,咱們還可使用MultiAutoCompleteTextView控件來完成連續輸入的功能。也就是說,當輸入完一個字符串後,在該字符串後面輸入一個逗號(,),在逗號先後能夠有任意多個空格,而後再輸入一個字符串,仍然會顯示自動提示列表。
使用MultiAutoCompleteTextView時,須要爲它的setTokenizer方法指定MultiAutoCompleteTextView.CommaTokenizer類對象實例,
該對象表示採用逗號做爲輸入多個字符串的分隔符。
< MultiAutoCompleteTextView
android:layout_width="fill_parent「 android:layout_height="wrap_content「
<!– completionThreshold 指定至少輸入幾個字符後纔會出現自動提示功能à
android:completionThreshold="1「
android:id="@+id/name" />
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String[] names = {"老張", "老方", "老畢", "李明" , "李麗", "陳江", "abc", "acc"};
MultiAutoCompleteTextView nameText = (MultiAutoCompleteTextView)this.findViewById(R.id.name);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, names);
nameText.setAdapter(adapter);
nameText.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());}
1六、android樣式和主題(style&theme)
android中的樣式和CSS樣式做用類似,都是用於爲界面元素定義顯示風格,它是一個包含一個或者多個view控件屬性的集合。如:須要定義字體的顏色和大小。
在CSS中是這樣定義的:
<style>
.itcast{COLOR:#0000CC;font-size:18px;}
</style>
能夠像這樣使用上面的css樣式:<div class="itcast">傳智播客</div>
在Android中能夠這樣定義樣式:
在res/values/styles.xml文件中添加如下內容
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name=「itcast」> <!-- 爲樣式定義一個全局惟一的名字-->
<item name=「android:textSize」>18px</item> <!-- name屬性的值爲使用了該樣式的View控件的屬性 -->
<item name="android:textColor">#0000CC</item>
</style>
</resources>
在layout文件中能夠像下面這樣使用上面的android樣式:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" ....>
<TextView style="@style/itcast"
..... />
</LinearLayout>
<style>元素中有一個parent屬性。這個屬性可讓當前樣式繼承一個父樣式,而且具備父樣式的值。固然,若是父樣式的值不符合你的需求,你也能夠對它進行修改,以下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="itcast">
<item name="android:textSize">18px</item> <!-- name屬性爲樣式要用在的View控件持有的屬性 -->
<item name="android:textColor">#0000CC</item>
</style>
<style name="subitcast" parent="@style/itcast">
<item name="android:textColor">#FF0000</item>
</style>
</resources>
android中主題也是用於爲應用定義顯示風格,它的定義和樣式的定義相同,以下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name=「itcastTheme">
<item name=「android:windowNoTitle」>true</item> <!– 沒標題 à
<item name=「android:windowFullscreen」>?android:windowNoTitle</item> <!– 全屏顯示 à
</style>
</resources>
上面「?android:windowNoTitle」中的問號用於引用在當前主題中定義過的資源的值。下面代碼顯示在AndroidManifest.xml中如何爲應用設置上面定義的主題:
<application android:icon="@drawable/icon" android:label="@string/app_name"
android:theme="@style/itcastTheme">
......
</application>
除了能夠在AndroidManifest.xml中設置主題,一樣也能夠在代碼中設置主題,以下:
setTheme(R.style.itcastTheme);
儘管在定義上,樣式和主題基本相同,可是它們使用的地方不一樣。樣式用在單獨的View,如:EditText、TextView等;主題經過AndroidManifest.xml中的<application>和<activity>用在整個應用或者某個 Activity,主題對整個應用或某個Activity進行全局性影響。若是一個應用使用了主題,同時應用下的view也使用了樣式,那麼當主題和樣式屬性發生衝突時,樣式的優先級高於主題。
另外android系統也定義了一些主題,例如:<activity android:theme=「@android:style/Theme.Dialog」>,該主題可讓Activity看起來像一個對話框,還有透明主題:@android:style/Theme.Translucent 。若是須要查閱這些主題,能夠在文檔的referenceàandroid-->R.style 中查看。
1七、編碼實現軟件界面
Android除了可使用xml實現軟件界面,還能夠經過編碼方式實現軟件的界面,並且在某種狀況下只能採用編碼方式實現軟件的界面,例如:軟件運行時須要根據運算結果決定顯示某些內容。若是不是必須,建議使用xml,由於這樣可使應用遵照mvc設計模式,具備良好的軟件分層結構。下面代碼實現瞭如HelloWorld項目同樣的軟件界面:
public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout linearLayout = new LinearLayout(this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
TextView textView = new TextView(this);
textView.setText(R.string.hello);
textView.setId(34);
LinearLayout.LayoutParams textParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
linearLayout.addView(textView, textParams);
setContentView(linearLayout, layoutParams);
}
}
1八、使用網頁開發軟件界面
由於android軟件開發分工目前尚未細化,程序員每每須要負責軟件界面的開發,雖然軟件的界面圖片已經由美工設計好了,但若是使用layout技術把軟件作成如圖片所示的界面確實很困難,並且也比較耗時。Android經過WebView實現了JS代碼與Java代碼互相通訊的功能,使的android軟件的界面開發也能夠採用HTML網頁技術,這樣,廣大網頁美工能夠參與進android軟件的界面開發工做,從而讓程序員從中解脫出來。
在項目的assets目錄放入index.html文件
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
A {
COLOR: #FFFFFF; TEXT-DECORATION: none
}
</style>
<script type="text/javascript">
function show(jsondata){
var jsonobjs = eval(jsondata);
var table = document.getElementById("personTable");
for(var y=0; y<jsonobjs.length; y++){
var tr = table.insertRow(table.rows.length); //添加一行
//添加三列
var td1 = tr.insertCell(0);
var td2 = tr.insertCell(1);
td2.align = "center";
var td3 = tr.insertCell(2);
//設置列內容和屬性
td1.innerHTML = jsonobjs[y].id;
td2.innerHTML = "<a href='javascript:itcast.call(\"5554\")'>"+ jsonobjs[y].name + "</a>";
td3.innerHTML = jsonobjs[y].phone;
}
}
</script>
</head>
<body bgcolor="#000000" text="#FFFFFF" style="margin:0 0 0 0" onload="javascript:itcast.personlist()">
<table border="0" width="100%" id="personTable" cellspacing="0">
<tr>
<td width="15%">編號</td><td align="center">姓名</td><td width="15%">電話</td>
</tr>
</table>
<a href="javascript:window.location.reload()">刷新</a>
</body>
</html>
public class HtmlActivity extends Activity {
private WebView webView;
private Handler handler = new Handler();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webView = (WebView)this.findViewById(R.id.webView);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setSaveFormData(false);
webView.getSettings().setSavePassword(false);
webView.getSettings().setSupportZoom(false);
webView.addJavascriptInterface(new ItcastJavaScript(), 「itcast」);//addJavascriptInterface方法中要綁定的Java對象
webView.setWebChromeClient(new ItcastWebClient());
webView.loadUrl("file:///android_asset/index.html");
}
private final class ItcastJavaScript{
public void personlist(){
webview.loadUrl("javascript:contactlist('"+ getPersonJson() + "')");
}
public void call(final String phone){
startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+ phone)));
}
public static String getPersonJson() {//生成json字符串
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", 56);
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", 56);
jsonObject.put("name", "老張");
jsonObject.put("phone", "5556");
JSONObject jsonObject2 = new JSONObject();
jsonObject2.put("id", 89);
jsonObject2.put("name", "老方");
jsonObject2.put("phone", "5558");
JSONArray jsonArray = new JSONArray();
jsonArray.put(jsonObject);
jsonArray.put(jsonObject2);
return jsonArray.toString();
} catch (JSONException e) {
e.printStackTrace();
}
return "";
}
}
private final class ItcastWebClient extends WebChromeClient{
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
new AlertDialog.Builder(HtmlActivity.this)
.setTitle("提示信息")
.setMessage(message)
.setPositiveButton("肯定", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialoginterface, int i){}
}).show();
return true;
}
}
}
1九、動畫(Animation)
Android提供了2種動畫:
1> Tween動畫,經過對 View 的內容進行一系列的圖形變換 (包括平移、縮放、旋轉、改變透明度)來實現動畫效果。動畫效果的定義能夠採用XML來作也能夠採用編碼來作。Tween動畫有4種類型:
> Frame動畫,即順序播放事先作好的圖像,跟放膠片電影相似。開發步驟:
(1)把準備好的圖片放進項目res/ drawable下。
(2)在項目的res目錄下建立文件夾anim,而後在anim文件夾下面定義動畫XML文件,文件名稱能夠自定義。固然也能夠採用編碼方式定義動畫效果(使用AnimationDrawable類)。
(3)爲View控件綁定動畫效果。調用表明動畫的AnimationDrawable的start()方法開始動畫。
本例要實現對ImageView對象進行漸變尺寸縮放動畫效果
1> 在項目的res目錄下建立文件夾anim,而後在anim文件夾下面定義動畫XML文件,文件名稱能夠自定義,如:scale.xml,內容以下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:toXScale="5"
android:toYScale="5"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="false"
android:duration="5000"
/>
</set>
動畫的進度使用interpolator控制,android提供了幾個Interpolator 子類,實現了不一樣的速度曲線,如LinearInterpolator實現了勻速效果、Accelerateinterpolator實現了加速效果、DecelerateInterpolator實現了減速效果等。還能夠定義本身的Interpolator子類,實現拋物線、自由落體等物理效果。
fromXScale(浮點型) 屬性爲動畫起始時X座標上的縮放尺寸
fromYScale(浮點型) 屬性爲動畫起始時Y座標上的縮放尺寸
toXScale(浮點型) 屬性爲動畫結束時X座標上的縮放尺寸
toYScale(浮點型) 屬性爲動畫結束時Y座標上的縮放尺寸
說明: 以上四種屬性值
0.0表示收縮到沒有
1.0表示正常無縮放
值小於1.0表示收縮
值大於1.0表示放大
pivotX(浮點型) 屬性爲動畫相對於物件的X座標的開始位置
pivotY(浮點型) 屬性爲動畫相對於物件的Y座標的開始位置
說明:
以上兩個屬性值 從0%-100%中取值
50%爲物件的X或Y方向座標上的中點位置
duration(長整型)屬性爲動畫持續時間 。說明: 時間以毫秒爲單位
2> 在layout文件添加<ImageView>節點:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon"
android:id="@+id/imageView"
/>
</LinearLayout>
說明:除了能夠對<ImageView>實現動畫效果,其實也能夠對其餘View實現動畫效果,如:<TextView>
3>在Activity裏對ImageView使用前面定義好的動畫效果:
public class AnimationActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView imageView = (ImageView)this.findViewById(R.id.imageView);
//加載動畫XML文件,生成動畫指令
Animation animation = AnimationUtils.loadAnimation(this, R.anim.scale);
//開始執行動畫
imageView.startAnimation(animation);
}
}
備註:上面採用的是xml文件定義動畫效果,做爲代替,也能夠採用編碼方式實現。下面採用編碼方式實現上述例子一樣的效果:
public class AnimationActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView imageView = (ImageView)this.findViewById(R.id.imageView);
ScaleAnimation animation = new ScaleAnimation(0.0f, 5f, 0.0f, 5f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(5000); //設置持續時間5秒
imageView.startAnimation(animation);
}
}
其餘動畫效果定義例子:
=================漸變透明度動畫效果======================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="0.1"
android:toAlpha="1.0"
android:duration="3000"
/>
</set>
編碼實現透明度動畫效果:
public class AnimationActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView imageView = (ImageView)this.findViewById(R.id.imageView);
AlphaAnimation animation = new AlphaAnimation(0.1, 1.0);
animation.setDuration(5000); //設置持續時間5秒
imageView.startAnimation(animation);
}
}
=================畫面位置移動動畫效果======================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:repeatCount="2"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="120"
android:toYDelta="120"
android:duration="3000"
/>
<!-- fromXDelta fromYDelta 爲動畫起始時 X和Y座標上的位置
toXDelta toYDelta爲動畫結束起始時 X和Y座標上的位置
-->
</set>
編碼實現位置移動動畫效果:
public class AnimationActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView imageView = (ImageView)this.findViewById(R.id.imageView);
TranslateAnimation animation = new TranslateAnimation(0, 120, 0, 120);
animation.setDuration(5000); //設置持續時間5秒
imageView.startAnimation(animation);
=================畫面旋轉動畫效果======================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:interpolator="@android:anim/accelerate_interpolator"
android:repeatCount="2"
android:fromDegrees="0"
android:toDegrees="+360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="3000"
/>
<!--
repeatCount 重複次數
fromDegrees爲動畫起始時物件的角度:
當角度爲負數——表示逆時針旋轉
當角度爲正數——表示順時針旋轉
(負數fromDegrees——toDegrees正數:順時針旋轉)
(負數fromDegrees——toDegrees負數:逆時針旋轉)
(正數fromDegrees——toDegrees正數:順時針旋轉)
(正數fromDegrees——toDegrees負數:逆時針旋轉)
toDegrees屬性爲動畫結束時物件旋轉的角度 能夠大於360度
pivotX,pivotY 爲動畫相對於物件的X、Y座標的開始位.說明:以上兩個屬性值 從0%-100%中取值,50%爲物件的X或Y方向座標上的中點位置
-->
</set>
編碼實現:
RotateAnimation animation = new RotateAnimation(0, -90, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(500);
imageView.startAnimation(animation);
===================== Frame動畫例子 ===============================
(1)把準備好的圖片放進項目res/ drawable下。
圖片有:girl_1.gif, girl_2.gif, girl_3.gif
(2)在項目的res目錄下建立文件夾anim,而後在anim文件夾下面定義動畫XML文件,文件名稱能夠自定義,如:frame.xml。
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/girl_1" android:duration="200" />
<item android:drawable="@drawable/girl_2" android:duration="200" />
<item android:drawable="@drawable/girl_3" android:duration="200" />
</animation-list>
上面的XML就定義了一個Frame動畫,其包含3幀動畫,3幀動畫中分別應用了drawable中的3張圖片:girl_1.gif, girl_2.gif, girl_3.gif,每幀動畫持續200毫秒。android:oneshot屬性若是爲true,表示動畫只播放一次中止在最後一幀上,若是設置爲false表示動畫循環播放。
(3)爲View控件綁定動畫效果,調用表明動畫的AnimationDrawable的start()方法開始動畫。
public class FrameActivity extends Activity {
private AnimationDrawable animationDrawable;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView imageView = (ImageView)this.findViewById(R.id.imageView);
imageView.setBackgroundResource(R.anim.frame);
animationDrawable = (AnimationDrawable) imageView.getBackground();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {//按下
animationDrawable.start();
return true;
}
return super.onTouchEvent(event);
}
}
有一點須要強調的是:啓動Frame動畫的代碼animationDrawable.start();不能應用在OnCreate()方法中,由於在OnCreate()中 AnimationDrawable尚未徹底的與ImageView綁定。在OnCreate()中啓動動畫,只能看到第一張圖片。這裏在觸摸事件中實現的。
20、傳感器的使用
傳感器類型:方向、加速度(重力)、光線、磁場、距離(臨近性)、溫度等。
(1)方向傳感器: Sensor.TYPE_ORIENTATION
(2)加速度(重力)傳感器: Sensor.TYPE_ACCELEROMETER
(3)光線傳感器: Sensor.TYPE_LIGHT
(4)磁場傳感器: Sensor.TYPE_MAGNETIC_FIELD
(5)距離(臨近性)傳感器: Sensor.TYPE_PROXIMITY
(6)溫度傳感器: Sensor.TYPE_TEMPERATURE
//獲取某種類型的感應器
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//註冊監聽,獲取傳感器變化值
sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);
上面第三個參數爲採樣率:最快、遊戲、普通、用戶界面。當應用程序請求特定的採樣率時,其實只是對傳感器子系統的一個建議,不保證特定的採樣率可用。
最快: SensorManager.SENSOR_DELAY_FASTEST
最低延遲,通常不是特別敏感的處理不推薦使用,該種模式可能形成手機電力大量消耗,因爲傳遞的爲原始數據,算法不處理好將會影響遊戲邏輯和UI的性能。
遊戲: SensorManager.SENSOR_DELAY_GAME
遊戲延遲,通常絕大多數的實時性較高的遊戲都使用該級別。
普通: SensorManager.SENSOR_DELAY_NORMAL
標準延遲,對於通常的益智類或EASY級別的遊戲可使用,但太低的採樣率可能對一些賽車類遊戲有跳幀現象。
用戶界面: SensorManager.SENSOR_DELAY_UI
通常對於屏幕方向自動旋轉使用,相對節省電能和邏輯處理,通常遊戲開發中咱們不使用。
下面介紹如何獲取加速度(重力)傳感器和方向傳感器的測量值:
public class MainActivity extends Activity {
private TextView accelerometer;
private TextView orientation;
private SensorManager sensorManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//獲取感應器管理器
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer = (TextView) findViewById(R.id.accelerometer);
orientation = (TextView) findViewById(R.id.orientation);
}
@Override
protected void onResume() {
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);//獲取重力加速度傳感器
sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);
Sensor sensor1 = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);//獲取方向傳感器
sensorManager.registerListener(listener, sensor1, SensorManager.SENSOR_DELAY_GAME);
super.onResume();
}
@Override
protected void onPause() {
sensorManager.unregisterListener(listener);//注消全部傳感器監聽
super.onPause();
}
private SensorEventListener listener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {//當傳感器的值發生變化
float x = event.values[SensorManager.DATA_X];
float y = event.values[SensorManager.DATA_Y];
float z = event.values[SensorManager.DATA_Z];
switch (event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
accelerometer.setText("Accelerometer Sensor: " + x + ", " + y + ", " + z);
break;
case Sensor.TYPE_ORIENTATION:
/*x該值表示方位,0表明北(North);90表明東(East);180表明南(South);270表明西(West)
若是x值正好是這4個值之一,而且手機是水平放置,手機的頂部對準的方向就是該值表明的方向。
y值表示傾斜度,或手機翹起的程度。當手機繞着X軸傾斜時該值發生變化。y值的取值範圍是-180≤y值 ≤180。
假設將手機屏幕朝上水平放在桌子上,這時若是桌子是徹底水平的,y值應該是0(因爲不多有桌子是絕對水平的,
所以,該值極可能不爲0,但通常都是-5和5之間的某個值)。這時從手機頂部開始擡起,直到將手機沿X軸旋轉180度(屏幕向下水平放在桌面上)。
在這個旋轉過程當中,y值會在0到-180之間變化,也就是說,從手機頂部擡起時,y的值會逐漸變小,
直到等於-180。若是從手機底部開始擡起,直到將手機沿X軸旋轉180度,這時y值會在0到180之間變化。
也就是y值會逐漸增大,直到等於180。能夠利用y值和z值來測量桌子等物體的傾斜度。
y值表示傾斜度,或手機翹起的程度。當手機繞着X軸傾斜時該值發生變化。y值的取值範圍是-180≤y值 ≤180。
假設將手機屏幕朝上水平放在桌子上,這時若是桌子是徹底水平的,y值應該是0(因爲不多有桌子是絕對水平的,
所以,該值極可能不爲0,但通常都是-5和5之間的某個值)。這時從手機頂部開始擡起,直到將手機沿X軸旋轉180度(屏幕向下水平放在桌面上)。
在這個旋轉過程當中,y值會在0到-180之間變化,也就是說,從手機頂部擡起時,y的值會逐漸變小,
直到等於-180。若是從手機底部開始擡起,直到將手機沿X軸旋轉180度,這時y值會在0到180之間變化。
也就是y值會逐漸增大,直到等於180。能夠利用y值和z值來測量桌子等物體的傾斜度。
所以,該值極可能不爲0,但通常都是-5和5之間的某個值)。這時從手機頂部開始擡起,直到將手機沿X軸旋轉180度(屏幕向下水平放在桌面上)。
在這個旋轉過程當中,y值會在0到-180之間變化,也就是說,從手機頂部擡起時,y的值會逐漸變小,
直到等於-180。若是從手機底部開始擡起,直到將手機沿X軸旋轉180度,這時y值會在0到180之間變化。
也就是y值會逐漸增大,直到等於180。能夠利用y值和z值來測量桌子等物體的傾斜度。
z值表示手機沿着Y軸的滾動角度。表示手機沿着Y軸的滾動角度。取值範圍是-90≤z值≤90。
假設將手機屏幕朝上水平放在桌面上,這時若是桌面是平的,z值應爲0。將手機左側逐漸擡起時,
z值逐漸變小,直到手機垂直於桌面放置,這時z值是-90。將手機右側逐漸擡起時,z值逐漸增大,
直到手機垂直於桌面放置,這時z值是90。在垂直位置時繼續向右或向左滾動,z值會繼續在-90至90之間變化。
*/
orientation.setText("Orientation Sensor: " + x + ", " + y + ", " + z);
break;
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {//當傳感器的精度變化時
}
};
}
2一、NinePatch圖片
NinePatch是一種頗有用的PNG圖片格式,它能夠在特定區域隨文字大小進行縮放。以下:
從上圖能夠看到,背景圖片的中間區域會隨着文字的大小進行縮放。背景圖片是一張NinePatch圖片。 NinePatch圖片可使用android自帶的draw9patch工具來製做,該工具在SDK安裝路徑的tools目錄下。執行該工具,而後點擊「File」->「open 9-path」打開一張用於製做NinePatch圖片的原來圖片。在畫布的上方和左方的邊上畫線指定縮放區域,
勾選「Show patches」可顯示畫定的區域,綠色
爲固定大小區域,紅色爲縮放區域,文字會擺放在紅色
區域。製做完後,點擊「File」à 「save 9-path」保存
圖片,draw9patch工具會自動爲圖片加上*.9.png後綴。
把製做好的圖片拷貝進項目的res/drawable目錄,而後
編寫代碼。以下:
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="退出" android:textColor="#330000"
android:background="@drawable/button"/>
2二、關閉應用
當應用再也不使用時,一般須要關閉應用,可使用如下三種方法關閉android應用:
第一種方法:首先獲取當前進程的id,而後殺死該進程。
android.os.Process.killProcess(android.os.Process.myPid())
第二種方法:終止當前正在運行的Java虛擬機,致使程序終止
System.exit(0);
第三種方法:強制關閉與該包有關聯的一切執行
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
manager.restartPackage(getPackageName());
<uses-permission android:name="android.permission.RESTART_PACKAGES" />
2三、判斷SIM卡屬於哪一個移動運營商
在文件AndroidManifest.xml中添加權限
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
第一種方法:
獲取手機的IMSI碼,並判斷是中國移動\中國聯通\中國電信
TelephonyManager telManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
/** 獲取SIM卡的IMSI碼
* SIM卡惟一標識:IMSI 國際移動用戶識別碼(IMSI:International Mobile Subscriber Identification Number)是區別移動用戶的標誌,
* 儲存在SIM卡中,可用於區別移動用戶的有效信息。IMSI由MCC、MNC、MSIN組成,其中MCC爲移動國家號碼,由3位數字組成,
* 惟一地識別移動客戶所屬的國家,我國爲460;MNC爲網絡id,由2位數字組成,
* 用於識別移動客戶所歸屬的移動網絡,中國移動爲00,中國聯通爲01,中國電信爲03;MSIN爲移動客戶識別碼,採用等長11位數字構成。
* 惟一地識別國內GSM移動通訊網中移動客戶。因此要區分是移動仍是聯通,只需取得SIM卡中的MNC字段便可
*/
String imsi = telManager.getSubscriberId();
if(imsi!=null){
if(imsi.startsWith("46000") || imsi.startsWith("46002")){//由於移動網絡編號46000下的IMSI已經用完,因此虛擬了一個46002編號,134/159號段使用了此編號
//中國移動
}else if(imsi.startsWith("46001")){
//中國聯通
}else if(imsi.startsWith("46003")){
//中國電信
}
}
第二種方法
TelephonyManager telManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String operator = telManager.getSimOperator();
if(operator!=null){
if(operator.equals("46000") || operator.equals("46002")){
//中國移動
}else if(operator.equals("46001")){
//中國聯通
}else if(operator.equals("46003")){
//中國電信
}
}
2四、從SIM卡中獲取聯繫人信息
Uri uri = Uri.parse("content://icc/adn");
String[] projection = {"_id", "name", "number"};
Cursor cursor = managedQuery(uri, projection, null, null, "name");
if(cursor!=null){
while(cursor.moveToNext()){
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("number"));
}
}
在文件AndroidManifest.xml中添加權限
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
Android系統內部經過Contentprovider對外共享Sim卡存放的聯繫人等信息,你能夠經過操做Contentprovider來實現Sim卡信息的添刪改查操做。
package com.android.internal.telephony;
import android.content.ContentProvider;
import android.content.UriMatcher;
import android.content.ContentValues;
import com.android.internal.database.ArrayListCursor;
import android.database.Cursor;
import android.net.Uri;
import android.os.SystemProperties;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import com.android.internal.telephony.IccConstants;
import com.android.internal.telephony.AdnRecord;
import com.android.internal.telephony.IIccPhoneBook;
public class IccProvider extends ContentProvider {
private static final String TAG = "IccProvider";
private static final boolean DBG = false;
private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] {
"name",
"number"
};
private static final int ADN = 1;
private static final int FDN = 2;
private static final int SDN = 3;
private static final String STR_TAG = "tag";
private static final String STR_NUMBER = "number";
private static final String STR_PIN2 = "pin2";
private static final UriMatcher URL_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
static {
URL_MATCHER.addURI("icc", "adn", ADN);
URL_MATCHER.addURI("icc", "fdn", FDN);
URL_MATCHER.addURI("icc", "sdn", SDN);
}
private boolean mSimulator;
@Override
public boolean onCreate() {
String device = SystemProperties.get("ro.product.device");
if (!TextUtils.isEmpty(device)) {
mSimulator = false;
} else {
// simulator
mSimulator = true;
}
return true;
}
@Override
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sort) {
ArrayList<ArrayList> results;
if (!mSimulator) {
switch (URL_MATCHER.match(url)) {
case ADN:
results = loadFromEf(IccConstants.EF_ADN);
break;
case FDN:
results = loadFromEf(IccConstants.EF_FDN);
break;
case SDN:
results = loadFromEf(IccConstants.EF_SDN);
break;
default:
throw new IllegalArgumentException("Unknown URL " + url);
}
} else {
// Fake up some data for the simulator
results = new ArrayList<ArrayList>(4);
ArrayList<String> contact;
contact = new ArrayList<String>();
contact.add("Ron Stevens/H");
contact.add("512-555-5038");
results.add(contact);
contact = new ArrayList<String>();
contact.add("Ron Stevens/M");
contact.add("512-555-8305");
results.add(contact);
results = new ArrayList<ArrayList>(4);
ArrayList<String> contact;
contact = new ArrayList<String>();
contact.add("Ron Stevens/H");
contact.add("512-555-5038");
results.add(contact);
contact = new ArrayList<String>();
contact.add("Ron Stevens/M");
contact.add("512-555-8305");
results.add(contact);
contact.add("512-555-5038");
results.add(contact);
contact = new ArrayList<String>();
contact.add("Ron Stevens/M");
contact.add("512-555-8305");
results.add(contact);
contact = new ArrayList<String>();
contact.add("Melissa Owens");
contact.add("512-555-8305");
results.add(contact);
contact = new ArrayList<String>();
contact.add("Directory Assistence");
contact.add("411");
results.add(contact);
}
return new ArrayListCursor(ADDRESS_BOOK_COLUMN_NAMES, results);
}
@Override
public String getType(Uri url) {
switch (URL_MATCHER.match(url)) {
case ADN:
case FDN:
case SDN:
return "vnd.android.cursor.dir/sim-contact";
default:
throw new IllegalArgumentException("Unknown URL " + url);
}
}
@Override
public Uri insert(Uri url, ContentValues initialValues) {
Uri resultUri;
int efType;
String pin2 = null;
if (DBG) log("insert");
int match = URL_MATCHER.match(url);
switch (match) {
case ADN:
efType = IccConstants.EF_ADN;
break;
case FDN:
efType = IccConstants.EF_FDN;
pin2 = initialValues.getAsString("pin2");
break;
default:
throw new UnsupportedOperationException(
"Cannot insert into URL: " + url);
}
String tag = initialValues.getAsString("tag");
String number = initialValues.getAsString("number");
boolean success = addIccRecordToEf(efType, tag, number, pin2);
if (!success) {
return null;
}
StringBuilder buf = new StringBuilder("content://im/");
switch (match) {
case ADN:
buf.append("adn/");
break;
case FDN:
buf.append("fdn/");
break;
}
// TODO: we need to find out the rowId for the newly added record
buf.append(0);
resultUri = Uri.parse(buf.toString());
/*
// notify interested parties that an insertion happened
getContext().getContentResolver().notifyInsert(
resultUri, rowID, null);
*/
return resultUri;
}
private String normalizeValue(String inVal) {
int len = inVal.length();
String retVal = inVal;
if (inVal.charAt(0) == '\'' && inVal.charAt(len-1) == '\'') {
retVal = inVal.substring(1, len-1);
}
return retVal;
}
@Override
public int delete(Uri url, String where, String[] whereArgs) {
int efType;
if (DBG) log("delete");
int match = URL_MATCHER.match(url);
switch (match) {
case ADN:
efType = IccConstants.EF_ADN;
break;
case FDN:
efType = IccConstants.EF_FDN;
break;
default:
throw new UnsupportedOperationException(
"Cannot insert into URL: " + url);
}
// parse where clause
String tag = null;
String number = null;
String pin2 = null;
String[] tokens = where.split("AND");
int n = tokens.length;
while (--n >= 0) {
String param = tokens[n];
if (DBG) log("parsing '" + param + "'");
String[] pair = param.split("=");
if (pair.length != 2) {
Log.e(TAG, "resolve: bad whereClause parameter: " + param);
continue;
}
String key = pair[0].trim();
String val = pair[1].trim();
if (STR_TAG.equals(key)) {
tag = normalizeValue(val);
} else if (STR_NUMBER.equals(key)) {
number = normalizeValue(val);
} else if (STR_PIN2.equals(key)) {
pin2 = normalizeValue(val);
}
}
if (TextUtils.isEmpty(tag)) {
return 0;
}
if (efType == FDN && TextUtils.isEmpty(pin2)) {
return 0;
}
boolean success = deleteIccRecordFromEf(efType, tag, number, pin2);
if (!success) {
return 0;
}
return 1;
}
@Override
public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
int efType;
String pin2 = null;
if (DBG) log("update");
int match = URL_MATCHER.match(url);
switch (match) {
case ADN:
efType = IccConstants.EF_ADN;
break;
case FDN:
efType = IccConstants.EF_FDN;
pin2 = values.getAsString("pin2");
break;
default:
throw new UnsupportedOperationException(
"Cannot insert into URL: " + url);
}
String tag = values.getAsString("tag");
String number = values.getAsString("number");
String newTag = values.getAsString("newTag");
String newNumber = values.getAsString("newNumber");
boolean success = updateIccRecordInEf(efType, tag, number,
newTag, newNumber, pin2);
if (!success) {
return 0;
}
return 1;
}
private ArrayList<ArrayList> loadFromEf(int efType) {
ArrayList<ArrayList> results = new ArrayList<ArrayList>();
List<AdnRecord> adnRecords = null;
if (DBG) log("loadFromEf: efType=" + efType);
try {
IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
ServiceManager.getService("simphonebook"));
if (iccIpb != null) {
adnRecords = iccIpb.getAdnRecordsInEf(efType);
}
} catch (RemoteException ex) {
// ignore it
} catch (SecurityException ex) {
if (DBG) log(ex.toString());
}
if (adnRecords != null) {
// Load the results
int N = adnRecords.size();
if (DBG) log("adnRecords.size=" + N);
for (int i = 0; i < N ; i++) {
loadRecord(adnRecords.get(i), results);
}
} else {
// No results to load
Log.w(TAG, "Cannot load ADN records");
results.clear();
}
if (DBG) log("loadFromEf: return results");
return results;
}
private boolean
addIccRecordToEf(int efType, String name, String number, String pin2) {
if (DBG) log("addIccRecordToEf: efType=" + efType + ", name=" + name +
", number=" + number);
boolean success = false;
// TODO: do we need to call getAdnRecordsInEf() before calling
// updateAdnRecordsInEfBySearch()? In any case, we will leave
// the UI level logic to fill that prereq if necessary. But
// hopefully, we can remove this requirement.
try {
IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
ServiceManager.getService("simphonebook"));
if (iccIpb != null) {
success = iccIpb.updateAdnRecordsInEfBySearch(efType, "", "",
name, number, pin2);
}
} catch (RemoteException ex) {
// ignore it
} catch (SecurityException ex) {
if (DBG) log(ex.toString());
}
if (DBG) log("addIccRecordToEf: " + success);
return success;
}
private boolean
updateIccRecordInEf(int efType, String oldName, String oldNumber,
String newName, String newNumber,String pin2) {
if (DBG) log("updateIccRecordInEf: efType=" + efType +
", oldname=" + oldName + ", oldnumber=" + oldNumber +
", newname=" + newName + ", newnumber=" + newNumber);
boolean success = false;
try {
IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
ServiceManager.getService("simphonebook"));
if (iccIpb != null) {
success = iccIpb.updateAdnRecordsInEfBySearch(efType,
oldName, oldNumber, newName, newNumber, pin2);
}
} catch (RemoteException ex) {
// ignore it
} catch (SecurityException ex) {
if (DBG) log(ex.toString());
}
if (DBG) log("updateIccRecordInEf: " + success);
return success;
}
private boolean deleteIccRecordFromEf(int efType, String name, String number, String pin2) {
if (DBG) log("deleteIccRecordFromEf: efType=" + efType +
", name=" + name + ", number=" + number + ", pin2=" + pin2);
boolean success = false;
try {
IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
ServiceManager.getService("simphonebook"));
if (iccIpb != null) {
success = iccIpb.updateAdnRecordsInEfBySearch(efType,
name, number, "", "", pin2);
}
} catch (RemoteException ex) {
// ignore it
} catch (SecurityException ex) {
if (DBG) log(ex.toString());
}
if (DBG) log("deleteIccRecordFromEf: " + success);
return success;
}
name, number, "", "", pin2);
}
} catch (RemoteException ex) {
// ignore it
} catch (SecurityException ex) {
if (DBG) log(ex.toString());
}
if (DBG) log("deleteIccRecordFromEf: " + success);
return success;
}
name, number, "", "", pin2);
}
} catch (RemoteException ex) {
// ignore it
} catch (SecurityException ex) {
if (DBG) log(ex.toString());
}
if (DBG) log("deleteIccRecordFromEf: " + success);
return success;
}
25、刪除呼叫記錄
在文件AndroidManifest.xml中添加權限
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
負責存放呼叫記錄的內容提供者源碼在ContactsProvider項目下:
源碼路徑:
com\android\providers\contacts\CallLogProvider.java
使用到的數據庫在:
/data/data/com.android.providers.contacts/databases/contacts2.db
表名:calls
呼叫記錄有三種類型:
來電:CallLog.Calls.INCOMING_TYPE (常量值:1)
外拔:CallLog.Calls.OUTGOING_TYPE(常量值:2)
未接:CallLog.Calls.MISSED_TYPE(常量值:3)
刪除指定號碼的來電或未接呼叫記錄:
IncomingCallLogContentObserver observer = new IncomingCallLogContentObserver(new Handler());
observer.setNumber("5554");
getContentResolver().registerContentObserver(CallLog.Calls.CONTENT_URI, true, observer);
private class IncomingCallLogContentObserver extends ContentObserver {
private String number;
public IncomingCallLogContentObserver(Handler handler){
super(handler);
}
public void setNumber(String number){
this.number = number;
}
public void onChange(boolean paramBoolean){
ContentResolver contentResolver = getContentResolver();
if(number!=null){
Uri localUri = CallLog.Calls.CONTENT_URI;
Cursor cursor = contentResolver.query(localUri, new String[]{"_id"}, "number=? AND (type=1 OR type=3)",
new String[]{number}, "_id desc limit 1");
if(cursor.moveToFirst()){
contentResolver.delete(localUri, "_id=?", new String[]{cursor.getString(0)});
}
cursor.close();
}
contentResolver.unregisterContentObserver(this);
}
}
26、在應用中安裝其餘程序
首先須要AndroidManifest.xml中加入安裝程序權限:
<!-- 安裝程序權限 -->
<uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
第二步把安裝程序添加進SDCard。如把文件名爲」 sogouinput_android_1.40_sweb.apk.zip」的sogou拼音輸入法安裝文件放進SDCard。能夠點擊下面按鈕:
第三步在程序中添加如下代碼:
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "sogouinput_android_1.40_sweb.apk.zip")),"application/vnd.android.package-archive");
startActivity(intent);
2七、如何反編繹APK文件
安裝ApkTool工具,該工具能夠解碼獲得資源文件,但不能獲得Java源文件。
安裝環境:須要安裝JRE1.6
1> 到http://code.google.com/p/android-apktool/下載apktool1.3.2.tar.bz2 和apktool-install-windows-2.2_r01-3.tar.bz2 文件。解壓兩個文件,而後把解壓後的文件放在一塊兒,如:c:\apktool
2> 在系統變量PATH中添加進aapt.exe,如:;c:\apktool\aapt.exe
3> 在DOS窗口下進入apktool.jar所在目錄。執行DOS命令:apktool d -s c:\soft\xxx.apk c:\soft\source。
命令格式:apktool d [opts] <file.apk> [dir] 中的d表明解碼,[opts]表明選項,-s選項表明不解碼源文件。
Apktool工具只能反編譯成smali的中間代碼文件,這裏須要藉助另一個開源工具Dex2Jar,該工具能夠把dex文件轉換成jar文件。這個工具不能直接翻譯成java文件,可是能夠把dex文件轉換成jar文件
下載地址:http://code.google.com/p/dex2jar/。
1> 把APK安裝包中的classes.dex解壓到某個目錄下,如:c:\soft
2> 在DOS窗口下進入dex2jar.bat所在目錄,執行DOS命令:dex2jar.bat c:\soft\source\classes.dex c:\soft\source,命令生成classes.dex.dex2jar.jar文件。
安裝jd-gui工具,該工具能夠把jar文件反編譯成Java源文件
下載地址:http://java.decompiler.free.fr/jd-gui/downloads/jd-gui-0.3.3.windows.zip。
運行該軟件,直接打開classes.dex.dex2jar.jar文件便可看到java源代碼。
2八、如何防止咱們的代碼被反編譯
因爲apk是Android虛擬機加載的,它有必定的規範,加密apk後Dalvik沒法
識別apk了。徹底避免是不可能的,總有人可以破解你的代碼。可是有幾種
方式來提升被反編譯取代碼的難度。
1 關鍵代碼使用jni調用本地代碼,用c或者c++編寫,所以相對比較難於反
編譯
2 混淆java代碼。混淆是不改變代碼邏輯的狀況下,增長無用代碼,或者重
命名,使反編譯後的源代碼難於看懂。
網上開源的java代碼混淆工具較多,通常是用ant的方式來編譯的