Android知识点(二)
七、多媒体
1、使用通知
(1)通知的基本用法
第一步,首先需要一个NotificationManager来对通知进行管理,
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
第二步,需要使用Builder构造器来创建Notification对象,(几乎Android每个版本都会对通知这部分功能进行或多或少的修改,解决方法使用support-v4库提供的NotificationCompat类)
Notification notification = new NotificationCompat.Builder(context).build();
例如:
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("This is content title")
.setContentText("This is content text")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.build();
第三步,调用NotificationManager 的notify()方法让通知显示出来。
manager.notify(1, notification);
小示例:
Intent intent = new Intent(this, NotificationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);//可以用于启动活动、启动服务以及发送广播等,PendingIntent更加倾向于在某个合适的时机去执行某个动作。
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("This is content title")//通知的标题内容
.setContentText("This is content text")//通知的正文内容
.setWhen(System.currentTimeMillis())//用于指定通知被创建的时间
.setSmallIcon(R.mipmap.ic_launcher)//设置通知的小图标
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))//设置通知的大图标
.setContentIntent(pi)//给通知加上点击效果
// .setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))//通知发出的时候播放一段音频
// .setVibrate(new long[]{0, 1000, 1000, 1000})//下标为0静止时长,下标为1震动时长,以次类推
// .setLights(Color.GREEN, 1000, 1000)//第一参数表示LED灯的颜色,第二个参数用于指定LED灯亮起的时长,第三个参数用于指定LED灯暗去的时长
.setDefaults(NotificationCompat.DEFAULT_ALL)//设置通知默认效果
// .setStyle(new NotificationCompat.BigTextStyle().bigText("Learn how to build notifications, send and sync data, and use voice actions. Get the official Android IDE and developer tools to build apps for Android."))//通知长文字效果
.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(), R.drawable.big_image)))//显示大图片的效果
.setPriority(NotificationCompat.PRIORITY_MAX)//通知的优先级
.setAutoCancel(true)//通知会自动取消掉
.build();
manager.notify(1, notification);
不要忘了震动要加权限
<uses-permission android:name="android.permission.VIBRATE" />
或者
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(1);//取消通知

2、调用摄像头和相册
(1)调用摄像头拍照

takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 创建File对象,用于存储拍照后的图片
File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
if (Build.VERSION.SDK_INT < 24) {
imageUri = Uri.fromFile(outputImage);
} else {
imageUri = FileProvider.getUriForFile(MainActivity.this, "com.example.cameraalbumtest.fileprovider", outputImage);
}
// 启动相机程序
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO);
}
});
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
try {
// 将拍摄的照片显示出来
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
picture.setImageBitmap(bitmap);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}

(2)从相册中选择照片
public class MainActivity extends AppCompatActivity {
public static final int CHOOSE_PHOTO = 2;
private ImageView picture;
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button chooseFromAlbum = (Button) findViewById(R.id.choose_from_album);
picture = (ImageView) findViewById(R.id.picture);
chooseFromAlbum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission. WRITE_EXTERNAL_STORAGE }, 1);
} else {
openAlbum();
}
}
});
}
private void openAlbum() {
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent, CHOOSE_PHOTO); // 打开相册
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openAlbum();
} else {
Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case CHOOSE_PHOTO:
if (resultCode == RESULT_OK) {
// 判断手机系统版本号
if (Build.VERSION.SDK_INT >= 19) {
// 4.4及以上系统使用这个方法处理图片
handleImageOnKitKat(data);
} else {
// 4.4以下系统使用这个方法处理图片
handleImageBeforeKitKat(data);
}
}
break;
default:
break;
}
}
@TargetApi(19)
private void handleImageOnKitKat(Intent data) {
String imagePath = null;
Uri uri = data.getData();
Log.d("TAG", "handleImageOnKitKat: uri is " + uri);
if (DocumentsContract.isDocumentUri(this, uri)) {
// 如果是document类型的Uri,则通过document id处理
String docId = DocumentsContract.getDocumentId(uri);
if("com.android.providers.media.documents".equals(uri.getAuthority())) {
String id = docId.split(":")[1]; // 解析出数字格式的id
String selection = MediaStore.Images.Media._ID + "=" + id;
imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
} else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
imagePath = getImagePath(contentUri, null);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
// 如果是content类型的Uri,则使用普通方式处理
imagePath = getImagePath(uri, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
// 如果是file类型的Uri,直接获取图片路径即可
imagePath = uri.getPath();
}
displayImage(imagePath); // 根据图片路径显示图片
}
private void handleImageBeforeKitKat(Intent data) {
Uri uri = data.getData();
String imagePath = getImagePath(uri, null);
displayImage(imagePath);
}
private String getImagePath(Uri uri, String selection) {
String path = null;
// 通过Uri和selection来获取真实的图片路径
Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
}
cursor.close();
}
return path;
}
private void displayImage(String imagePath) {
if (imagePath != null) {
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
picture.setImageBitmap(bitmap);
} else {
Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show();
}
}
}

