1、Android的状态栏通知(Notification)

通知用于在状态栏显示消息,消息到来时以图标方式表示,如下:

//获取通知管理器

NotificationManagermNotificationManager=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

inticon=android.R.drawable.stat_notify_chat;

longwhen=System.currentTimeMillis();

//新建一个通知,指定其图标和标题

Notificationnotification=newNotification(icon,null,when);//第一个参数为图标,第二个参数为短暂提示标题,第三个为通知时间

notification.defaults=Notification.DEFAULT_SOUND;//发出默认声音

Intentopenintent=newIntent(this,OtherActivity.class);

PendingIntentcontentIntent=PendingIntent.getActivity(this,0,openintent,0);//当点击消息时就会向系统发送openintent意图

notification.setLatestEventInfo(this,“标题”,“我是内容",contentIntent);

mNotificationManager.notify(0,notification);//第一个参数为自定义的通知唯一标识

2、对话框通知(DialogNotification)

当你的应用需要显示一个进度条或需要用户对信息进行确认时,可以使用对话框来完成。

下面代码将打开一个如右图所示的对话框:

newAlertDialog.Builder(context)

.setTitle("java培训")

.setCancelable(false)//设置不能通过“后退”按钮关闭对话框

.setMessage("浏览传智播客网站?")

.setPositiveButton("确认",

newDialogInterface.OnClickListener(){

publicvoidonClick(DialogInterfacedialoginterface,inti){

Uriuri=Uri.parse("http://www.itcast.cn/");//打开链接

Intentintent=newIntent(Intent.ACTION_VIEW,uri);

startActivity(intent);

}

})

.setNegativeButton("取消",newDialogInterface.OnClickListener(){

publicvoidonClick(DialogInterfacedialog,intid){

dialog.cancel();

}

})

.show();//显示对话框

上面代码采用的是一个链式调用,像setTitle()setMessage()这些方法,他们的返回值都是当前对话框对象。

3、创建带单选项列表的对话框

下面代码将打开一个如右上图所示的选项列表对话框:

finalString[]items={"java",".net","php"};

newAlertDialog.Builder(SenderNotificationActivity.this).setTitle("选择语言")

.setItems(items,newDialogInterface.OnClickListener(){

publicvoidonClick(DialogInterfacedialog,intitem){

Toast.makeText(getApplicationContext(),items[item],

Toast.LENGTH_SHORT).show();

}

}).show();//显示对话框

下面代码将打开一个如右下图所示的带单选框的列表对话框:

finalString[]items={"java",".net","php"};

newAlertDialog.Builder(SenderNotificationActivity.this).setTitle("选择语言")

.setSingleChoiceItems(items,1,newDialogInterface.OnClickListener(){

publicvoidonClick(DialogInterfacedialog,intitem){

Toast.makeText(getApplicationContext(),items[item],

Toast.LENGTH_SHORT).show();

dialog.cancel();

}

}).show();//显示对话框

setSingleChoiceItems()的第二个参数是设置默认选项,

选项索引从0开始,-1代表不选择任何选项。

4、创建带多选项列表的对话框

下面代码将打开一个如右下图所示的多选项列表对话框:

finalString[]items={"java",".net","php"};

newAlertDialog.Builder(SenderNotificationActivity.this).setCancelable(false)

.setTitle("选择语言")

.setMultiChoiceItems(items,newboolean[]{false,true,false},newDialogInterface.OnMultiChoiceClickListener(){

@Override

publicvoidonClick(DialogInterfacedialog,intwhich,booleanisChecked){

if(isChecked){

Toast.makeText(getApplicationContext(),items[which],

Toast.LENGTH_SHORT).show();

}

}

})

.setPositiveButton("确认",

newDialogInterface.OnClickListener(){

publicvoidonClick(DialogInterfacedialoginterface,inti){

dialoginterface.dismiss();

}

})

.show();//显示对话框

5进度对话框(ProgressDialog)

使用代码ProgressDialog.show(ProgressDialogActivity.this,"请稍等","数据正在加载中...",true);创建并显示一个进度对话框。

调用setProgressStyle()方法设置进度对话框风格。有两种风格:

ProgressDialog.STYLE_SPINNER旋体进度条风格(为默认风格)

ProgressDialog.STYLE_HORIZONTAL横向进度条风格

publicclassProgressDialogActivityextendsActivity{

privateProgressDialogprogressDialog;

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.menu);

//开始一条专门处理耗时工作的线程

newThread(newRunnable(){

@Override

publicvoidrun(){

try{

Thread.sleep(5*1000);//假设这项工作需要5秒才能完成

progressDialog.dismiss();//关闭进程对话框

//runOnUiThread(finishDialog);//要求运行在UI线程

}catch(InterruptedExceptione){}

}

}).start();

progressDialog=ProgressDialog.show(ProgressDialogActivity.this,"请稍等","数据正在加载中...",true);

}

privateRunnablefinishDialog=newRunnable(){

@Override

publicvoidrun(){

progressDialog.dismiss();

}

};

}

6、单选框(RadioButton)

要完成单选框显示,我们需要使用到RadioGroupRadioButton(单选框)RadioGroup用于对单选框进行分组,相同组内的单选框只有一个单选框能被选中。(例子代码请见下方备注栏)

RadioGroup.check(R.id.dotNet);id名为dotNet的单选框设置成选中状态。

(RadioButton)findViewById(radioGroup.getCheckedRadioButtonId());//获取被选中的单选框。

RadioButton.getText();//获取单选框的值

调用setOnCheckedChangeListener()方法,处理单选框被选择事件,把RadioGroup.OnCheckedChangeListener实例作为参数传入

界面设计:

<?xmlversion="1.0"encoding="utf-8"?>

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<RadioGroupandroid:id="@+id/radioGroup"

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

<RadioButtonandroid:id="@+id/java"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="java"/>

<RadioButtonandroid:id="@+id/dotNet"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="dotNet"/>

<RadioButtonandroid:id="@+id/php"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="PHP"/>

</RadioGroup>

</LinearLayout>

处理程序:

publicvoidonCreate(BundlesavedInstanceState){

......

RadioGroupradioGroup=(RadioGroup)findViewById(R.id.radioGroup);

radioGroup.setOnCheckedChangeListener(newRadioGroup.OnCheckedChangeListener(){

publicvoidonCheckedChanged(RadioGroupgroup,intcheckedId){

RadioButtonradioButton=(RadioButton)findViewById(checkedId);

Log.i(TAG,String.valueOf(radioButton.getText()));

}

});

}

7、多选框(CheckBox)

每个多选框都是独立的,可以通过迭代所有多选框,然后根据其状态是否被选中再获取其值。

CheckBox.setChecked(true);//设置成选中状态。

CheckBox.getText();//获取多选框的值

调用setOnCheckedChangeListener()方法,处理多选框被选择事件,把CompoundButton.OnCheckedChangeListener实例作为参数传入

界面设计:

<?xmlversion="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">

<CheckBoxandroid:id="@+id/checkboxjava"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="java"/>

