Android知识点(二)

2017-12-13  本文已影响0人  xx伐木累zw

七、多媒体

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);//取消通知
image.png

2、调用摄像头和相册

(1)调用摄像头拍照

image.png
 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;
    }
}
image.png

(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();
    }
  }
}
image.png

3、播放多媒体文件

(1)播放音频

image.png
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();
    }
}
}
image.png

(2)播放视频

image.png
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();
    }
  }
}
image.png

八、网络技术

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格式数据

数据源:


image.png

(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个数数据

数据源:


image.png

(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

image.png

小示例:

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)

image.png

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)解析异步消息处理机制

image.png

(4)使用AsncTask

image.png

2、服务的基本用法

(1)定义一个服务

image.png

小示例:

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()方法就能让这个服务停止下来。


image.png

(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;
    }
  }
}
image.png

3、服务的生命周期

image.png

4、服务的更多技巧

(1)使用前台服务

image.png

修改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

image.png

在服务中开启多线程可以解决上面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;


image.png

5、服务的最佳实践之完整的下载示例

源码地址

十、基于位置的服务(百度、高德地图)

下面的所有功能都参考百度官网的开发文档来做:百度地图开放平台 | 百度地图API SDK | 地图开发

image.png

1、申请API Key

image.png
image.png

2、使用百度定位

Android 定位SDK

3、使用百度地图

Android 地图SDK

image.png

十一、Material Design(Android5.0)

1、Toolbar

Toolbar取代ActionBar

2、滑动菜单

DrawerLayout NavigationView

3、悬浮按钮和可交互提示

FloatingActionButton Snackbar CoordinatorLayout

4、卡片式布局

CardView AppBarLayout

5、下拉刷新

SwipeRefreshLayout

6、可折叠式标题栏

CollapsingToolbarLayout

十二、更多高级技能

1、全局获取Context的技巧

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

2、使用Intent传递对象

3、定制自己的日志工具

4、调试Android程序

5、创建定时任务

6、多窗口模式编程

上一篇 下一篇

猜你喜欢

热点阅读