第九章 第十章 服务

服务
这使得应用程序即使在关闭的情况下仍然可以在后台继续运行
服务并不是运行在一个独立的进程当中的,而是依赖于创建服务
时所在的应用程序进程。当某个应用程序进程被杀掉时,所有依赖于该进程的服务也会停 止运行。
实际上服务并不会自动开启线程,所有的代码 都是默认运行在主线程当中的
new Thread(new Runnable() {
@Override
public void run() {
// 处理具体的逻辑 }
}).start();

class MyThread extends Thread {
@Override
public void run() {
// 处理具体的逻辑 }
}
那么该如何启动这个线程呢?其实也很简单,只需要 new 出 MyThread 的实例,然后调 用它的 start()方法,这样 run()方法中的代码就会在子线程当中运行了,如下所示:
new MyThread().start();

handler 类

AsyncTask

1. Params

在执行 AsyncTask 时需要传入的参数,可用于在后台任务中使用。
2. Progress
后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为 进度单位。
364
第 9 章 后台默默的劳动者,探究服务
3. Result
当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值 类型。

经常需要去重写的方法 有以下四个。
1. onPreExecute()
这个方法会在后台任务开始执行之前调用,用于进行一些界面上的初始化操作,比 如显示一个进度条对话框等。
2. doInBackground(Params…)
这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任 务。任务一旦完成就可以通过 return 语句来将任务的执行结果返回,如果 AsyncTask 的 第三个泛型参数指定的是 Void,就可以不返回任务执行结果。注意,在这个方法中是不 可以进行 UI 操作的,如果需要更新 UI 元素,比如说反馈当前任务的执行进度,可以调 用 publishProgress(Progress…)方法来完成。
3. onProgressUpdate(Progress…)
当在后台任务中调用了 publishProgress(Progress…)方法后,这个方法就会很快被调
用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对 UI 进行操 作,利用参数中的数值就可以对界面元素进行相应地更新。
4. onPostExecute(Result)
当后台任务执行完毕并通过 return 语句进行返回时,这个方法就很快会被调用。返 回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些 UI 操作,比如 说��醒任务执行的结果,以及关闭掉进度条对话框等。

如果想要启动这个任务,只需编写以下代码即可:
new DownloadTask().execute();
以上就是 AsyncTask 的基本用法,怎么样,是不是感觉简单方便了许多?我们并不需要 去考虑什么异步消息处理机制,也不需要专门使用一个 Handler 来发送和接收消息,只需要 调用一下 publishProgress()方法就可以轻松地从子线程切换到 UI 线程了。

服务 抽象类

onCreate()、onStartCommand()和 onDestroy()这三个方法, 它们是每个服务中最常用到的三个方法了。其中 onCreate()方法会在服务创建的时候调用, onStartCommand()方法会在每次服务启动的时候调用,onDestroy()方法会在服务销毁的时候 调用。

Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); // 启动服务
break;
case R.id.stop_service:
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent); // 停止服务

如果没有点击 Stop Service 按钮,服务就会一直处于运行状态。那服务有没有什么办法让自已停止下来呢? 当然可以,只需要在 MyService 的任何一个位置调用 stopSelf()方法就能让这个服务停止下 来了。

然服务是在活 动里启动的,但在启动了服务之后,活动与服务基本就没有什么关系了。确实如此,我们在 活动里调用了 startService()方法来启动 MyService 这个服务,然后 MyService 的 onCreate()和 onStartCommand()方法就会得到执行。之后服务会一直处于运行状态,但具体运行的是什么 逻辑,活动就控制不了了
break;

private DownloadBinder mbinder=new DownloadBnder();
class DownloadBinder extends Binder{
startDownload(); getProgress();
}

public IBinder onBind(Intent intent){

return mBinder;

}

当一个活动和服务绑定了之后,就可以调用该服务里的 Binder ��供的方法了。
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE); // 绑定服务

private MyService.DownloadBinder downloadBinder;
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();
} };

这里传入 BIND_AUTO_CREATE 表示在活动和服务进行绑定后自动 创建服务。这会使得 MyService 中的 onCreate()方法得到执行,但 onStartCommand()方法不 会执行。

startService()方法,又调用了 bindService()方法的, 这种情况下该如何才能让服务销毁掉呢?根据 Android 系统的机制,一个服务只要被启动或 者被绑定了之后,就会一直处于运行状态,必须要让以上两种条件同时不满足,服务才能被 销毁。所以,这种情况下要同时调用 stopService()和 unbindService()方法,onDestroy()方法才 会执行。

