編輯:關於Android編程
除非我們特別為某個操作指定特定的線程,否則大部分在前台UI界面上的操作任務都執行在一個叫做UI Thread的特殊線程中。這可能存在某些隱患,因為部分在UI界面上的耗時操作可能會影響界面的響應性能。UI界面的性能問題會容易惹惱用戶,甚至可能導致系統ANR錯誤。為了避免這樣的問題,Android Framework提供了幾個類,用來幫助你把那些耗時操作移動到後台線程中執行。那些類中最常用的就是IntentService.
IntentService為在單一後台線程中執行任務提供了一種直接的實現方式。它可以處理一個耗時的任務並確保不影響到UI的響應性。另外IntentService的執行還不受UI生命周期的影響,以此來確保AsyncTask能夠順利運行。
但是IntentService有下面幾個局限性:
不可以直接和UI做交互。為了把他執行的結果體現在UI上,需要把結果返回給Activity。
工作任務隊列是順序執行的,如果一個任務正在IntentService中執行,此時你再發送一個新的任務請求,這個新的任務會一直等待直到前面一個任務執行完畢才開始執行。
正在執行的任務無法打斷。
雖然有上面那些限制,然而在在大多數情況下,IntentService都是執行簡單後台任務操作的理想選擇。
Step 1: 為你的app創建一個IntentService組件,需要自定義一個新的類,它繼承自IntentService,並重寫onHandleIntent()方法,如下所示:
public class RSSPullService extends IntentService { @Override protected void onHandleIntent(Intent workIntent) { // 這裡可以得到傳進來的intent,就可以獲得intent所攜帶的數據 String dataString = workIntent.getDataString(); ... // 對獲得的數據進行操作,比如一些耗時的網絡操作 ... } }
注意:一個普通Service組件的其他回調,例如onCreate()、onStartCommand()會被IntentService自動調用。在IntentService中,要避免重寫那些回調。
Step 2:在Manifest文件中定義IntentService
IntentService需要在manifest文件添加相應的條目如下所示:
......
注意
至此,你已經有了一個基本的IntentService類,你可以通過構造Intent對象向它發送操作請求。
創建任務請求並發送到IntentService
為了創建一個任務請求並發送到IntentService。需要先創建一個顯式Intent,並將請求數據添加到intent中,然後通過調用 startService() 方法把任務請求數據發送到IntentService。
下面是代碼的示例:
創建一個新的顯式Intent用來啟動IntentService。
/*
* 創建一個Intent來啟動RSSPullService,把一個鏈接存放進intent中
*/
Intent mServiceIntent = new Intent(getActivity(), RSSPullService.class);
mServiceIntent.setData(Uri.parse(dataUrl));
執行startService()開啟服務
getActivity.startService(mServiceIntent);
注意:
可以在Activity或者Fragment的任何位置發送任務請求。例如,如果你先獲取用戶輸入,您可以從響應按鈕單擊或類似手勢的回調方法裡面發送任務請求。
一旦執行了startService(),IntentService在自己本身的onHandleIntent()方法裡面開始執行這個任務,任務結束之後,不需要使用stopService()方法來停止這個服務,因為IntentService會自動停止這個Service。
下一步是如何把工作任務的執行結果返回給發送任務的Activity或者Fragment。
利用IntentService將執行任務的結果返回給Activity或者Fragment
下面用一個實例來說明IntentService的一般工作步驟:
(1)在Activity中通過startService啟動service,並傳遞參數。
(2)Service中接收參數,做耗時的處理,處理完畢,發送Broadcat,並把處理結果傳遞出來
(3)Activity中注冊BroadcastReceiver,監聽廣播,更新UI。
Step 1:創建一個IntentService,接收參數
RSSPullService.java
public class RSSPullService extends IntentService {
//
public static final String BROADCAST_ACTION =
"com.example.android.threadsample.BROADCAST";
//構造方法必須重寫
public RSSPullService() {
super("RSSPullService");
}
@Override
protected void onHandleIntent(Intent workIntent) {
//接收參數,做耗時的處理,處理完畢,發送Broadcat
//將數據打印出來
Log.i(TAG,dataString);
//接收到數據,做耗時處理
String result = downloadHtml(dataString);
Log.i("result",result);
}
...
}
Step 2:在MainActivity中通過startService啟動IntentService,並傳遞參數
MainActivity.java
public class MainActivity extends AppCompatActivity {
MyReceiver receiver = new MyReceiver();
TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
regist();
bindView();
}
private void bindView() {
mTextView = (TextView)this.findViewById(R.id.textView);
Button button = (Button)this.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
//創建一個顯示Intent
Intent serviceIntent = new Intent(MainActivity.this,RSSPullService.class);
//將百度網址傳入Intent
serviceIntent.setData(Uri.parse("http://www.baidu.com"));
//啟動服務
startService(serviceIntent);
}
});
}
...
}
Step 3:在MainActivity中注冊廣播,這裡我們利用LocalBroadcastManager來注冊廣播,監聽廣播,
MainActivity.java
private void regist() {
IntentFilter intentFilter = new IntentFilter(RSSPullService.BROADCAST_ACTION);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, intentFilter);
}
//取消注冊
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
Step 4:在service中處理耗時操作,並發送Broadcat,並把處理結果傳遞出來
RssPullService.java
public class RSSPullService extends IntentService {
private static final String TAG = "RSSPullService";
public static final String EXTENDED_DATA_STATUS =
"com.example.android.threadsample.STATUS";
private LocalBroadcastManager mLocalBroadcastManager;
...
protected void onHandleIntent(Intent intent) {
...
//將耗時操作的結果放進Intent,調用LocalBroadcastManager.sendBroadcast將intent傳遞回去
Intent localIntent = new Intent(BROADCAST_ACTION);
localIntent.putExtra(EXTENDED_DATA_STATUS,result);
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
mLocalBroadcastManager.sendBroadcast(localIntent);
}
...
//處理耗時任務的方法
private String downloadHtml(String dataString) {
try {
URL url = new URL(dataString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
InputStream in = conn.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len = 0;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
in.close();
Log.i("html",out.toByteArray().toString());
return new String(out.toByteArray());
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
}
Step 5:在Activity中創建廣播,接收廣播,更新UI
MainActivity.java
private class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String data = intent.getStringExtra(RSSPullService.EXTENDED_DATA_STATUS);
Log.i("test", data);
mTextView.setText(data);
}
}
最後別忘了加上網絡權限:
執行結束,效果圖如下:
我把主要的幾個類的代碼放上來:
MainActivity.java :
public class MainActivity extends AppCompatActivity {
MyReceiver receiver = new MyReceiver();
TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
regist();
bindView();
}
private void regist() {
IntentFilter intentFilter = new IntentFilter(RSSPullService.BROADCAST_ACTION);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, intentFilter);
}
private void bindView() {
mTextView = (TextView)this.findViewById(R.id.textView);
Button button = (Button)this.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent serviceIntent = new Intent(MainActivity.this,RSSPullService.class);
serviceIntent.setData(Uri.parse("http://www.baidu.com"));
startService(serviceIntent);
}
});
}
private class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String data = intent.getStringExtra(RSSPullService.EXTENDED_DATA_STATUS);
Log.i("test", data);
mTextView.setText(data);
}
}
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
}
RssPullService.java :
public class RSSPullService extends IntentService {
public static final String BROADCAST_ACTION =
"com.example.android.threadsample.BROADCAST";
private static final String TAG = "RSSPullService";
public static final String EXTENDED_DATA_STATUS =
"com.example.android.threadsample.STATUS";
private LocalBroadcastManager mLocalBroadcastManager;
private ResponseReceiver receiver;
public RSSPullService() {
super("RSSPullService");
}
@Override
protected void onHandleIntent(Intent intent) {
String dataString = intent.getDataString();
Log.i(TAG,dataString);
String result = downloadHtml(dataString);
Log.i("result",result);
Intent localIntent = new Intent(BROADCAST_ACTION);
localIntent.putExtra(EXTENDED_DATA_STATUS,result);
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
mLocalBroadcastManager.sendBroadcast(localIntent);
}
private String downloadHtml(String dataString) {
try {
URL url = new URL(dataString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
InputStream in = conn.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len = 0;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
in.close();
Log.i("html",out.toByteArray().toString());
return new String(out.toByteArray());
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
}
AndroidManifest.xml:
...
了解Android控件的觸摸事件傳遞與處理對我們日常開發中自定義控件和觸摸事件沖突解決有重大意義。Android控件的觸摸事件傳遞和處理主要有以下幾個方法,下面一一介紹。
今天要做一個帶箭頭的圓角矩形菜單,大概長下面這個樣子: 要求頂上的箭頭要對准菜單錨點,菜單項按壓反色,菜單背景色和按壓色可配置。最簡單的做法就是讓UX給個三角形
首先我們來對這三種消息提示機制來一個直觀的認識,分別是AlertDialog Toast、Notification接下來分別介紹這三種機制各自對應的使用場景
之所以單列一篇寫進程管理,是因為看到注釋上寫“這是一個復雜的進程管理程序”,但是仔細看了一下好像也沒那麼“復雜”...這一