Fork me on GitHub Android《第一行代码》简要笔记(三) - 冰路梦 | binglumeng

Android《第一行代码》简要笔记(三)

Posted by 冰路梦 on 2017-06-07

Android《第一行代码》简要笔记(三)

第八章、多媒体

1、通知

Android使用Notification Manager来管理通知,getSystemService()来获取对象实例。

1
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

因Android版本众多,迭代更新Notification亦在更新,故而Android官方使用NotificationCompat作为兼容包。

Notification notification = new NotificationCompat.Builder(context).build();

1
2
3
4
5
6
7
8
//创建一个通知
Notification notification = new NotificationCompat.Builder(context)
.setContentTitle("Notification Title")
.setContextText("Content Text in Notification ")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.small_icon)
.setLargeIcon(BitmapFactory.decodeResource(getResource(),R.drawable.large_icon))
.build();

如上创建了一个Notification对象,需要用Manager来管理

1
manager.notify(1,notification);//第一个参数是id,用于标记不同的通知,有利于以后找到并操作该通知。

PendingIntent:类似与Intent,它会在适当的时机去执行这个意图,理解为延迟版的Intent。

  • PendingIntent

getActivity()、getService()、getBroadcast()。四个参数来获取实例对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>...
> Intent intent = new Intent(this,MyNotificationActivity.class);//点击的响应启动
>PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);//四个参数,最后一个是Flag。
>//NotificationManager
>NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
>//Notification
>Notification notification = new NotificationCompat.Builder(context)
> .setContentTitle("Notification Title")
> .setContextText("Content Text in Notification ")
> .setWhen(System.currentTimeMillis())
> .setSmallIcon(R.drawable.small_icon)
> .setLargeIcon(BitmapFactory.decodeResource(getResource(),R.drawable.large_icon))
> //设置通知被点击后的响应
> .setContentIntent(pi)
> .build();
>manager.notify(1,notification);
>

>

通知的取消,有两种方式

  • NotificationCompat构建它的时候,设置setAutoCancel(true)
  • 用NotificationManager对象来manager.cancel(1);此处传入的id是上面代码中指定的通知的id。

通知还有许多其他用法:

1
2
3
4
5
6
7
8
9
10
11
...
.setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))//设置声音
.setVibrate(new long[]{0,1000,1000,1000})//设置震动,从启动后0毫秒立即执行,然后震动1秒,休息一秒,再震动一秒。需要权限哦!!!
.setLights(Color.GREEEN,1000,1000)//设置led闪亮,颜色、亮的时长、熄灭时长
.setDefault(NotificationCompat.DEFAULT_ALL)//都是默认值
...
.build();
//其他高级用法,比如长文本,可能显示不了,就用到.setStyle方法
.setSytle(new NotificationCompat.BigTextStyle().bigText("This is a large text too long ...."))
//大图片
.setStyle(new NotificationCompat.BitPictureStyle(BitmapFactory.decodeResource(getResource(),R.drawable.big_pic)))

setPriority设置通知的优先级,默认都是一般。

1
PRIORITY_MIN、PRIORITY_LOW、PRIORITY_DEFAULT、PRIORITY_HIGH、PRIORITY_MAX
1
.setPriority(NotificationCompat.PRIORITY_MAX)

2、Camera

  • 调取摄像头拍照获得图片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class MainActivity extends AppCompatActivity{
public static final int TAKE_PHOTO = 1;
private ImageView ivPicture;
private Uri uriImage;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setConentView(R.layout.activity_main);
Button btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v){
//创建File对象,存储拍摄后的照片
File outImage = new File(getExternalCacheDir(),"outImage.jpg");
try{
//删除已存在
if(outImage.exists()){
outImage.delete();
}
outImage.createFile();
}catch(IOException e){
e.printStackTrace();
}
//根据不同的版本,不同的获取uri的方式
if(Build.VERSION.SDK_INT >= 24 ){
//第二个参数的字符串,是7.0以上版本,获取uri需要的authority
uriImage = FileProvider.getUriForFile(MainActivity.this,"com.example.cameratest.fileprovider",outImage);//获得uri。
}else{
uriImage = Uri.fromFile(outImage);
}
//启动相机
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT,uriImage);
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(uriImage));
ivPicture.setImageBitmap(bitmap);
}catch(IOException e){
e.printStackTrace();
}
}
break;
default:
break;
}
}
}

如上,在Android 7.0以下获取uri不太麻烦,7.0以上则需要provider获取。就要在AndroidManifest中注册

1
2
3
4
5
6
7
8
9
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.cameratest.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>

上面的Provider引用了xml就需要创建

1
2
3
<paths xmlns:android="http://schema.android.com/apk/res/android">
<external-path name="my_images" path=""/>
</paths>

这里external-path就是指定uri共享的路径,path表示共享整个sd卡。4.4版本一下,需要声明sd卡权限。

  • 从相册获取图片