前台服务和普通服务最大的区别就在于,它会一直有一个正在运 行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的 效果。当然有时候你也可能不仅仅是为了防止服务被回收掉才使用前台服务的,有些项目由
380
第 9 章 后台默默的劳动者,探究服务 于特殊的需求会要求必须使用前台服务

public class MyService extends Service {
……
@Override
public void onCreate() {
super.onCreate();
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);

        直处于运行状态,必须调用 stopService()或者 stopSelf()方法才能让服务停止下来。所以,如果想要实现让一个服务在执行完毕后自动停止 的功能,就可以这样写:
public class MyService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


383
第一行代码——Android
 @Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() { // 处理具体的逻辑
stopSelf();
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}

IntentService 异步的、会自动停止的服务

onHandleIntent(Intent intent){

}

服务主要做什么功能服务中经常用到的技术之一,在后台执 行定时任务。
Alarm 机制则不存在这种情况,它具有唤醒 CPU 的功能,即可以保证每次需要执行定时 任务的时候 CPU 都能正常工作
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

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);

HttpPost httpPost = new HttpPost(“http://www.baidu.com“);
然后通过一个 NameValuePair 集合来存放待��交的参数,并将这个参数集合传入到一个 UrlEncodedFormEntity 中,然后调用 HttpPost 的 setEntity()方法将构建好的 UrlEncodedFormEntity 传入,如下所示:
List params = new ArrayList();
params.add(new BasicNameValuePair(“username”, “admin”));
params.add(new BasicNameValuePair(“password”, “123456”));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, “utf-8”);
httpPost.setEntity(entity);
接下来的操作就和 HttpGet 一样了,调用 HttpClient 的 execute()方法,并将 HttpPost 对 象传入即可:
httpClient.execute(httpPost);

获取到httpResponse.然后得到httpEntity。
HttpEntity entity=httpResponse.getEntity();
String response=EntityUtils.toString(entity,”utf-8”);

pull解析

private void parseXMLWithPull(String xmlData) {
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(new StringReader(xmlData));
int eventType = xmlPullParser.getEventType();
String id = “”;
String name = “”;
String version = “”;
while (eventType != XmlPullParser.END_DOCUMENT) {
String nodeName = xmlPullParser.getName();
switch (eventType) {
// 开始解析某个结点
case XmlPullParser.START_TAG: {
if (“id”.equals(nodeName)) {
id = xmlPullParser.nextText();
} else if (“name”.equals(nodeName)) {
name = xmlPullParser.nextText();
} else if (“version”.equals(nodeName)) {
version = xmlPullParser.nextText();
}
break; }
410
第 10 章 看看精彩的世界,使用网络技术
// 完成解析某个结点
case XmlPullParser.END_TAG: {
if (“app”.equals(nodeName)) {
Log.d(“MainActivity”, “id is ” + id);
Log.d(“MainActivity”, “name is ” + name);
Log.d(“MainActivity”, “version is ” + version);
}
break; }
default:
break;
}
eventType = xmlPullParser.next();
}
} catch (Exception e) {
e.printStackTrace();
} }

SAX 解析的方

SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader xmlReader = factory.newSAXParser().getXMLReader();
415
第一行代码——Android
ContentHandler handler = new ContentHandler(); // 将ContentHandler的实例设置到XMLReader中 xmlReader.setContentHandler(handler);
// 开始执行解析
xmlReader.parse(new InputSource(new StringReader(xmlData)));
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ContentHandler extends DefaultHandler{
private String nodeName;
private StringBuilder id;
private StringBuilder name;
private StringBuilder version;

@Override
public void startDocument() throws SAXException {
id = new StringBuilder();
name = new StringBuilder();
version = new StringBuilder();
}

}

解析json格式数据

解析json数据 可以用jsonObject gson

{“name”:”Tom”,”age”:20}
Gson gson=new gson();
Person person=gson.from(JsonData,Person.class

);

如果需要解析的是一段 JSON 数组会稍微麻烦一点,我们需要借助 TypeToken 将期望解 析成的数据类型传入到 fromJson()方法中,如下所示
[{“id”:”5”,”version”:”5.5”,”name”:”Angry Birds”},
{“id”:”6”,”version”:”7.0”,”name”:”Clash of Clans”},
{“id”:”7”,”version”:”3.5”,”name”:”Hey Day”}]

List people=gson.fromJson(jsonData,new TypeToken

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值