3、播放多媒体文件
(1)播放音频

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private MediaPlayer mediaPlayer = new MediaPlayer();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button play = (Button) findViewById(R.id.play);
Button pause = (Button) findViewById(R.id.pause);
Button stop = (Button) findViewById(R.id.stop);
play.setOnClickListener(this);
pause.setOnClickListener(this);
stop.setOnClickListener(this);
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission. WRITE_EXTERNAL_STORAGE }, 1);
} else {
initMediaPlayer(); // 初始化MediaPlayer
}
}
private void initMediaPlayer() {
try {
File file = new File(Environment.getExternalStorageDirectory(), "music.mp3");
mediaPlayer.setDataSource(file.getPath()); // 指定音频文件的路径
mediaPlayer.prepare(); // 让MediaPlayer进入到准备状态
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initMediaPlayer();
} else {
Toast.makeText(this, "拒绝权限将无法使用程序", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start(); // 开始播放
}
break;
case R.id.pause:
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause(); // 暂停播放
}
break;
case R.id.stop:
if (mediaPlayer.isPlaying()) {
mediaPlayer.reset(); // 停止播放
initMediaPlayer();
}
break;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
}

(2)播放视频

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private VideoView videoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
videoView = (VideoView) findViewById(R.id.video_view);
Button play = (Button) findViewById(R.id.play);
Button pause = (Button) findViewById(R.id.pause);
Button replay = (Button) findViewById(R.id.replay);
play.setOnClickListener(this);
pause.setOnClickListener(this);
replay.setOnClickListener(this);
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission. WRITE_EXTERNAL_STORAGE }, 1);
} else {
initVideoPath(); // 初始化MediaPlayer
}
}
private void initVideoPath() {
File file = new File(Environment.getExternalStorageDirectory(), "movie.mp4");
videoView.setVideoPath(file.getPath()); // 指定视频文件的路径
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initVideoPath();
} else {
Toast.makeText(this, "拒绝权限将无法使用程序", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
if (!videoView.isPlaying()) {
videoView.start(); // 开始播放
}
break;
case R.id.pause:
if (videoView.isPlaying()) {
videoView.pause(); // 暂停播放
}
break;
case R.id.replay:
if (videoView.isPlaying()) {
videoView.resume(); // 重新播放
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (videoView != null) {
videoView.suspend();
}
}
}

八、网络技术
1、WebView的用法
第一步,
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
第二步,
WebView webView = (WebView) findViewById(R.id.web_view);
webView.getSettings().setJavaScriptEnabled(true);//调用getSettings()方法设置一些浏览器的属性,这里只是让WebView支持JavaScript脚本;
webView.setWebViewClient(new WebViewClient());//从一个网页跳转到另一个网页时,使目标网页仍然在当前WebView中显示,而不是打开系统浏览器
webView.loadUrl("https://www.baidu.com");//展示相应网页的内容。
webView的其他方法: void goBack()后退;void goForward()前进;boolean zoomIn()放大网页;boolean zoomOut()缩小网页;
使用WebView加载HTML代码;loadDataWithBaseURL(String baseUrl,String data,String mimeType,String encoding,String historyUrl);
data:需要加载的HTML代码;mimeType:指定HTML代码的MIME类型,对于HTML代码可指定为text/html;encoding:指定HTML代码编码所用的字符集(例如:UTF-8);
在webView的JavaScript中调用Android方法:
1、调用WebView关联的WebSettings的setJavascriptEnabled(true)启用JavaScript调用功能;
2、调用WebView的addJavascriptInterface(Object object,String name)方法将Object对象暴露给JavaScript脚本;
3、在JavaScript脚本中通过刚才暴露的name对象调用Android方法;!WebView.jpg
WebView2.jpg
第三步,声明权限
<uses-permission android:name="android.permission.INTERNET" />
2、使用HTTP协议访问网络
(1)使用HttpURLConnection
第一步,获取到HttpURLConnection的实例,
URL url = new URL("https://www.baidu.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
第二步,设置一下HTTP请求所使用的方法。常用的主要有:GET和POST,GET表示希望从服务器那里获取数据,而POST则表示希望提交数据给服务器。
connection.setRequestMethod("GET");
第三步,进行一些自由的定制,比如设置连接超时、读取超时的毫秒数,以及服务器希望得到的一些消息头等。
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
第四步,调用getInputStream()方法就可以获取到服务器返回的输入流,剩下的任务就是对输入流进行读取。
InputStream in = connection.getInputStream();
第五步,最后调用disconnect()方法将这个HTTP连接关闭掉。
connection.disconnect();
小例子:
private void sendRequestWithHttpURLConnection() {
// 开启线程来发起网络请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL("https://www.baidu.com");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
InputStream in = connection.getInputStream();
// 下面对获取到的输入流进行读取
reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
showResponse(response.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (connection != null) {
connection.disconnect();
}
}
}
}).start();
}
private void showResponse(final String response) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// 在这里进行UI操作,将结果显示到界面上
responseText.setText(response);
}
});
}
如果想要提交数据给服务器呢?
只需要将HTTP请求的方法改成POST,并在获取输入流之前要把提交的数据写出即可。每条数据都要以键值对的形式存在,数据和数据之间用“&”符号隔开,比如:
connection.setRequestMethod("POST");
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes("username=admin&password=123456");
(2)使用OkHttp
第一步,编辑app/build.gradle文件,在dependencies闭包中添加如下内容,
compile 'com.squareup.okhttp3:okhttp:3.9.1'
第二步,创建一个OkHttpClient的实例,
OkHttpClient client = new OkHttpClient();
第三步,如果想发起一条HTTP请求,就需要创建一个Request对象:
Request request = new Request.Builder().build();
Request request = new Request.Builder()
.url("https://www.baidu.com")
.build();
第四步,之后调用OkHttpClient 的newCall()方法来创建一个call对象,并调用它的execute()方法来发送请求并获取服务器返回的数据,如下:
Response response = client.newCall(request).execute();
第五步,其中Response对象就是服务器返回的数据,我们可以使用如下写法来得到返回的具体内容:
String responseData = response.body().string();
如果是发起一条POST请求,需要先构建出一个RequestBody对象来存放待提交的参数;
RequestBody requestBody = new FormBody.Builder()
.add("username","admin")
.add("password","123456")
.build();
然后再Request.Builder中调用一下post()方法,并将RequestBody对象传入:
Request request = new Request.Builder()
.url("https://www.baidu.com")
.post(requestBody)
.build();
接下来的操作就和GET请求一样了。
小示例:
private void sendRequestWithOkHttp() {
new Thread(new Runnable() {
@Override
public void run() {
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://www.baidu.com")
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
showResponse(responseData);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
3、解析XML格式数据
数据源:

(1)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;
}
// 完成解析某个结点
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();
}
}
(2)SAX解析方式
小示例:
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();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// 记录当前结点名
nodeName = localName;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// 根据当前的结点名判断将内容添加到哪一个StringBuilder对象中
if ("id".equals(nodeName)) {
id.append(ch, start, length);
} else if ("name".equals(nodeName)) {
name.append(ch, start, length);
} else if ("version".equals(nodeName)) {
version.append(ch, start, length);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("app".equals(localName)) {
Log.d("ContentHandler", "id is " + id.toString().trim());
Log.d("ContentHandler", "name is " + name.toString().trim());
Log.d("ContentHandler", "version is " + version.toString().trim());
// 最后要将StringBuilder清空掉
id.setLength(0);
name.setLength(0);
version.setLength(0);
}
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
}
private void parseXMLWithSAX(String xmlData) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader xmlReader = factory.newSAXParser().getXMLReader();
ContentHandler handler = new ContentHandler();
// 将ContentHandler的实例设置到XMLReader中
xmlReader.setContentHandler(handler);
// 开始执行解析
xmlReader.parse(new InputSource(new StringReader(xmlData)));
} catch (Exception e) {
e.printStackTrace();
}
}
4、解析JSON个数数据
数据源:

