Android軟體開發之應用程式之間的通訊介紹
Android 開發中在程式之間通訊的介面做的還是非常豐富的本例主要向大家介紹程式之間是如何進行溝通,有哪幾種溝通方式如何來實現溝通。
1. 使用handler傳遞訊息
handler 大家可以把它想象成主執行緒(UI執行緒)的一個子執行緒,它可以給主執行緒(UI執行緒)傳送資料從而更新主執行緒(UI執行緒)的UI與邏輯,handler是一個子執行緒所以它的耗時操作不會阻塞主執行緒,大家都知道在android的開發中如果程式碼中某個地方阻塞主執行緒超過5秒的話系統會提示ANR (系統提示強制關閉)所以在耗時操作上我們可以考慮開啟一個子執行緒避免ANR。 handler會向主執行緒傳送訊息會以佇列的形式排列著配合等待主執行緒更新UI
下面這個例子詮釋了這一點利用handler傳遞訊息來更新主執行緒的UI顯示內容點選按鈕後每過一秒通過handler傳送訊息更新UI執行緒顯示的時間直到顯示時間更新到10然後結束這個執行緒。
package com.example.handleractivity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity implements Runnable{ public final static int UPDATE_TIME =0; public final static int UPDATE_COMPLETED =1; private int mShowNumber = 0; private Button mButton = null; private TextView mTextView = null; private Thread mThread = null; private boolean mRunning = false; @Override protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); mButton = (Button)findViewById(R.id.button0); mTextView = (TextView)findViewById(R.id.textView0); mThread = new Thread(this); mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub mRunning = true; mThread.start(); } }); mTextView.setText("點選按鈕開始更新時間"); super.onCreate(savedInstanceState); } @Override public void run() { // TODO Auto-generated method stub while (mRunning) { try { mShowNumber++; Bundle bandle = new Bundle(); bandle.putString("number", String.valueOf(mShowNumber)); Message msg = new Message(); if(mShowNumber <=10) { msg.what = UPDATE_TIME; }else { mRunning = false; msg.what = UPDATE_COMPLETED; } msg.setData(bandle); handler.sendMessage(msg); Thread.sleep(1000); }catch (InterruptedException e) { e.printStackTrace(); } } } Handler handler = new Handler() { public void handleMessage(Message msg) { Bundle bundle= msg.getData(); String number = bundle.getString("number"); switch(msg.what) { case UPDATE_TIME: mTextView.setText("正在更新時間" + number); break; case UPDATE_COMPLETED: mTextView.setText("更新完畢"); break; } super.handleMessage(msg); } }; public void ShowDialog(String string) { AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setIcon(R.drawable.ic_launcher); builder.setTitle(string); builder.setPositiveButton("確定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { // TODO Auto-generated method stub finish(); } }); builder.show(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
2. Notifation通知欄資訊
Notifation通知欄會在螢幕上方向使用者提示資訊但是不會打斷使用者正在閱讀的內容,除非使用者手動將 Notifation通知欄拉下。 Notifation的好處就是在於不會影響使用者的操作,比如使用者正在閱讀非常重要的資訊這時候幫他直接開啟一個activity會非常不合適因為直接影響到了他當時的操作行為所以Notifation就出來了。建議大家在開發中遇到可能打斷使用者使用的情況下都去使用Notifation通知欄。
package com.example.notificationactivity; import android.os.Bundle; import android.app.Activity; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Intent; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { NotificationManager mManager = null; Notification notification =null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); notification = new Notification(R.drawable.icon, "Android專業開發群", System.currentTimeMillis()); notification.flags = Notification.FLAG_AUTO_CANCEL; Intent intent = new Intent(this, MyShowActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_NEW_TASK); Bundle bundle = new Bundle(); bundle.putString("name", "從Notification轉跳過來的"); intent.putExtras(bundle); PendingIntent contentIntent = PendingIntent.getActivity(this, R.string.app_name, intent, PendingIntent.FLAG_UPDATE_CURRENT); notification.setLatestEventInfo(this, "Android專業開發群","QQ群號 164257885", contentIntent); Button button0 = (Button)findViewById(R.id.button1); button0.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub mManager.notify(0, notification); } }); Button button1 = (Button)findViewById(R.id.button2); button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub mManager.cancelAll(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
3. 廣播的傳送與接收
Android開發中如果須要對兩個完全沒關係的程式之間進行通訊就可以使用傳送廣播與接收廣播的機制來實現,例如程式A傳送了一個廣播程式B接受到做一些事情這樣就達到了相互的通訊。
呼叫sendBroadcast()傳入intent後來傳送廣播。
package com.example.broadcastactivity;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
public final static String SEND_OK_MESSAGE = "send.ok.message";
public final static String SEND_CANCLE_MESSAGE = "send.cancle.message";
Button mButton0 = null;
Button mButton1 = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton0 = (Button)findViewById(R.id.button1);
mButton0.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent intent = new Intent(SEND_OK_MESSAGE);
intent.putExtra("name", "您傳送了OK這條廣播哦");
sendBroadcast(intent);
}
});
mButton1 = (Button)findViewById(R.id.button2);
mButton1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent(SEND_CANCLE_MESSAGE);
intent.putExtra("name", "您傳送了Cancle這條廣播哦");
sendBroadcast(intent);
}
});
//Intent i = new Intent(this, MyService.class);
//startService(i);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
接收廣播的話我們開啟一個service在service中通過BroadcastReceiver來接收廣播前提是須要接收的廣播須要在onStart()中註冊一下在AndroidManifest.xml中可以過濾只接收須要接收的廣播。
<service android:name=".MyService">
<intent-filter>
<action android:name="cn.m15.xys.MyService"></action>
</intent-filter>
<intent-filter>
<action android:name="send.ok.message" />
<action android:name="send.cancle.message" />
</intent-filter>
</service>
在onStart()中註冊了程式中所需要的兩個廣播。
package com.example.servicereceive;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.widget.Toast;
public class MyService extends Service {
public final static String SEND_OK_MESSAGE = "send.ok.message";
public final static String SEND_CANCLE_MESSAGE = "send.cancle.message";
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
public void onStart(Intent intent, int startId) {
IntentFilter myFilter = new IntentFilter();
myFilter.addAction(SEND_OK_MESSAGE);
myFilter.addAction(SEND_CANCLE_MESSAGE);
this.registerReceiver(myBroadCast, myFilter);
super.onStart(intent, startId);
}
private BroadcastReceiver myBroadCast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
if (action.equals(SEND_OK_MESSAGE)) {
Toast.makeText(context, "接收到了一條廣播為" + SEND_OK_MESSAGE, Toast.LENGTH_LONG).show();
}else if(action.equals(SEND_CANCLE_MESSAGE)) {
Toast.makeText(context, "接收到了一條廣播為" + SEND_CANCLE_MESSAGE, Toast.LENGTH_LONG).show();
}
}
};
}
這裡注意一下service如果沒有起來我們是接收不到廣播的所以一定要保證接收的時候service是開啟的,上例中的service是在開啟activity時開啟的但是如果使用者把手機關掉然後在開機,這樣的話service就不是開啟狀態這樣就非常危險了因為這時scrvice就接收不到任何訊息了除非使用者再次進activity才會幫他開啟scrvice所以我們可以在使用者開機後就直接將scrvice開啟,具體的實現方式如下。
在AndroidManifest.xml中註冊一個開機廣播這個廣播系統只會在開機發出而且只會發出一次所以我們接收這個廣播就可以知道手機是否為開機狀態。
<receiver android:name=".MyBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
注意加入許可權。
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
在BroadcastRecevier中接收開機廣播然後開啟service就可以實現開機啟動service。
package com.example.servicereceive;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MyBootReceiver extends BroadcastReceiver {
static final String BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if (intent.getAction().equals(BOOT_COMPLETED)) {
Intent i = new Intent(context, MyService.class);
context.startService(i);
}
}
}
4. Activity與Activity之間的轉跳
在軟體應用的開發中肯定會有多個Activity這樣它們之間就會存在相互轉跳的關係轉跳的實現方式還是使用Intent 然後startActivity ,當然轉跳的話是可以帶資料過去的。比如從A跳到B可以把A中的一些資料通過Intent傳遞給B。
讀下面這段程式碼大家會發現intent與bandle傳遞數值的方式基本一樣為什麼還要分成兩個呢?確實他們兩個傳遞的數值的方式非常類似,他們兩個的區別就是Intent屬於把零散的資料傳遞過去而bundle則是把零散的資料先放入bundle然後在傳遞過去。我舉一個例子比如我們現在有3個activity A.B.C須要把A的資料穿給B然後在穿給C,如果使用intent一個一個傳遞須要在A類中一個一個傳遞給B然後B類中獲取到所有數值然後在一個一個傳遞給C這樣很麻煩但是如果是bundle的話 B類中直接將bundler傳遞給C不用一個一個獲得具體的值然後在C類中直接取得解析數值。
package com.example.activityactivity;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button botton3 = (Button)findViewById(R.id.button1);
botton3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent intent = new Intent(MainActivity.this, ShowActivity.class);
intent.putExtra("name", "雨鬆MOMO");
intent.putExtra("age", 25);
intent.putExtra("boy", true);
Bundle bundle = new Bundle();
bundle.putString("b_name", "小可愛");
bundle.putInt("b_age", 23);
bundle.putBoolean("b_boy", false);
intent.putExtras(bundle);
startActivity(intent);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
接收
package com.example.activityactivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
public class ShowActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.my);
Intent intent = getIntent();
String name = intent.getStringExtra("name");
int age = intent.getIntExtra("age", 0);
boolean isboy = intent.getBooleanExtra("boy", false);
TextView textView0 = (TextView)findViewById(R.id.textView1);
textView0.setText("姓名 " + name + "年齡 " + age + "男孩? " + isboy);
Bundle bundle = intent.getExtras();
name = bundle.getString("b_name");
age = bundle.getInt("b_age",0);
isboy = bundle.getBoolean("b_boy", false);
TextView textView1 = (TextView)findViewById(R.id.textView2);
textView1.setText("姓名 " + name + "年齡 " + age + "男孩? " + isboy);
super.onCreate(savedInstanceState);
}
}