<CheckBoxandroid:id="@+id/checkboxdotNet"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="dotNet"/>

<CheckBoxandroid:id="@+id/checkboxphp"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="PHP"/>

<Buttonandroid:id="@+id/checkboxButton"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="获取值"/>

</LinearLayout>

代码处理:

publicclassCheckBoxActivityextendsActivity{

privatestaticfinalStringTAG="CheckBoxActivity";

privateList<CheckBox>checkboxs=newArrayList<CheckBox>();

@Override

publicvoidonCreate(BundlesavedInstanceState){

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(CheckBoxbox:checkboxs){

box.setOnCheckedChangeListener(listener);

}

Buttonbutton=(Button)findViewById(R.id.checkboxButton);

button.setOnClickListener(newView.OnClickListener(){

@Override

publicvoidonClick(Viewv){

List<String>values=newArrayList<String>();

for(CheckBoxbox:checkboxs){

if(box.isChecked()){

values.add(box.getText().toString());

}

}

Toast.makeText(CheckBoxActivity.this,values.toString(),1).show();

}

});

}

CompoundButton.OnCheckedChangeListenerlistener=newCompoundButton.OnCheckedChangeListener(){@Override

publicvoidonCheckedChanged(CompoundButtonbuttonView,booleanisChecked){

CheckBoxcheckBox=(CheckBox)buttonView;

Log.i(TAG,"isChecked="+isChecked+",value="+checkBox.getText());//输出单选框的值

}

};

}

8、下拉列表框(Spinner)

Spinner.getItemAtPosition(Spinner.getSelectedItemPosition());获取下拉列表框的值

调用setOnItemSelectedListener()方法,处理下拉列表框被选择事件,把AdapterView.OnItemSelectedListener实例作为参数传入

界面设计:

<?xmlversion="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">

<Spinnerandroid:id="@+id/spinner"

android:layout_height="wrap_content"

android:layout_width="fill_parent"/>

</LinearLayout>

代码处理:

publicclassSpinnerActivityextendsActivity{

privatestaticfinalStringTAG="SpinnerActivity";

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.spinner);

//第二个参数为下拉列表框每一项的界面样式,该界面样式由Android系统提供,当然您也可以自定义

ArrayAdapter<String>adapter=newArrayAdapter<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");

Spinnerspinner=(Spinner)findViewById(R.id.spinner);

spinner.setAdapter(adapter);

spinner.setOnItemSelectedListener(newAdapterView.OnItemSelectedListener(){

@Override

publicvoidonItemSelected(AdapterView<?>adapterView,Viewview,intposition,longid){

Spinnerspinner=(Spinner)adapterView;

StringitemContent=(String)adapterView.getItemAtPosition(position);

}

@Override

publicvoidonNothingSelected(AdapterView<?>view){

Log.i(TAG,view.getClass().getName());

}

});

}

}

9下拉列表框—采用javabean作为Adapter元素

很多时候显示在下拉列表框的值并不是希望得到的值,如果要做一个联系人下拉列表框,列表框列出的是联系人的姓名,因为姓名有可能相同,所以我们希望得到的值应该为该联系人的id,要实现这种需求我们需要自定义Adapter,当然自定义Adapter需要我们编写一小段代码,如果我们不想编写Adapter,又能实现我们的需求,那是最好不过的了。通过观察ArrayAdaptergetView(intposition,ViewconvertView,ViewGroupparent)的内部代码发现,如果为ArrayAdapter指定的实际泛型参数类型没有实现CharSequence(字符串)接口,将会调用该类型对象的toString()向下拉列表框输出显示值。利用这个特点我们可以重写javaBeantoString()向下拉列表框提供显示值。

界面设计:

<?xmlversion="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">

<Spinnerandroid:id="@+id/spinner"

android:layout_height="wrap_content"

android:layout_width="fill_parent"/>

</LinearLayout>

代码处理:

publicclassSpinnerActivityextendsActivity{

privatestaticfinalStringTAG="SpinnerActivity";

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.spinner);

ArrayAdapter<Person>adapter=newArrayAdapter<Person>(this,android.R.layout.simple_spinner_item);

adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

adapter.add(newPerson(12,"李明"));

adapter.add(newPerson(100,"李明"));

adapter.add(newPerson(62,"张天"));

Spinnerspinner=(Spinner)findViewById(R.id.spinner);

spinner.setAdapter(adapter);

spinner.setOnItemSelectedListener(newAdapterView.OnItemSelectedListener(){

@Override

publicvoidonItemSelected(AdapterView<?>adapterView,Viewview,intposition,longid){

Spinnerspinner=(Spinner)adapterView;

Personperson=(Person)adapterView.getItemAtPosition(position);

}

@Override

publicvoidonNothingSelected(AdapterView<?>view){

Log.i(TAG,view.getClass().getName());

}

});

}

}

Person.java:

publicclassPerson{

privateIntegerid;

privateStringname;

publicPerson(Integerid,Stringname){

this.id=id;

this.name=name;

}

publicIntegergetId(){

returnid;

}

publicvoidsetId(Integerid){

this.id=id;

}

publicStringgetName(){

returnname;

}

publicvoidsetName(Stringname){

this.name=name;

}

@Override

publicStringtoString(){

returnname;

}

}

10、下拉列表框--自定义选项界面样式

Spinner.getItemAtPosition(Spinner.getSelectedItemPosition());获取下拉列表框的值

调用setOnItemSelectedListener()方法,处理下拉列表框被选择事件,把AdapterView.OnItemSelectedListener实例作为参数传入

主界面设计:

<?xmlversion="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">

<Spinnerandroid:id="@+id/spinner"

android:layout_height="wrap_content"

android:layout_width="fill_parent"/>

</LinearLayout>

下拉列表框每一项的界面样式:stylespinner.xml

<?xmlversion="1.0"encoding="utf-8"?>

<TextViewxmlns: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"

/>

代码处理:

publicclassSpinnerActivityextendsActivity{

privatestaticfinalStringTAG="SpinnerActivity";

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.spinner);

//第二个参数为layout文件在R文件的id,第三个参数为TextViewlayout文件的id

ArrayAdapter<String>adapter=newArrayAdapter<String>(this,R.layout.stylespinner,R.id.contentTextView);

adapter.add("java");

adapter.add("dotNet");

adapter.add("php");

Spinnerspinner=(Spinner)findViewById(R.id.spinner);

spinner.setAdapter(adapter);

spinner.setOnItemSelectedListener(newAdapterView.OnItemSelectedListener(){

@Override

publicvoidonItemSelected(AdapterView<?>adapterView,Viewview,intposition,longid){

Spinnerspinner=(Spinner)adapterView;

StringitemContent=(String)adapterView.getItemAtPosition(position);

}

@Override

publicvoidonNothingSelected(AdapterView<?>view){

Log.i(TAG,view.getClass().getName());

}

});

}

}

11、拖动条(SeekBar)

SeekBar.getProgress()获取拖动条当前值

调用setOnSeekBarChangeListener()方法,处理拖动条值变化事件,把SeekBar.OnSeekBarChangeListener实例作为参数传入