(1)使用JSONObject
小示例:
private void parseJSONWithJSONObject(String jsonData) {
try {
JSONArray jsonArray = new JSONArray(jsonData);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String id = jsonObject.getString("id");
String name = jsonObject.getString("name");
String version = jsonObject.getString("version");
Log.d("MainActivity", "id is " + id);
Log.d("MainActivity", "name is " + name);
Log.d("MainActivity", "version is " + version);
}
} catch (Exception e) {
e.printStackTrace();
}
}
(2)使用GSON

小示例:
private void parseJSONWithGSON(String jsonData) {
Gson gson = new Gson();
List<App> appList = gson.fromJson(jsonData, new TypeToken<List<App>>() {
}.getType());
for (App app : appList) {
Log.d("MainActivity", "id is " + app.getId());
Log.d("MainActivity", "name is " + app.getName());
Log.d("MainActivity", "version is " + app.getVersion());
}
}
九、服务(Service)

1、Android多线程编程
(1)线程的基本用法
几种线程的使用方式:
第一种:
class MyThread extends Thread{
@Override
public void run() {
//处理具体逻辑
}
}
new MyThread().start();
第二种:
class MyThread implements Runnable{
@Override
public void run() {
//处理具体逻辑
}
}
MyThread myThread = new MyThread();
new Thread(myThread).start();
第三种:
new Thread(new Runnable(){
@Override
public void run() {
//处理具体逻辑
}
}).start();
(2)在子线程中更新UI奔溃问题
使用handler解决:
public static final int UPDATE_TEXT = 1;
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_TEXT:
// 在这里可以进行UI操作
text.setText("Nice to meet you");
break;
default:
break;
}
}
};
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message); // 将Message对象发送出去
}
}).start();
(3)解析异步消息处理机制

