对《第一行代码——Android》的学习笔记
服务是什么
服务是Android中实现程序运行后台 的解决方案,它非常适用于去执行那些不需要和用户交互而且还要求长期运行的任务。
服务的后台概念实际上并不会自动开启线程,所有的代码还是在主线程中运行。
Android的多线程编程
线程的基本用法
class MyThread extends Thred{
public void run(){
//处理具体的逻辑
}
}
使用 new MyThread().start();
使用继承的方式耦合性很高,更多的时候我们都会选择使用实现Runnable接口的方式来定义一个线程,如下所示:
class MyThread implements Runnable{
public void run(){
//处理的具体逻辑
}
}
如果使用了这种方法,启动线程的方式也要改变:
MyThread myThread=new MyThread();
new Thread(myThread).start();
更常用的方法是实现匿名类
new Thread(new Runnable(){
public void run(){
//处理具体的逻辑
}
}).start();
在子线程中更新UI
Android是不允许在子线程中更新Ui的,所以Android提供了一套异步处理的机制
public class MainActivity extends Activity implements OnClickListener {
public static final int UPDATE_TEXT = 1;
private TextView text;
private Button changeText;
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_TEXT:
text.setText("Nice to meet you");
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
changeText = (Button) findViewById(R.id.change_text);
changeText.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.change_text:
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message);
}
}).start();
break;
default:
break;
}
}
}
程序中并没有在子线程中更新UI,而是创建一个Message对象,并将它的what字段的值指定为UPDATE——TEXT,然后调用Handler的dendMessage()方法将這条Message发送出去。Hander就会收到这条Message,并在handleMessage()方法中对它进行处理。此时handlemessage()方法中的代码就是在主线程中运行了。
解析异步消息处理机制
Android中的异步处理主要有四个消息组成,Message,Handler,MessageQueue和Looper。
1.Message
Message是在主线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间传递数据。刚刚使用了Message的what字段,除此之外还可以使用arg1和 arg2 字段来携带一些整形数据,使用obj字段携带一个Object对象。
2.Handler
Handler顾名思义也就是处理者的意思,它主要用于发送和处理消息。发送消息一般是使用Handler的sendMessage()方法,而发出的消息经过一系列的辗转处理后,最终会传递到Handler的handleMessage()方法中。
3.MessageQueue
是消息队列的意思,它主要用于存放所有通过Handler发送的消息。这部分消息会一直存在于消息队列中。等待被处理。每个线程只会有一个MessageQueue对象。
4.Looper
Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入一个无限循环中,然后每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的HandleMessage()方法中。每个线程中也只会有一个Looper对象。
异步消息处理首先需要在线程中创建一个handler对象,并重写handleMessage()方法。然后当子线程中需要进行UI操作时,就创建一个Message对象,并通过Handler将这条消息发送出去。之后这条消息就会被添加到MesssageQueue的队列中等待被处理,而looper则会一直尝试从MessageQueue中取出待处理的消息,最后分发到Handler的handleMessage()方法中。由于handler是在主线程中创建的,所以此时handleMessage()方法中的代码也会在主线程中运行,于是我们就放心的进行Ui的更新了。
使用AsyncTask
Android系统提供用于异步处理的工具之一
服务的基本用法
定义一个服务
public class MyService extends Service{
public IBinder onBind (Intent intent){
return null;
}
onBind()方法是唯一一个抽象方法。服务中还有其他三个常用的方法
1.onCreate()方法会在服务创建时调用
2.onstaartCommand()方法会在每次服务起动时调用
3.onDestroy()会在服务销毁是调用
另外需要注意的是,每一个服务都要注册,这是四大组件的共同特点。
启动服务与停止服务
启动服务
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
停止服务
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);
活动与服务进行通信
我们希望在MyService里提供一个下载功能。
class DownloadBinder extends Binder {
public void startDownload() {
new Thread(new Runnable() {
@Override
public void run() {
// start downloading
}
}).start();
Log.d("MyService", "startDownload executed");
}
public int getProgress() {
Log.d("MyService", "getProgress executed");
return 0;
}
}
在mainactivity中
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {//活动与服务解除绑定时调用
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {//活动与服务绑定是调用
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getProgress();
}
};
将服务与活动绑定
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);
解除绑定
unbindService(connection);
服务的更多技巧
使用前台服务
前台服务和普通服务的最大区别在于前台服务会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏可以看到详细的信息。比如说墨迹天气,他的服务在后台更新数据,会在状态栏一直更新当前天气。
Notification notification = new Notification(R.drawable.ic_launcher,
"Notification comes", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification.setLatestEventInfo(this, "This is title", "This is content",
pendingIntent);
startForeground(1, notification);
不同于建立通知的方法,在构建出Notification对象中并没有使用NotificationManager来将通知显示出来,而是调用startForeground()方法。
使用IntentService
为了简单的创建一个异步的,会自动停止的服务,Android专门提供了一个IntentService类
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d("MyIntentService", "Thread id is " + Thread.currentThread().getId());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyIntentService", "onDestroy executed");
}
}
启动IntentServicevice
Intent intentService = new Intent(this, MyIntentService.class);
startService(intentService);
服务的最佳实践——后台执行的定时任务
Android中的定时任务有两种实现方式:
一种是Java API里提供的Timer类;
另一种是android的Alarm机制。
设定一个任务在一个小时候后执行
public class LongRunningService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
Log.d("LongRunningService", "executed at " + new Date().toString());
}
}).start();
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int anHour = 60 * 60 * 1000;
long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
Intent i = new Intent(this, AlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
return super.onStartCommand(intent, flags, startId);
}
}
然后新建一个AlarmReceiver
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, LongRunningService.class);
context.startService(i);
}
}
一旦启动LongRunningService,就会在onStartCommand()设定一个定时任务,这样一个小时后AlarmReceiver的onReceiver()方法就会执行,然后在这里启动LongunningService.这样就做到了一个在后台长期运行的服务
public class MainActivity extends Activity {
View view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, LongRunningService.class);
startService(intent);
}
}