主界面设计:

<?xmlversion="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"/>

<Buttonandroid:id="@+id/seekBarButton"

android:layout_height="wrap_content"

android:layout_width="wrap_content"

android:text="获取值"

/>

</LinearLayout>

代码处理:

publicclassSeekBarActivityextendsActivity{

privateSeekBarseekBar;

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.seekbar);

seekBar=(SeekBar)findViewById(R.id.seekBar);

seekBar.setMax(100);//设置最大刻度

seekBar.setProgress(30);//设置当前刻度

seekBar.setOnSeekBarChangeListener(newSeekBar.OnSeekBarChangeListener(){

@Override

publicvoidonProgressChanged(SeekBarseekBar,intprogress,booleanfromTouch){

Log.v("onProgressChanged()",String.valueOf(progress)+","+String.valueOf(fromTouch));

}

@Override

publicvoidonStartTrackingTouch(SeekBarseekBar){//开始拖动

Log.v("onStartTrackingTouch()",String.valueOf(seekBar.getProgress()));

}

@Override

publicvoidonStopTrackingTouch(SeekBarseekBar){//结束拖动

Log.v("onStopTrackingTouch()",String.valueOf(seekBar.getProgress()));

}

});

Buttonbutton=(Button)this.findViewById(R.id.seekBarButton);

button.setOnClickListener(newView.OnClickListener(){

@Override

publicvoidonClick(Viewv){

Toast.makeText(SeekBarActivity.this,String.valueOf(seekBar.getProgress()),1).show();

}

});

}

}

12、菜单(Menu)

重写ActivityonCreateOptionsMenu(Menumenu)方法,该方法用于创建选项菜单,在用户按下手机的“Menu”按钮时就会显示创建好的菜单,在onCreateOptionsMenu(Menumenu)方法内部可以调用Menu.add()方法实现菜单的添加。

重写ActivityonMenuItemSelected()方法,该方法用于处理菜单被选择事件

通过手机上提供的“MENU”按钮可以打开菜单,如果希望通过代码打开菜单,可以调用ActivityopenOptionsMenu()方法。

publicclassMenuActivityextendsActivity{

privatestaticfinalStringTAG="MenuActivity";

privatestaticfinalintMENU_ADD=Menu.FIRST;

privatestaticfinalintMENU_UPDATE=Menu.FIRST+1;

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.menu);

}

@Override

publicbooleanonCreateOptionsMenu(Menumenu){

menu.add(Menu.NONE,MENU_ADD,Menu.NONE,"添加");

menu.add(Menu.NONE,MENU_UPDATE,Menu.NONE,"更新");

returnsuper.onCreateOptionsMenu(menu);

}

@Override

publicbooleanonMenuItemSelected(intfeatureId,MenuItemitem){

switch(item.getItemId()){

caseMENU_ADD:

Log.i(TAG,"addwasselected");

returntrue;

caseMENU_UPDATE:

Log.i(TAG,"updatewasselected");

returntrue;

default:

returnsuper.onMenuItemSelected(featureId,item);

}

}

}

13、进度条(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,进度条将进行到一半。

14、输入内容自动完成文本框(AutoCompleteTextView

AutoCompleteTextViewEditText组件类似,都可以输入文本。

AutoCompleteTextView组件可以和一个字符串数组或List对象

绑定,当用户输入两个及以上字符时,系统将在

AutoCompleteTextView组件下方列出字符串数组中所有以输入

字符开头的字符串,这一点和www.google.com的搜索框非常相似,

当输入某一个要查找的字符串时,google搜索框就会列出以这个

字符串开头的最热门的搜索字符串列表。

<AutoCompleteTextView

android:layout_width="fill_parentandroid:layout_height="wrap_content

<!completionThreshold指定至少输入几个字符后才会出现自动提示功能à

android:completionThreshold="1

android:id="@+id/name"/>

publicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);

setContentView(R.layout.main);

String[]names={"老张","老方","老毕","李明","李丽","陈江","abc","acc"};

AutoCompleteTextViewnameText=(AutoCompleteTextView)this.findViewById(R.id.name);

ArrayAdapter<String>adapter=newArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,names);

nameText.setAdapter(adapter);

}

15、多次输入-内容自动完成文本框(MultiAutoCompleteTextView

除了AutoCompleteTextView控件外,我们还可以使用MultiAutoCompleteTextView控件来完成连续输入的功能。也就是说,当输入完一个字符串后,在该字符串后面输入一个逗号(,),在逗号前后可以有任意多个空格,然后再输入一个字符串,仍然会显示自动提示列表。

使用MultiAutoCompleteTextView时,需要为它的setTokenizer方法指定MultiAutoCompleteTextView.CommaTokenizer类对象实例,

该对象表示采用逗号作为输入多个字符串的分隔符。

<MultiAutoCompleteTextView

android:layout_width="fill_parentandroid:layout_height="wrap_content

<!completionThreshold指定至少输入几个字符后才会出现自动提示功能à

android:completionThreshold="1

android:id="@+id/name"/>

publicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);

setContentView(R.layout.main);

String[]names={"老张","老方","老毕","李明","李丽","陈江","abc","acc"};

MultiAutoCompleteTextViewnameText=(MultiAutoCompleteTextView)this.findViewById(R.id.name);

ArrayAdapter<String>adapter=newArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,names);

nameText.setAdapter(adapter);

nameText.setTokenizer(newMultiAutoCompleteTextView.CommaTokenizer());}

16、android样式和主题(style&theme)

android中的样式和CSS样式作用相似,都是用于为界面元素定义显示风格,它是一个包含一个或者多个view控件属性的集合。如:需要定义字体的颜色和大小。

CSS中是这样定义的:

<style>