(4)使用AsncTask

2、服务的基本用法
(1)定义一个服务

小示例:
public class MyService extends Service {
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
Log.d("MyService", "onCreate executed");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MyService", "onStartCommand executed");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyService", "onDestroy executed");
}
}
虽然Android studio帮我们完成了服务的注册,但是不要忘了服务是四大组件要在AndroidManifest.xml文件中进行注册;
(2)启动和停止服务
启动:
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); // 启动服务
停止服务:
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent); // 停止服务
或者在MyService的任何位置调用stopSelf()方法就能让这个服务停止下来。

(3)活动和服务进行通信
修改MyService中的代码,添加如下代码:
private DownloadBinder mBinder = new DownloadBinder();
class DownloadBinder extends Binder {
public void startDownload() {
Log.d("MyService", "startDownload executed");
}
public int getProgress() {
Log.d("MyService", "getProgress executed");
return 0;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
修改MainActivity中的代码,如下所示:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
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();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startService = (Button) findViewById(R.id.start_service);
Button stopService = (Button) findViewById(R.id.stop_service);
startService.setOnClickListener(this);
stopService.setOnClickListener(this);
Button bindService = (Button) findViewById(R.id.bind_service);
Button unbindService = (Button) findViewById(R.id.unbind_service);
bindService.setOnClickListener(this);
unbindService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_service:
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); // 启动服务
break;
case R.id.stop_service:
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent); // 停止服务
break;
case R.id.bind_service:
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE); // 绑定服务
break;
case R.id.unbind_service:
unbindService(connection); // 解绑服务
break;
default:
break;
}
}
}

3、服务的生命周期

4、服务的更多技巧
(1)使用前台服务

修改MyService onCreate方法中的代码,如下:
@Override
public void onCreate() {
super.onCreate();
Log.d("MyService", "onCreate executed");
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("This is content title")
.setContentText("This is content text")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setContentIntent(pi)
.build();
startForeground(1, notification);
}
(2)使用IntentService

在服务中开启多线程可以解决上面ANR的问题,但是有一些程序猿忘记开启线程或者忘记调用stopSelf()方法。为了简单地创建一个异步的、会自动停止的服务,Android专门提供了一个IntentService类,
使用IntentService类:
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService"); // 调用父类的有参构造函数
}
@Override
protected void onHandleIntent(Intent intent) {
// 打印当前线程的id
Log.d("MyIntentService", "Thread id is " + Thread.currentThread(). getId());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyIntentService", "onDestroy executed");
}
}
修改MainActivity中的代码,如下:
Button startIntentService = (Button) findViewById(R.id.start_intent_service);
startIntentService.setOnClickListener(this);
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_intent_service:
// 打印主线程的id
Log.d("MainActivity", "Thread id is " + Thread.currentThread(). getId());
Intent intentService = new Intent(this, MyIntentService.class);
startService(intentService);
break;
default:
break;
}
}
最后不要忘了在AndroidManifest.xml文件中注册MyIntentService;

5、服务的最佳实践之完整的下载示例
十、基于位置的服务(百度、高德地图)
下面的所有功能都参考百度官网的开发文档来做:百度地图开放平台 | 百度地图API SDK | 地图开发

1、申请API Key


2、使用百度定位
3、使用百度地图

十一、Material Design(Android5.0)
1、Toolbar
2、滑动菜单
3、悬浮按钮和可交互提示
FloatingActionButton Snackbar CoordinatorLayout
4、卡片式布局
5、下拉刷新
6、可折叠式标题栏
十二、更多高级技能
1、全局获取Context的技巧


以下所有知识点参考郭霖第一行代码第二版第十三章