为了保证App运行的流畅性,大部分耗时操作,比如文件的读/写,网络的请求等都不能放在主线程来实现,而是需要另开线程或者通过开启服务组件放在后台执行.
多线程
使用多线程也可以实现类似后台服务的功能.Android中有三种实现多线程的方式.
匿名类
通过Thread类可以开启一个线程, Runnable接口中的方法run,会在调用start方法开启线程后执行.
//1匿名类
new Thread(new Runnable() {
@Override
public void run() {
Log.i("Thread", "run: " + "Thread");
}
}).start();
实现接口类
让TestThread类实现接口,然后传入开启的线程testThread.
public class TestThread implements Runnable {
@Override
public void run() {
Log.i("TestThread", "run: " + "TestThread");
}
}
TestThread testThread = new TestThread();
new Thread(testThread).start();
继承Thread类
让子类SonThread继承Thread,并实现run方法.
public class SonThread extends Thread {
@Override
public void run() {
Log.i("SonThread", "run: " + "SonThread");
}
}
SonThread sonThread = new SonThread();
sonThread.start();
子线程注意事项
通过Thread开启的子线程可以处理逻辑或数据操作,但是却不能更新UI.只有在主线程(original thread)中,才可以更新UI.不同线程间的通信可以通过Handler类或者AsyncTask类来实现.
异步消息处理机制
Handler
private TextView textView;
public static final int UPDATE_TEXT = 1;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
textView.setText("Hello world!");
break;
default:
break;
}
}
};
new Thread(new Runnable() {
@Override
public void run() {
Message msg = new Message();
msg.what = UPDATE_TEXT;
handler.sendMessage(msg);
}
}).start();
当子线程完成任务后,通过Handler类发送带有参数的消息Message.然后handler接收到消息后,可以调用接口handleMessage来更新UI.
Hander处理异步消息,通过Message,MessageQueue,Looper来实现.MessageQueue相当于一个容器,用于存储线程中的Message消息.线程开启后,Looper会调用自身的loop方法,不断检测线程中的Message消息,发现后就会加入到MessageQueue中,可以把它看做MessageQueue的管家.Hander会根据Looper将Message加入MessageQueue的顺序,在主线程中进行处理.
AsyncTask
public class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
private ProgressBar progressBar;
private Context context;
public DownloadTask(ProgressBar progressBar, Context context){
this.progressBar = progressBar;
this.context = context;
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onPreExecute() {
progressBar.setMin(0);
progressBar.setMax(10000);
progressBar.setProgress(0);
progressBar.setVisibility(View.VISIBLE);
}
@Override
protected Boolean doInBackground(Void... voids) {
int progress = 0;
try{
while (progress < 10000){
progress += 1;
publishProgress(progress);
}
}catch (Exception e){
e.printStackTrace();
return false;
}
return true;
}
@Override
protected void onProgressUpdate(Integer... values) {
progressBar.setProgress(values[0]);
}
@Override
protected void onPostExecute(Boolean aBoolean) {
progressBar.setVisibility(View.INVISIBLE);
if (aBoolean){
Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(context, "Failure", Toast.LENGTH_SHORT).show();
}
}
}
//调用
new DownloadTask(progressBar, this).execute();
AsyncTask有三个泛型,第一个代表执行任务时参数类型,第二个是执行过程中的进度,最后一个是执行结果. 在onPreExecute方法中做一些执行任务前的辅助工作; doInBackground方法用于处理耗时逻辑,执行的进度progress可以通过调用publishProgress方法传出,然后就会调用onProgressUpdate方法;在onProgressUpdate可以更新UI,显示在界面上;任务执行完毕后,会调用onPostExecute方法来返回任务执行的结果.
使用服务
服务类似子线程,可以很方便的处理耗时操作.
定义
public class TestService extends Service {
public TestService() {
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
继承至Service,实现抽象方法onBind.其中onCreate方法在服务被创建时执行,一个服务只能执行一次;onStartCommand在Service被调用时执行,可以反复调用多次; onDestroy方法在服务被停止时调用,一个服务也只能调用一次.
调用
正确调用Service,首先需要在AndroidManifest中的Application标签中进行注册.
<service android:name=".TestService"
android:enabled="true"
android:exported="true"></service>
通过Intent可以很方便的开启和关闭服务.
public void startService(View view){
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
}
public void stopService(View view){
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);
}
通过Service的前台服务,可以让App运行的信息始终显示在手机通知栏中.
@Override
public void onCreate() {
super.onCreate();
Log.i("MyService", "onCreate: " + "MyService");
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
Notification notify = new NotificationCompat.Builder(this)
.setContentTitle("This is title")
.setContentText("This is text")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setContentIntent(pi)
.build();
startForeground(1, notify);
}
通过IBinder在Activity和Service中进行通信
class MyBinder extends Binder {
public void startDownload(){
Log.i("startDownload", "startDownload");
}
public int getProgress(){
Log.i("getProgress", "getProgress");
return 0;
}
}
private MyBinder myBinder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}
修改MyService中IBinder的实现,并添加内部类MyBinder.然后可以在MainActivity通过ServiceConnection调用MyBinder中的方法.
private MyService.MyBinder downloadBinder;
//通过serviceConnection可以获取服务的Binder, 然后调用Binder中的方法;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder)
downloadBinder = (MyService.MyBinder)iBinder;
downloadBinder.startDownload();
downloadBinder.getProgress();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
public void bindService(View view){
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, serviceConnection, BIND_AUTO_CREATE);
}
public void unbindService(View view){
Intent bindIntent = new Intent(this, MyService.class);
unbindService(serviceConnection);
}
销毁的三种方式
- 通过startService启动的服务,可以通过stopService的方式销毁.通过bindService启动的服务,可以通过unbindService的方式销毁.这两种方式,都会调用服务的onDestroy方法.如果在活动中既调用startService又调用bindService,那么就需要同时调用两者的停止方法来销毁.
2.在服务的执行方法onStartCommand调用stopSelf()方法.
3.让服务继承至IntentService.这样当服务中的onStartCommand方法执行完毕,会自动销毁.
总结
多线程和服务的存在,让一个App在运行期间,可以同时处理多个任务,保证了界面运行的流畅性.通过Thread类开启线程,将任务放在线程的run方法中.用Handle类和AsyncTask类可以实现子线程与主线程的通信.服务类似新开一个进程,通过Activity开启后会一直存在,直到调用stopSelf方法或者相应的关闭方法.为了防止服务忘记关闭或者关闭失败造成的资源浪费,可以让服务继承IntentService类.这样开启的服务,在任务执行完毕后会自动停止.