.itcast{COLOR:#0000CC;font-size:18px;}

</style>

可以像这样使用上面的css样式:<divclass="itcast">传智播客</div>

Android中可以这样定义样式:

res/values/styles.xml文件中添加以下内容

<?xmlversion="1.0"encoding="utf-8"?>

<resources>

<stylename=itcast><!--为样式定义一个全局唯一的名字-->

<itemname=android:textSize>18px</item><!--name属性的值为使用了该样式的View控件的属性-->

<itemname="android:textColor">#0000CC</item>

</style>

</resources>

layout文件中可以像下面这样使用上面的android样式:

<?xmlversion="1.0"encoding="utf-8"?>

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"....>

<TextViewstyle="@style/itcast"

...../>

</LinearLayout>

<style>元素中有一个parent属性。这个属性可以让当前样式继承一个父样式,并且具有父样式的值。当然,如果父样式的值不符合你的需求,你也可以对它进行修改,如下:

<?xmlversion="1.0"encoding="utf-8"?>

<resources>

<stylename="itcast">

<itemname="android:textSize">18px</item><!--name属性为样式要用在的View控件持有的属性-->

<itemname="android:textColor">#0000CC</item>

</style>

<stylename="subitcast"parent="@style/itcast">

<itemname="android:textColor">#FF0000</item>

</style>

</resources>

android中主题也是用于为应用定义显示风格,它的定义和样式的定义相同,如下:

<?xmlversion="1.0"encoding="utf-8"?>

<resources>

<stylename=itcastTheme">

<itemname=android:windowNoTitle>true</item><!–没标题à

<itemname=android:windowFullscreen>?android:windowNoTitle</item><!–全屏显示à

</style>

</resources>

上面“?android:windowNoTitle”中的问号用于引用在当前主题中定义过的资源的值。下面代码显示在AndroidManifest.xml中如何为应用设置上面定义的主题:

<applicationandroid:icon="@drawable/icon"android:label="@string/app_name"

android:theme="@style/itcastTheme">

......

</application>

除了可以在AndroidManifest.xml中设置主题,同样也可以在代码中设置主题,如下:

setTheme(R.style.itcastTheme);

尽管在定义上,样式和主题基本相同,但是它们使用的地方不同。样式用在单独的View,如:EditTextTextView等;主题通过AndroidManifest.xml中的<application><activity>用在整个应用或者某个Activity,主题对整个应用或某个Activity进行全局性影响。如果一个应用使用了主题,同时应用下的view也使用了样式,那么当主题和样式属性发生冲突时,样式的优先级高于主题。

另外android系统也定义了一些主题,例如:<activityandroid:theme=@android:style/Theme.Dialog>,该主题可以让Activity看起来像一个对话框,还有透明主题:@android:style/Theme.Translucent如果需要查阅这些主题,可以在文档的referenceàandroid-->R.style中查看。

17、编码实现软件界面

Android除了可以使用xml实现软件界面,还可以通过编码方式实现软件的界面,而且在某种情况下只能采用编码方式实现软件的界面,例如:软件运行时需要根据运算结果决定显示某些内容。如果不是必须,建议使用xml,因为这样可以使应用遵守mvc设计模式,具有良好的软件分层结构。下面代码实现了如HelloWorld项目一样的软件界面:

publicclassMainActivityextendsActivity{

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

LinearLayoutlinearLayout=newLinearLayout(this);

LinearLayout.LayoutParamslayoutParams=newLinearLayout.LayoutParams(

ViewGroup.LayoutParams.FILL_PARENT,ViewGroup.LayoutParams.FILL_PARENT);

TextViewtextView=newTextView(this);

textView.setText(R.string.hello);

textView.setId(34);

LinearLayout.LayoutParamstextParams=newLinearLayout.LayoutParams(

ViewGroup.LayoutParams.FILL_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);

linearLayout.addView(textView,textParams);

setContentView(linearLayout,layoutParams);

}

}

18、使用网页开发软件界面

因为android软件开发分工目前还没有细化,程序员往往需要负责软件界面的开发,虽然软件的界面图片已经由美工设计好了,但如果使用layout技术把软件做成如图片所示的界面确实很困难,而且也比较耗时。Android通过WebView实现了JS代码与Java代码互相通信的功能,使的android软件的界面开发也可以采用HTML网页技术,这样,广大网页美工可以参与进android软件的界面开发工作,从而让程序员从中解脱出来。

在项目的assets目录放入index.html文件

<!DOCTYPEhtmlPUBLIC"-//W3C//DTDHTML4.01Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<metahttp-equiv="Content-Type"content="text/html;charset=UTF-8">

<title>Inserttitlehere</title>

<styletype="text/css">

A{

COLOR:#FFFFFF;TEXT-DECORATION:none

}

</style>

<scripttype="text/javascript">

functionshow(jsondata){

varjsonobjs=eval(jsondata);

vartable=document.getElementById("personTable");

for(vary=0;y<jsonobjs.length;y++){

vartr=table.insertRow(table.rows.length);//添加一行

//添加三列

vartd1=tr.insertCell(0);

vartd2=tr.insertCell(1);

td2.align="center";

vartd3=tr.insertCell(2);

//设置列内容和属性

td1.innerHTML=jsonobjs[y].id;

td2.innerHTML="<ahref='javascript:itcast.call(\"5554\")'>"+jsonobjs[y].name+"</a>";

td3.innerHTML=jsonobjs[y].phone;

}

}

</script>

</head>

<bodybgcolor="#000000"text="#FFFFFF"style="margin:0000"onload="javascript:itcast.personlist()">

<tableborder="0"width="100%"id="personTable"cellspacing="0">

<tr>

<tdwidth="15%">编号</td><tdalign="center">姓名</td><tdwidth="15%">电话</td>

</tr>

</table>

<ahref="javascript:window.location.reload()">刷新</a>

</body>

</html>

publicclassHtmlActivityextendsActivity{

privateWebViewwebView;

privateHandlerhandler=newHandler();

@Override

publicvoidonCreate(BundlesavedInstanceState){

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(newItcastJavaScript(),itcast);//addJavascriptInterface方法中要绑定的Java对象

webView.setWebChromeClient(newItcastWebClient());

webView.loadUrl("file:///android_asset/index.html");

}

privatefinalclassItcastJavaScript{

publicvoidpersonlist(){

webview.loadUrl("javascript:contactlist('"+getPersonJson()+"')");

}

publicvoidcall(finalStringphone){

startActivity(newIntent(Intent.ACTION_CALL,Uri.parse("tel:"+phone)));

}

publicstaticStringgetPersonJson(){//生成json字符串

try{

JSONObjectjsonObject=newJSONObject();

jsonObject.put("id",56);

try{

JSONObjectjsonObject=newJSONObject();

jsonObject.put("id",56);

jsonObject.put("name","老张");

jsonObject.put("phone","5556");

JSONObjectjsonObject2=newJSONObject();

jsonObject2.put("id",89);

jsonObject2.put("name","老方");

jsonObject2.put("phone","5558");

JSONArrayjsonArray=newJSONArray();

jsonArray.put(jsonObject);

jsonArray.put(jsonObject2);

returnjsonArray.toString();

}catch(JSONExceptione){

e.printStackTrace();

}

return"";

}

}

privatefinalclassItcastWebClientextendsWebChromeClient{

@Override

publicbooleanonJsAlert(WebViewview,Stringurl,Stringmessage,JsResultresult){

newAlertDialog.Builder(HtmlActivity.this)

.setTitle("提示信息")

.setMessage(message)

.setPositiveButton("确定",newDialogInterface.OnClickListener(){

publicvoidonClick(DialogInterfacedialoginterface,inti){}

}).show();

returntrue;

}

}

}

19、动画(Animation

Android提供了2种动画:

1>Tween动画,通过对View的内容进行一系列的图形变换(包括平移、缩放、旋转、改变透明度)来实现动画效果。动画效果的定义可以采用XML来做也可以采用编码来做。Tween动画有4种类型:

>Frame动画,即顺序播放事先做好的图像,跟放胶片电影类似。开发步骤:

1)把准备好的图片放进项目res/drawable下。

2)在项目的res目录下创建文件夹anim,然后在anim文件夹下面定义动画XML文件,文件名称可以自定义。当然也可以采用编码方式定义动画效果(使用AnimationDrawable类)。

3)为View控件绑定动画效果。调用代表动画的AnimationDrawablestart()方法开始动画。