书中代码包含了运行时权限判断,此处仅写出关键代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
...
public static final int CHOOSE_PHOTO = 2;
...
private void openAlbum(){
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent,CHOOSE_PHOTO);
}
...
@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){
handleImageOnKitKat(data);
}else{
handleImageBeforeKitKat(data);
}
}
break;
...
}
//api>=19时
@TargetApi(19)
private void handleIamgeOnKitKat(Intent data){
String imagePath = null;
Uri uri = data.getData();
if(DocumentsContract.isDocumentUri(this,uri)){
//若是doc类型的uri,通过doc 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._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.getSchema())){
//如果是content类型的uri,使用普通处理方式
imagePath = getImagePath(uri,null);
}else if("file".equalsIgnoreCase(uri.getSchema())){
//file类型的uri,可直接获取图片路径
imagePath = uri.getPath();
}
//显示图片
displayImage(imagePath);
}
//4.4以下版本
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 获取path
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、播放多媒体

  • 音频

MediaPlayer类提供了良好的封装的方法

1
2
3
4
5
6
7
8
9
10
setDataSource()//设置播放文件的路径
prepare();
start();
pause();
reset();
seekTo();
stop();
release();
isPlaying();
getDuration();

注意:1、权限的判断;2、播放、暂停、停止等操作要判断是否在playing,释放资源判断是否为空。

  • 视频播放

    类似与音频播放,Android提供了VideoView来操作。

    1
    2
    3
    4
    5
    6
    7
    setVieoPath();
    start();
    pause();
    resume();
    seekTo();
    isPlaying();
    getDuration();

第九章、网络

1、WebView

1
2
3
4
5
6
7
...
WebView webView = (WebView)findViewById(R.id.wv);
webView.getSettings().setJavaScriptEnable(true);//启用JS
webView.setWebViewClient(new WebViewClient());
webView.loadUrl("https://www.binglumeng.gitbub.io");
...

2、Http访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
...
//网络为耗时操作,尽量放在子线程中,注意在线程中获取响应,要在这里处理,而不是在外边,有可能会导致方法走过了,数据没回来。!!!
private void sendRequestWithHttpURLConnection(){
new Thread(new Runnable(){
@Override
public void run(){
HttpURLConnection conn = null;
BufferedReader reader = null;
try{
URL url = new URL("https://binglumeng.github.io");
conn = (HttpURLConncetion)url.openConncetion();
conn.setRequestMethod("GET");
conn.setConnectionTimeout(8000);
conn.setReadTimeout(8000);
InputStream in = conn.getInputStream();
//读取输入流
reader = new BufferedReader(new InputStream(in));
StringBuilder sb = new StringBuilder();
String line;
while((line = reader.readline())!=null){
sb.append(line);
}
showResponse(sb.toString());
}catch(Exception e){
e.printStackTrace();
}finally{
if(reader!=null){
reader.close();
}catch(IOException e){
e.printStackTrace();
}
//
if(conn!=null){
conn.disconnect();
}
}
}
}).start();
}
private void showResponse(final String response){
runOnUiThread(new Runnable(){
@Override
public void run(){
...
}
});
}

GETPOST请求为常用的HTTP请求,若用POST注意其中数据用键值对形式,数据与数据之间用&符号。

1
2
3
conn.setRequsetMethod("POST");
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
out.writeBytes("username=admin&passwor=123456");

3、OKHttp框架

okhttp算是比较优秀的网络框架,使用需要在AndroidStudio中添加依赖

1
compile 'com.squareup.okhttp3:okhttp:3.4.1'
1
2
3
4
5
6
7
8
...
OkHttpClient client = new OkHttpClient();//默认get请求
Request requset = new Requset.Builder()
.url("http://www.baidu.com")
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();//获取返回体数据
...
  • xml数据解析

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    ...
    //PUll解析
    String xmlData;
    XmlPullParseFactory factory = XmlPullParseFactory.newInstance();
    XmlPullParser parser = factory.newPullParser();
    parser.setInput(new StringReader(xmlData));
    int eventType = parser.getEventType();
    String id = "";
    String name = "";
    String version = "";
    while(eventType != XmlPullParser.END_DOCUMENT){
    String nodeName = parser.getName();
    switch(eventType){
    case XmlPullParser.START_TAG:
    //根据nodeName获取对应内容
    if("id".equals(nodeName)){
    id = parser.nextText();
    }else if("name".equals(nodeName)){
    name = parser.nextText();
    }else if("version".equals(nodeName)){
    version = parser.nextText();
    }
    break;
    case XmlPullParser.END_TAG:
    ...
    break;
    default:
    break;
    }
    eventType = parser.next();
    }

    SAX解析太繁杂。

  • JSON数据解析

    1
    [{"id":"5","version":"5.5","name":"Clash of Clans"}]
    • 使用JsonObject
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ...
    JSONArray array = new JSONArray(jsonData);
    for(int i = 0;i < array.length();i++){
    JSONObject obj = array.getJSONObject(i);
    String id = obj.getString("id");
    String version = obj.getString("version");
    String name = obj.getString("name");
    }
    ...
    • GSON

    Google开源的JSON解析工具,AndroidStudio添加Gradle依赖。compile 'com.google.code.gson:gson:2.7'Gson是一个json转化为java Bean对象的工具。

    1
    {"name":"Tom","age":"20"}
    1
    2
    Gson gson = new Gson();
    Person person = gson.fromJson(jsonData,Person.class);

    如果是json数组,需要借助TypeToken

    1
    List<Person> people = gson.from(jsonData,new TypeToken<List<Person>>(){}.getType());