Android核心基礎(十一)

一、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)

 

要完成單選框顯示,咱們須要使用到RadioGroupRadioButton(單選框)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,又能實現咱們的需求,那是最好不過的了。經過觀察ArrayAdaptergetView(int position, View convertView, ViewGroup parent)的內部代碼發現,若是爲ArrayAdapter指定的實際泛型參數類型沒有實現CharSequence(字符串)接口,將會調用該類型對象的toString()向下拉列表框輸出顯示值。利用這個特色咱們能夠重寫javaBeantoString()向下拉列表框提供顯示值。

界面設計:

<?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,第三個參數爲TextViewlayout文件的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)

 

重寫ActivityonCreateOptionsMenu(Menu menu)方法,該方法用於建立選項菜單,在用戶按下手機的「Menu」按鈕時就會顯示建立好的菜單,在onCreateOptionsMenu(Menu menu)方法內部能夠調用Menu.add()方法實現菜單的添加。

重寫ActivityonMenuItemSelected()方法,該方法用於處理菜單被選擇事件

經過手機上提供的「MENU」按鈕能夠打開菜單,若是但願經過代碼打開菜單,能夠調用ActivityopenOptionsMenu()方法。

 

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 

AutoCompleteTextViewEditText組件相似,均可以輸入文本。

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,如:EditTextTextView等;主題經過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控件綁定動畫效果。調用表明動畫的AnimationDrawablestart()方法開始動畫。

本例要實現對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%爲物件的XY方向座標上的中點位置

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 爲動畫起始時 XY座標上的位置

toXDelta toYDelta爲動畫結束起始時  XY座標上的位置

 -->

</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  爲動畫相對於物件的XY座標的開始位.說明:以上兩個屬性值 從0%-100%中取值,50%爲物件的XY方向座標上的中點位置

 -->

</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控件綁定動畫效果,調用表明動畫的AnimationDrawablestart()方法開始動畫。

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值的取值範圍是-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("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 國際移動用戶識別碼(IMSIInternational Mobile Subscriber Identification Number)是區別移動用戶的標誌,

         * 儲存在SIM卡中,可用於區別移動用戶的有效信息。IMSIMCCMNCMSIN組成,其中MCC爲移動國家號碼,由3位數字組成,

         * 惟一地識別移動客戶所屬的國家,我國爲460MNC爲網絡id,由2位數字組成,

         * 用於識別移動客戶所歸屬的移動網絡,中國移動爲00,中國聯通爲01,中國電信爲03MSIN爲移動客戶識別碼,採用等長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八、如何防止咱們的代碼被反編譯

因爲apkAndroid虛擬機加載的,它有必定的規範,加密apkDalvik沒法

識別apk了。徹底避免是不可能的,總有人可以破解你的代碼。可是有幾種

方式來提升被反編譯取代碼的難度。

關鍵代碼使用jni調用本地代碼,用c或者c++編寫,所以相對比較難於反

   編譯

混淆java代碼。混淆是不改變代碼邏輯的狀況下,增長無用代碼,或者重

   命名,使反編譯後的源代碼難於看懂。

   網上開源的java代碼混淆工具較多,通常是用ant的方式來編譯的

相關文章
相關標籤/搜索