本例要实现对ImageView对象进行渐变尺寸缩放动画效果

1>在项目的res目录下创建文件夹anim,然后在anim文件夹下面定义动画XML文件,文件名称可以自定义,如:scale.xml,内容如下:

<?xmlversion="1.0"encoding="utf-8"?>

<setxmlns:android="http://schemas.android.com/apk/res/android">

<scaleandroid: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%为物件的XY方向坐标上的中点位置

duration(长整型)属性为动画持续时间。说明:时间以毫秒为单位

2>layout文件添加<ImageView>节点:

<?xmlversion="1.0"encoding="utf-8"?>

<LinearLayoutxmlns: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使用前面定义好的动画效果:

publicclassAnimationActivityextendsActivity{

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

ImageViewimageView=(ImageView)this.findViewById(R.id.imageView);

//加载动画XML文件,生成动画指令

Animationanimation=AnimationUtils.loadAnimation(this,R.anim.scale);

//开始执行动画

imageView.startAnimation(animation);

}

}

备注:上面采用的是xml文件定义动画效果,作为代替,也可以采用编码方式实现。下面采用编码方式实现上述例子同样的效果:

publicclassAnimationActivityextendsActivity{

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

ImageViewimageView=(ImageView)this.findViewById(R.id.imageView);

ScaleAnimationanimation=newScaleAnimation(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);

}

}

其他动画效果定义例子:

=================渐变透明度动画效果======================

<?xmlversion="1.0"encoding="utf-8"?>

<setxmlns:android="http://schemas.android.com/apk/res/android">

<alpha

android:fromAlpha="0.1"

android:toAlpha="1.0"

android:duration="3000"

/>

</set>

编码实现透明度动画效果:

publicclassAnimationActivityextendsActivity{

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

ImageViewimageView=(ImageView)this.findViewById(R.id.imageView);

AlphaAnimationanimation=newAlphaAnimation(0.1,1.0);

animation.setDuration(5000);//设置持续时间5

imageView.startAnimation(animation);

}

}

=================画面位置移动动画效果======================

<?xmlversion="1.0"encoding="utf-8"?>

<setxmlns: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"

/>

<!--fromXDeltafromYDelta为动画起始时XY坐标上的位置

toXDeltatoYDelta为动画结束起始时XY坐标上的位置

-->

</set>

编码实现位置移动动画效果:

publicclassAnimationActivityextendsActivity{

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

ImageViewimageView=(ImageView)this.findViewById(R.id.imageView);

TranslateAnimationanimation=newTranslateAnimation(0,120,0,120);

animation.setDuration(5000);//设置持续时间5

imageView.startAnimation(animation);

=================画面旋转动画效果======================

<?xmlversion="1.0"encoding="utf-8"?>

<setxmlns: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为动画相对于物件的XY坐标的开始位.说明:以上两个属性值从0%-100%中取值,50%为物件的XY方向坐标上的中点位置

-->

</set>

编码实现:

RotateAnimationanimation=newRotateAnimation(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

<?xmlversion="1.0"encoding="utf-8"?>

<animation-listxmlns:android="http://schemas.android.com/apk/res/android"

android:oneshot="false">

<itemandroid:drawable="@drawable/girl_1"android:duration="200"/>

<itemandroid:drawable="@drawable/girl_2"android:duration="200"/>

<itemandroid: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控件绑定动画效果,调用代表动画的AnimationDrawablestart()方法开始动画。

publicclassFrameActivityextendsActivity{

privateAnimationDrawableanimationDrawable;

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

ImageViewimageView=(ImageView)this.findViewById(R.id.imageView);

imageView.setBackgroundResource(R.anim.frame);

animationDrawable=(AnimationDrawable)imageView.getBackground();

}

@Override

publicbooleanonTouchEvent(MotionEventevent){

if(event.getAction()==MotionEvent.ACTION_DOWN){//按下

animationDrawable.start();

returntrue;

}

returnsuper.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

//获取某种类型的感应器

Sensorsensor=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

一般对于屏幕方向自动旋转使用,相对节省电能和逻辑处理,一般游戏开发中我们不使用。


下面介绍如何获取加速度(重力)传感器和方向传感器的测量值:

publicclassMainActivityextendsActivity{

privateTextViewaccelerometer;

privateTextVieworientation;

privateSensorManagersensorManager;

@Override

publicvoidonCreate(BundlesavedInstanceState){

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

protectedvoidonResume(){

Sensorsensor=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);//获取重力加速度传感器

sensorManager.registerListener(listener,sensor,SensorManager.SENSOR_DELAY_GAME);

Sensorsensor1=sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);//获取方向传感器

sensorManager.registerListener(listener,sensor1,SensorManager.SENSOR_DELAY_GAME);

super.onResume();

}

@Override

protectedvoidonPause(){

sensorManager.unregisterListener(listener);//注消所有传感器监听

super.onPause();

}

privateSensorEventListenerlistener=newSensorEventListener(){

@Override

publicvoidonSensorChanged(SensorEventevent){//当传感器的值发生变化

floatx=event.values[SensorManager.DATA_X];

floaty=event.values[SensorManager.DATA_Y];

floatz=event.values[SensorManager.DATA_Z];

switch(event.sensor.getType()){

caseSensor.TYPE_ACCELEROMETER:

accelerometer.setText("AccelerometerSensor:"+x+","+y+","+z);

break;

caseSensor.TYPE_ORIENTATION:

/*x该值表示方位,0代表北(North);90代表东(East);180代表南(South);270代表西(West

如果x值正好是这4个值之一,并且手机是水平放置,手机的顶部对准的方向就是该值代表的方向。

y值表示倾斜度,或手机翘起的程度。当手机绕着X轴倾斜时该值发生变化。y值的取值范围是-180y值≤180

假设将手机屏幕朝上水平放在桌子上,这时如果桌子是完全水平的,y值应该是0(由于很少有桌子是绝对水平的,

因此,该值很可能不为0,但一般都是-55之间的某个值)。这时从手机顶部开始抬起,直到将手机沿X轴旋转180度(屏幕向下水平放在桌面上)。

在这个旋转过程中,y值会在0-180之间变化,也就是说,从手机顶部抬起时,y的值会逐渐变小,

直到等于-180。如果从手机底部开始抬起,直到将手机沿X轴旋转180度,这时y值会在0180之间变化。

也就是y值会逐渐增大,直到等于180。可以利用y值和z值来测量桌子等物体的倾斜度。

y值表示倾斜度,或手机翘起的程度。当手机绕着X轴倾斜时该值发生变化。y值的取值范围是-180y值≤180

假设将手机屏幕朝上水平放在桌子上,这时如果桌子是完全水平的,y值应该是0(由于很少有桌子是绝对水平的,

因此,该值很可能不为0,但一般都是-55之间的某个值)。这时从手机顶部开始抬起,直到将手机沿X轴旋转180度(屏幕向下水平放在桌面上)。

在这个旋转过程中,y值会在0-180之间变化,也就是说,从手机顶部抬起时,y的值会逐渐变小,

直到等于-180。如果从手机底部开始抬起,直到将手机沿X轴旋转180度,这时y值会在0180之间变化。

也就是y值会逐渐增大,直到等于180。可以利用y值和z值来测量桌子等物体的倾斜度。

因此,该值很可能不为0,但一般都是-55之间的某个值)。这时从手机顶部开始抬起,直到将手机沿X轴旋转180度(屏幕向下水平放在桌面上)。

在这个旋转过程中,y值会在0-180之间变化,也就是说,从手机顶部抬起时,y的值会逐渐变小,

直到等于-180。如果从手机底部开始抬起,直到将手机沿X轴旋转180度,这时y值会在0180之间变化。

也就是y值会逐渐增大,直到等于180。可以利用y值和z值来测量桌子等物体的倾斜度。

z值表示手机沿着Y轴的滚动角度。表示手机沿着Y轴的滚动角度。取值范围是-90z值≤90

假设将手机屏幕朝上水平放在桌面上,这时如果桌面是平的,z值应为0。将手机左侧逐渐抬起时,

z值逐渐变小,直到手机垂直于桌面放置,这时z值是-90。将手机右侧逐渐抬起时,z值逐渐增大,

直到手机垂直于桌面放置,这时z值是90。在垂直位置时继续向右或向左滚动,z值会继续在-9090之间变化。

*/

orientation.setText("OrientationSensor:"+x+","+y+","+z);

break;

}

}

@Override

publicvoidonAccuracyChanged(Sensorsensor,intaccuracy){//当传感器的精度变化时

}

};

}

21、NinePatch图片

NinePatch是一种很有用的PNG图片格式,它可以在特定区域随文字大小进行缩放。如下:

从上图可以看到,背景图片的中间区域会随着文字的大小进行缩放。背景图片是一张NinePatch图片。NinePatch图片可以使用android自带的draw9patch工具来制作,该工具在SDK安装路径的tools目录下。执行该工具,然后点击“File->open9-path”打开一张用于制作NinePatch图片的原来图片。在画布的上方和左方的边上画线指定缩放区域,

勾选“Showpatches”可显示画定的区域,绿色

为固定大小区域,红色为缩放区域,文字会摆放在红色

区域。制作完后,点击“File”à“save9-path”保存

图片,draw9patch工具会自动为图片加上*.9.png后缀。

把制作好的图片拷贝进项目的res/drawable目录,然后

编写代码。如下:

<TextViewandroid:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="退出"android:textColor="#330000"

android:background="@drawable/button"/>

22、关闭应用

当应用不再使用时,通常需要关闭应用,可以使用以下三种方法关闭android应用:

第一种方法:首先获取当前进程的id,然后杀死该进程。

android.os.Process.killProcess(android.os.Process.myPid())

第二种方法:终止当前正在运行的Java虚拟机,导致程序终止

System.exit(0);

第三种方法:强制关闭与该包有关联的一切执行

ActivityManagermanager=(ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);

manager.restartPackage(getPackageName());

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

23、判断SIM卡属于哪个移动运营商

在文件AndroidManifest.xml中添加权限

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

第一种方法:

获取手机的IMSI,并判断是中国移动\中国联通\中国电信

TelephonyManagertelManager=(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);

/**获取SIM卡的IMSI

*SIM卡唯一标识:IMSI国际移动用户识别码(IMSIInternationalMobileSubscriberIdentificationNumber)是区别移动用户的标志,

*储存在SIM卡中,可用于区别移动用户的有效信息。IMSIMCCMNCMSIN组成,其中MCC为移动国家号码,由3位数字组成,

*唯一地识别移动客户所属的国家,我国为460MNC为网络id,由2位数字组成,

*用于识别移动客户所归属的移动网络,中国移动为00,中国联通为01,中国电信为03MSIN为移动客户识别码,采用等长11位数字构成。

*唯一地识别国内GSM移动通信网中移动客户。所以要区分是移动还是联通,只需取得SIM卡中的MNC字段即可

*/

Stringimsi=telManager.getSubscriberId();

if(imsi!=null){

if(imsi.startsWith("46000")||imsi.startsWith("46002")){//因为移动网络编号46000下的IMSI已经用完,所以虚拟了一个46002编号,134/159号段使用了此编号

//中国移动

}elseif(imsi.startsWith("46001")){

//中国联通

}elseif(imsi.startsWith("46003")){

//中国电信

}

}

第二种方法

TelephonyManagertelManager=(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);

Stringoperator=telManager.getSimOperator();

if(operator!=null){

if(operator.equals("46000")||operator.equals("46002")){

//中国移动

}elseif(operator.equals("46001")){

//中国联通

}elseif(operator.equals("46003")){

//中国电信

}

}

24、从SIM卡中获取联系人信息

Uriuri=Uri.parse("content://icc/adn");

String[]projection={"_id","name","number"};

Cursorcursor=managedQuery(uri,projection,null,null,"name");

if(cursor!=null){

while(cursor.moveToNext()){

Stringname=cursor.getString(cursor.getColumnIndex("name"));

Stringphone=cursor.getString(cursor.getColumnIndex("number"));

}

}

在文件AndroidManifest.xml中添加权限

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

Android系统内部通过Contentprovider对外共享Sim卡存放的联系人等信息,你可以通过操作Contentprovider来实现Sim卡信息的添删改查操作。

packagecom.android.internal.telephony;

importandroid.content.ContentProvider;

importandroid.content.UriMatcher;

importandroid.content.ContentValues;

importcom.android.internal.database.ArrayListCursor;

importandroid.database.Cursor;

importandroid.net.Uri;

importandroid.os.SystemProperties;

importandroid.os.RemoteException;

importandroid.os.ServiceManager;

importandroid.text.TextUtils;

importandroid.util.Log;

importjava.util.ArrayList;

importjava.util.List;

importcom.android.internal.telephony.IccConstants;

importcom.android.internal.telephony.AdnRecord;

importcom.android.internal.telephony.IIccPhoneBook;

publicclassIccProviderextendsContentProvider{

privatestaticfinalStringTAG="IccProvider";

privatestaticfinalbooleanDBG=false;

privatestaticfinalString[]ADDRESS_BOOK_COLUMN_NAMES=newString[]{

"name",

"number"

};

privatestaticfinalintADN=1;

privatestaticfinalintFDN=2;

privatestaticfinalintSDN=3;

privatestaticfinalStringSTR_TAG="tag";

privatestaticfinalStringSTR_NUMBER="number";

privatestaticfinalStringSTR_PIN2="pin2";

privatestaticfinalUriMatcherURL_MATCHER=newUriMatcher(UriMatcher.NO_MATCH);

static{

URL_MATCHER.addURI("icc","adn",ADN);

URL_MATCHER.addURI("icc","fdn",FDN);

URL_MATCHER.addURI("icc","sdn",SDN);

}

privatebooleanmSimulator;

@Override

publicbooleanonCreate(){

Stringdevice=SystemProperties.get("ro.product.device");

if(!TextUtils.isEmpty(device)){

mSimulator=false;

}else{

//simulator

mSimulator=true;

}

returntrue;

}

@Override

publicCursorquery(Uriurl,String[]projection,Stringselection,

String[]selectionArgs,Stringsort){

ArrayList<ArrayList>results;

if(!mSimulator){

switch(URL_MATCHER.match(url)){

caseADN:

results=loadFromEf(IccConstants.EF_ADN);

break;

caseFDN:

results=loadFromEf(IccConstants.EF_FDN);

break;

caseSDN:

results=loadFromEf(IccConstants.EF_SDN);

break;

default:

thrownewIllegalArgumentException("UnknownURL"+url);

}

}else{

//Fakeupsomedataforthesimulator

results=newArrayList<ArrayList>(4);

ArrayList<String>contact;

contact=newArrayList<String>();

contact.add("RonStevens/H");

contact.add("512-555-5038");

results.add(contact);

contact=newArrayList<String>();

contact.add("RonStevens/M");

contact.add("512-555-8305");

results.add(contact);

results=newArrayList<ArrayList>(4);

ArrayList<String>contact;

contact=newArrayList<String>();

contact.add("RonStevens/H");

contact.add("512-555-5038");

results.add(contact);

contact=newArrayList<String>();

contact.add("RonStevens/M");

contact.add("512-555-8305");

results.add(contact);

contact.add("512-555-5038");

results.add(contact);

contact=newArrayList<String>();

contact.add("RonStevens/M");

contact.add("512-555-8305");

results.add(contact);

contact=newArrayList<String>();

contact.add("MelissaOwens");

contact.add("512-555-8305");

results.add(contact);

contact=newArrayList<String>();

contact.add("DirectoryAssistence");

contact.add("411");

results.add(contact);

}

returnnewArrayListCursor(ADDRESS_BOOK_COLUMN_NAMES,results);

}

@Override

publicStringgetType(Uriurl){

switch(URL_MATCHER.match(url)){

caseADN:

caseFDN:

caseSDN:

return"vnd.android.cursor.dir/sim-contact";

default:

thrownewIllegalArgumentException("UnknownURL"+url);

}

}

@Override

publicUriinsert(Uriurl,ContentValuesinitialValues){

UriresultUri;

intefType;

Stringpin2=null;

if(DBG)log("insert");

intmatch=URL_MATCHER.match(url);

switch(match){

caseADN:

efType=IccConstants.EF_ADN;

break;

caseFDN:

efType=IccConstants.EF_FDN;

pin2=initialValues.getAsString("pin2");

break;

default:

thrownewUnsupportedOperationException(

"CannotinsertintoURL:"+url);

}

Stringtag=initialValues.getAsString("tag");

Stringnumber=initialValues.getAsString("number");

booleansuccess=addIccRecordToEf(efType,tag,number,pin2);

if(!success){

returnnull;

}

StringBuilderbuf=newStringBuilder("content://im/");

switch(match){

caseADN:

buf.append("adn/");

break;

caseFDN:

buf.append("fdn/");

break;

}

//TODO:weneedtofindouttherowIdforthenewlyaddedrecord

buf.append(0);

resultUri=Uri.parse(buf.toString());

/*

//notifyinterestedpartiesthataninsertionhappened

getContext().getContentResolver().notifyInsert(

resultUri,rowID,null);

*/

returnresultUri;

}

privateStringnormalizeValue(StringinVal){

intlen=inVal.length();

StringretVal=inVal;

if(inVal.charAt(0)=='\''&&inVal.charAt(len-1)=='\''){

retVal=inVal.substring(1,len-1);

}

returnretVal;

}

@Override

publicintdelete(Uriurl,Stringwhere,String[]whereArgs){

intefType;

if(DBG)log("delete");

intmatch=URL_MATCHER.match(url);

switch(match){

caseADN:

efType=IccConstants.EF_ADN;

break;

caseFDN:

efType=IccConstants.EF_FDN;

break;

default:

thrownewUnsupportedOperationException(

"CannotinsertintoURL:"+url);

}

//parsewhereclause

Stringtag=null;

Stringnumber=null;

Stringpin2=null;

String[]tokens=where.split("AND");

intn=tokens.length;

while(--n>=0){

Stringparam=tokens[n];

if(DBG)log("parsing'"+param+"'");

String[]pair=param.split("=");

if(pair.length!=2){

Log.e(TAG,"resolve:badwhereClauseparameter:"+param);

continue;

}

Stringkey=pair[0].trim();

Stringval=pair[1].trim();

if(STR_TAG.equals(key)){

tag=normalizeValue(val);

}elseif(STR_NUMBER.equals(key)){

number=normalizeValue(val);

}elseif(STR_PIN2.equals(key)){

pin2=normalizeValue(val);

}

}

if(TextUtils.isEmpty(tag)){

return0;

}

if(efType==FDN&&TextUtils.isEmpty(pin2)){

return0;

}

booleansuccess=deleteIccRecordFromEf(efType,tag,number,pin2);

if(!success){

return0;

}

return1;

}

@Override

publicintupdate(Uriurl,ContentValuesvalues,Stringwhere,String[]whereArgs){

intefType;

Stringpin2=null;

if(DBG)log("update");

intmatch=URL_MATCHER.match(url);

switch(match){

caseADN:

efType=IccConstants.EF_ADN;

break;

caseFDN:

efType=IccConstants.EF_FDN;

pin2=values.getAsString("pin2");

break;

default:

thrownewUnsupportedOperationException(

"CannotinsertintoURL:"+url);

}

Stringtag=values.getAsString("tag");

Stringnumber=values.getAsString("number");

StringnewTag=values.getAsString("newTag");

StringnewNumber=values.getAsString("newNumber");

booleansuccess=updateIccRecordInEf(efType,tag,number,

newTag,newNumber,pin2);

if(!success){

return0;

}

return1;

}

privateArrayList<ArrayList>loadFromEf(intefType){

ArrayList<ArrayList>results=newArrayList<ArrayList>();

List<AdnRecord>adnRecords=null;

if(DBG)log("loadFromEf:efType="+efType);

try{

IIccPhoneBookiccIpb=IIccPhoneBook.Stub.asInterface(

ServiceManager.getService("simphonebook"));

if(iccIpb!=null){

adnRecords=iccIpb.getAdnRecordsInEf(efType);

}

}catch(RemoteExceptionex){

//ignoreit

}catch(SecurityExceptionex){

if(DBG)log(ex.toString());

}

if(adnRecords!=null){

//Loadtheresults

intN=adnRecords.size();

if(DBG)log("adnRecords.size="+N);

for(inti=0;i<N;i++){

loadRecord(adnRecords.get(i),results);

}

}else{

//Noresultstoload

Log.w(TAG,"CannotloadADNrecords");

results.clear();

}

if(DBG)log("loadFromEf:returnresults");

returnresults;

}

privateboolean

addIccRecordToEf(intefType,Stringname,Stringnumber,Stringpin2){

if(DBG)log("addIccRecordToEf:efType="+efType+",name="+name+

",number="+number);

booleansuccess=false;

//TODO:doweneedtocallgetAdnRecordsInEf()beforecalling

//updateAdnRecordsInEfBySearch()?Inanycase,wewillleave

//theUIlevellogictofillthatprereqifnecessary.But

//hopefully,wecanremovethisrequirement.

try{

IIccPhoneBookiccIpb=IIccPhoneBook.Stub.asInterface(

ServiceManager.getService("simphonebook"));

if(iccIpb!=null){

success=iccIpb.updateAdnRecordsInEfBySearch(efType,"","",

name,number,pin2);

}

}catch(RemoteExceptionex){

//ignoreit

}catch(SecurityExceptionex){

if(DBG)log(ex.toString());

}

if(DBG)log("addIccRecordToEf:"+success);

returnsuccess;

}

privateboolean

updateIccRecordInEf(intefType,StringoldName,StringoldNumber,

StringnewName,StringnewNumber,Stringpin2){

if(DBG)log("updateIccRecordInEf:efType="+efType+

",oldname="+oldName+",oldnumber="+oldNumber+

",newname="+newName+",newnumber="+newNumber);

booleansuccess=false;

try{

IIccPhoneBookiccIpb=IIccPhoneBook.Stub.asInterface(

ServiceManager.getService("simphonebook"));

if(iccIpb!=null){

success=iccIpb.updateAdnRecordsInEfBySearch(efType,

oldName,oldNumber,newName,newNumber,pin2);

}

}catch(RemoteExceptionex){

//ignoreit

}catch(SecurityExceptionex){

if(DBG)log(ex.toString());

}

if(DBG)log("updateIccRecordInEf:"+success);

returnsuccess;

}

privatebooleandeleteIccRecordFromEf(intefType,Stringname,Stringnumber,Stringpin2){

if(DBG)log("deleteIccRecordFromEf:efType="+efType+

",name="+name+",number="+number+",pin2="+pin2);

booleansuccess=false;

try{

IIccPhoneBookiccIpb=IIccPhoneBook.Stub.asInterface(

ServiceManager.getService("simphonebook"));

if(iccIpb!=null){

success=iccIpb.updateAdnRecordsInEfBySearch(efType,

name,number,"","",pin2);

}

}catch(RemoteExceptionex){

//ignoreit

}catch(SecurityExceptionex){

if(DBG)log(ex.toString());

}

if(DBG)log("deleteIccRecordFromEf:"+success);

returnsuccess;

}

name,number,"","",pin2);

}

}catch(RemoteExceptionex){

//ignoreit

}catch(SecurityExceptionex){

if(DBG)log(ex.toString());

}

if(DBG)log("deleteIccRecordFromEf:"+success);

returnsuccess;

}

name,number,"","",pin2);

}

}catch(RemoteExceptionex){

//ignoreit

}catch(SecurityExceptionex){

if(DBG)log(ex.toString());

}

if(DBG)log("deleteIccRecordFromEf:"+success);

returnsuccess;

}

25删除呼叫记录

在文件AndroidManifest.xml中添加权限

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

<uses-permissionandroid: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

删除指定号码的来电或未接呼叫记录:

IncomingCallLogContentObserverobserver=newIncomingCallLogContentObserver(newHandler());

observer.setNumber("5554");

getContentResolver().registerContentObserver(CallLog.Calls.CONTENT_URI,true,observer);

privateclassIncomingCallLogContentObserverextendsContentObserver{

privateStringnumber;

publicIncomingCallLogContentObserver(Handlerhandler){

super(handler);

}

publicvoidsetNumber(Stringnumber){

this.number=number;

}

publicvoidonChange(booleanparamBoolean){

ContentResolvercontentResolver=getContentResolver();

if(number!=null){

UrilocalUri=CallLog.Calls.CONTENT_URI;

Cursorcursor=contentResolver.query(localUri,newString[]{"_id"},"number=?AND(type=1ORtype=3)",

newString[]{number},"_iddesclimit1");

if(cursor.moveToFirst()){

contentResolver.delete(localUri,"_id=?",newString[]{cursor.getString(0)});

}

cursor.close();

}

contentResolver.unregisterContentObserver(this);

}

}

26在应用中安装其他程序

首先需要AndroidManifest.xml中加入安装程序权限:

<!--安装程序权限-->

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

第二步把安装程序添加进SDCard。如把文件名为”sogouinput_android_1.40_sweb.apk.zip”的sogou拼音输入法安装文件放进SDCard。可以点击下面按钮:

第三步在程序中添加以下代码:

Intentintent=newIntent();

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

intent.setAction(android.content.Intent.ACTION_VIEW);

intent.setDataAndType(Uri.fromFile(newFile(Environment.getExternalStorageDirectory(),"sogouinput_android_1.40_sweb.apk.zip")),"application/vnd.android.package-archive");

startActivity(intent);

27、如何反编绎APK文件

安装ApkTool工具,该工具可以解码得到资源文件,但不能得到Java源文件。

安装环境:需要安装JRE1.6

1>http://code.google.com/p/android-apktool/下载apktool1.3.2.tar.bz2apktool-install-windows-2.2_r01-3.tar.bz2文件。解压两个文件,然后把解压后的文件放在一起,如:c:\apktool

2>在系统变量PATH中添加进aapt.exe,如:;c:\apktool\aapt.exe

3>DOS窗口下进入apktool.jar所在目录。执行DOS命令:apktoold-sc:\soft\xxx.apkc:\soft\source

命令格式:apktoold[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.batc:\soft\source\classes.dexc:\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源代码。

28、如何防止我们的代码被反编译

由于apkAndroid虚拟机加载的,它有一定的规范,加密apkDalvik无法

识别apk了。完全避免是不可能的,总有人能够破解你的代码。但是有几种

方式来提高被反编译取代码的难度。

1关键代码使用jni调用本地代码,用c或者c++编写,因此相对比较难于反

编译

2混淆java代码。混淆是不改变代码逻辑的情况下,增加无用代码,或者重

命名,使反编译后的源代码难于看懂。

网上开源的java代码混淆工具较多,一般是用ant的方式来编译的

更多相关文章

  1. Android(安卓)通过WebView 调用Js sqlite数据库
  2. 初学Android,五大布局对象(六)
  3. Test
  4. Android(安卓)UI设计的三种常见布局(LinearLayout、RelativeLayou
  5. Android(安卓)11适配指南之Toast解析
  6. android 全屏 webview 加载的h5的输入框,被键盘遮挡的解决
  7. Android——GSON解析JSON
  8. android APP隐私政策弹框的实现代码实例
  9. android手机打电话代码分析

随机推荐

  1. 浅谈android的mount命令
  2. [置顶] 搜集整理的一些博客导航
  3. Android(安卓)- 小功能 - Android中dp和p
  4. Android工程引用另外一个工程的正确/错误
  5. Android真机测试,Find Explorer无法打开da
  6. Android混合开发(一)——移动端与前端交互
  7. [置顶] Android仿UC浏览器左右上下滚动功
  8. Android图片压缩小结
  9. android 可拖动排序的源码示例
  10. android imageview围绕中心旋转动画