Android Review---3

Android Review—3

零蚀

  • 网络简述

    • webView简单应用
    //申请网络权限后
    WebView webView = (WebView) findViewById(R.id.web);
    //获取设置浏览属性的类websetting
    WebSettings settings = webView.getSettings();
    //支持javascript脚本
    settings.getJavaScriptEnabled();
    //页面跳转时还是在webView里面进行显示
    webView.setWebViewClient(new WebViewClient());
    webView.loadUrl("http://www.baidu.com");
    
    • HttpURLConnection简单应用
    //耗时操作,要在线程里操作
    new Thread(new Runnable() {
         @Override
         public void run() {
             //网络请求
             request();
         }
    }).start();
    /*
    * 请求网络
    * */
    private void request() {
        try {
            //网址(baidu返回是null,hahaha)
            URL url=new URL(address);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(1000);
            connection.setReadTimeout(1000);
            InputStream inputStream= connection.getInputStream();
            //对输入流进行缓冲读取,(缓冲的本质,是由于各个硬件的运作效率不同的产物)
            reader = new BufferedReader(new InputStreamReader(inputStream));
            Log.e(TAG, "onCreate: "+reader.readLine() );
            String line;
            while ((line= reader.readLine())!=null){
    
                Log.e(TAG, "onCreate: "+line );
            }
    
        } catch (Exception e) {
            Log.e(TAG, "Exception: "+e.getMessage() );
        }finally {
            if(reader!=null){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(connection!=null){
                connection.disconnect();
            }
        }
    }
    
    //        psot提交信息
    //        connection.setRequestMethod("POST");
    //        DataOutputStream out= new DataOutputStream(connection.getOutputStream());
    //        out.writeBytes("username=aaa&password=123");
    
    • OkHttp的简单使用

    🔗OkHttp的github链接
    关于协议,加密,授权,编码,结构,网络请求方法原理等细节见网络篇

    • XML数据格式如下:
    <total>
        <item>
            <id>001</id>
            <name>Anny</name>
            <age>120</age>
        </item>
    </total>
    
    • XML解析之pull解析
    //XML解析
    String xmlData="<data>假如这是一个xml数据</data>";
    //pull解析
    parseXMLWithPull(xmlData);
    /**
     * @param xmlData
     */
    private void parseXMLWithPull(String xmlData) {
        try {
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser xmlPullParser = factory.newPullParser();
            xmlPullParser.setInput(new StringReader(xmlData));
            int eventType = xmlPullParser.getEventType();
            while(eventType!=xmlPullParser.END_DOCUMENT){
                String nodeName=xmlPullParser.getName();
                switch (eventType){
                    //开始解析节点
                    case XmlPullParser.START_TAG:
                        //匹配开始的标签对
                        if("id".equals(nodeName)){
                            id = xmlPullParser.nextText();
                        }
                        //.....
                        break;
                    //完成解析某个节点
                    case XmlPullParser.END_TAG:
                        if("item".equals(nodeName)){
                            Log.e(TAG,"id="+id);
                            //.....打印item标签里的所有属性值
                        }
    
                }
                //将"指针"移到下一位
                eventType=xmlPullParser.next();
            }
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    • XML解析之sax解析
    //解析类
    public class ContentHandle extends DefaultHandler {
    
        public static final String TAG="TAG_CONTENTHANDLE";
    
        private String nodeName;
    
        private StringBuilder id;
    
        @Override
        public void startDocument() throws SAXException {
            super.startDocument();
            id=new StringBuilder();
    
        }
    
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            super.startElement(uri, localName, qName, attributes);
            //记录当前的节点名
            nodeName=localName;
        }
    
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            super.characters(ch, start, length);
            //添加内容
            if ("id".equals(nodeName)){
                id.append(ch, start, length);
            }else{
                //......
            }
        }
    
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            super.endElement(uri, localName, qName);
    
            if ("item".equals(localName)){
                Log.d(TAG, "endElement: id is"+id.toString().trim());
                Log.d(TAG, "endElement: name is");
                Log.d(TAG, "endElement: XXX is");
            }
            //清空StringBuilder
            id.setLength(0);
    
        }
    
        @Override
        public void endDocument() throws SAXException {
            super.endDocument();
        }
    }
    
    /**
     * 解析方法
     * @param xmlData
     */
    private void parseXMLWithSAX(String xmlData) {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            XMLReader xmlReader = factory.newSAXParser().getXMLReader();
            ContentHandle contentHandle=new ContentHandle();
            xmlReader.setContentHandler(contentHandle);
            xmlReader.parse(new InputSource(new StringReader(xmlData)));
    
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    
    }
    
    • json数据格式一般如下:
    {"id":1,"version":2,"name":"Anny"}
    
    • json解析用的一般是GSON开源库

    🔗GSON的Github链接
    关于协议,加密,授权,编码,结构,网络请求方法原理等细节见网络篇


  • 服务

    服务并不会自动开启线程,所有代码默认运行在主线程中。所以要自行开发子线程。

    • 多线程
    //Thread类
    
    * @param  target
     *         the object whose {@code run} method is invoked when this thread
     *         is started. If {@code null}, this classes {@code run} method does
     *         nothing.
     */
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    .............
    /**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
    ............
    
    

    可见Thread通过init来创建一个线程,然后调用target(Runnable)接口方式将run()方法的内容放入线程中。

    拓展见Android 线程篇(新增)

    子线程中不能更新UI需要所以需要转化到主线程中更新UI

    //切换到主线程中
    runOnUiThread(new Runnable() {
            @Override
            public void run() {
                
            }
        });
        
    //源码
    /**
     * Runs the specified action on the UI thread. If the current thread is the UI
     * thread, then the action is executed immediately. If the current thread is
     * not the UI thread, the action is posted to the event queue of the UI thread.
     *
     * @param action the action to run on the UI thread
     */
    public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }
    

    runOnUiThread是Activity中的一个方法,判断若是在线程中,则通过handle将runnable的内容post到主线程中。

    • 异步消息处理之handler
    @SuppressLint("HandlerLeak")
    Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 1:
                    Toast.makeText(Main2Activity.this, "来了老弟", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };
    /**
     *线程中发送消息
     */
     new Thread(new Runnable() {
            @Override
            public void run() {
                Message message = new Message();
                message.what=1;
                handler.sendMessage(message);
            }
        }).start();
        
    //这里有个内存泄漏的提示,可以在destory销毁handler解决,或者自定义,然后若引用解决
    //@Override
    //protected void onDestroy() {
    //    super.onDestroy();
    //    handler.removeCallbacksAndMessages(null);
    //}
    
    //这种方法也能切回主线程
     handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.e(TAG, "run: "+Thread.currentThread().getName() );
                    }
                });
    
    • 解析异步消息
    1. Message 是线程间传递的消息,它可以在内部携带少量的信息,用于在不同线程间交换数据。除what字段外,还可以使用arg1和arg2字段来携带一些整形的数据,使用obj也可以携带一个object对象。
    2. Handler 是处理者,用于发送和处理消息,发送一般是sendMessage()方法,而发送消息是经历了一系列的辗转处理后最终送到了handlerMessage()方法中。
    3. MessageQueue() 是消息队列的意思,它主要存放所有通过handler发送的消息,这部分消息会一直存在于消息队列中等待被处理,每个线程中有一个消息队列
    4. Looper是线程中MessageQueue的管理者,调用Looper的loop()方法,就会进入一个无限循环的当中,然后发现MessageQueue中存在一个消息就会将它取出,并传递到handlerMessage中。每个线程都有一个Looper对象。
    MessageQueue
    next
    很多Message
    回调dispacth方法
    发送新消息
    Message
    Message
    Messages
    Looper
    Handler
    handlerMessage方法
    Handler机制
    • AsyncTask

    AsyncTask是一个抽象类。所以要继承他。

    /**
     * AsyncTask的三个范型参数
     * Params 执行时所要传入的参数,可用于后台任务中使用
     * Progress 进度单位
     * Result 返回值类型
    */
    public class MyTask extends AsyncTask<Void,Integer,Boolean> {
    
    
        //执行前调用,用于初始化操作
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
    
        //子线程中运行,在这里处理耗时任务。
        @Override
        protected Boolean doInBackground(Void... voids) {
            //耗时任务
            //将进度发送给Update方法
            publishProgress(100);
            //return 的结果返回给onPostExecute方法接收处理
            return null;
        }
    
        //更新程度
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
        }
    
        //结果
        @Override
        protected void onPostExecute(Boolean aBoolean) {
            super.onPostExecute(aBoolean);
        }
    }
    
    //调用
    new MyTask().execute();
    
    • 服务

    首先注册,或者在new中创建一个service,其中export指是否供外界调用。

    <service
            android:name=".util.MyService"
            android:enabled="true"
            android:exported="true"></service>
    

    启动/停止

    //启动一个服务
    Intent intent=new Intent(this, MyService.class);
    startService(intent);
    //停止一个服务
    stopService(intent);
    

    Service给Activity的通信

    //创建binder对象,用于service和activity的媒介
    //添加name来进行传值c测试
    public class MyBinder extends Binder {
    
        String name="";
        public MyBinder() {
        }
        public MyBinder(String name){
            this.name=name;
        }
    
        public void startDownLoad(){
            //下载
            Log.e("TAG", "startDownLoad: "+name);
        }
        public void getProgress(){
            //获取进度
        }
    }
    
    //创建service类,将binder对象返回
    public class MyService extends Service {
        public MyService() {
        }
    
    
        /**
         * 服务绑定的方法
         * @param intent
         * @return Return the communication channel to the service
        */
        MyBinder binder=new MyBinder("来了老弟");
        @Override
        public IBinder onBind(Intent intent) {
            return binder;
        }
    
        //第一次创建会调用
        @Override
        public void onCreate() {
            super.onCreate();
        }
    
        //只要服务启动就会走这个方法
        //如果多次点击startService(),这个方法每次都会被执行到
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
        }
    
    }
    
    
    ServiceConnection conn=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //在服务绑定的时候被调用
            MyBinder binder = (MyBinder) service;
            binder.startDownLoad();
            binder.getProgress();
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
            //服务解绑的时候被调用
        }
    };
    //绑定服务,将conn中的binder和service的binder绑定
    //第三个参数,是服务自动创建,oncreate方法执行onstartcommand方法不执行
    Intent binder=new Intent(this,MyService.class);
    bindService(binder,conn,BIND_AUTO_CREATE);
    
    //结束后别忘了解绑
    unbindService(conn);
    

    *前台服务
    服务的优先级问题,虽然服务一般会运行在后台,但是由于系统不会让应用一直骚扰用户,所以服务的优先级是比较低的,所以想让服务一直存在,就要用到保活手段,首先,能用💰摆平的都不是问题,就是开通白名单,其次也可用一个像素activity保活手段,但是有些手机无效。除此之外,以下是提升Service优先级的方法,将后台服务变为前台服务,但是前台服务,会弹出一个Notification来提醒用户,根据用户意愿来设置:

    
    //MyService中onCreate()方法
    //创建通道
    NotificationManager manager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.O){
        NotificationChannel channel = new NotificationChannel(
                    "channelID",
                    "channelName",
                    NotificationManager.IMPORTANCE_HIGH);
            manager.createNotificationChannel(channel);
        }
    
    //前台服务
    Intent intent=new Intent(this, Main2Activity.class);
    PendingIntent pi=PendingIntent.getActivities(this,0,new Intent[]{intent},0);
    Notification notification = new NotificationCompat.Builder(this,"channelID")
                .setContentText("Notifacation")
                .build();
    startForeground(1,notification);
    
    
    • IntentService

    应用场景:服务内的异步线程执行逻辑结束,服务也跟着stop,相当于在服务里面开了一个子线程,线程结束,服务结束,(也要注册的,苟富贵,莫相忘)

    
    //继承IntentService
    public class MyIntentService extends IntentService {
        /**
         * Creates an IntentService.  Invoked by your subclass's constructor.
         *
         * @param name Used to name the worker thread, important only for debugging.
        */
        public MyIntentService(String name) {
            super(name);
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            //耗时操作的方法
            Log.e("TAG", "努力耗时操作" );
            Log.e("TAG", Thread.currentThread().getName() );
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
    
            Log.e("TAG", "onDestroy: 执行到MyIntentService了" );
        }
    }
    
    //启动服务
    Intent intent=new Intent(this,MyIntentService.class);
    startService(intentService);
    
    • 基于位置的服务

    定位功能分为两种,一个是GPS,一个是网络定位。GPS定位是手机内硬件自带的定位功能,精准度很高,但是缺点是只能在室外进行定位,室内无法接收到卫星的信号,网络定位是根据手机附近三个基站进行测试,以此来计算出手机和每个基站的距离,再通过三角定位确定出一个大致的范围,以下会用第三方库进行定位,百度地图:

    🔗百度地图开放平台

    第一步:需要发布版和开发版的SHA1,它指打包程序时候用的申请API KEY的必须要填的一个字段,它指打包程序时候所用签名文件的SHA1指纹,可以通过Android studio进行查看(debug):

    右侧Gradle选项
    项目名
    :app
    Task
    signingReport

    便会在logcat中打印SHA1信息信息,目前用的是debug.keystore文件所生成的指纹,但是若要正式的签名,打包生成key,注意创建key store path 以文件名结尾,生成对应文件…/xx.jsk。
    然后获取SHA1

    keytool -list -v -keystore keystore;
    

    第二步:填入开发SHA1和发布SHA1

    第三部:下载SDK,(我是找了一会没有发现跳转,点图标过来的,厉害了)

    🔗百度地图SDK下载链接

    🔗百度地图SDK开发文档

    后续的接入函数,初始化SDK,文档写的非常详细,抄抄就行。至于导入SDK后的最初呈现效果,就不贴图了(最不喜欢贴图,还要重新上传,省事)。

    mapStatus 地图状态
    compassEnable 是否开启指南针,默认开启
    mapType 地图模式,默认为普通地图
    rotateGesturesEnabled 是否允许地图旋转手势,默认允许
    scrollGesturesEnabled 是否允许拖拽手势,默认允许
    overlookingGesturesEnabled 是否允许俯视图手势,默认允许
    zoomControlsEnabled 是否显示缩放按钮控件,默认允许
    zoomControlsPosition 设置缩放控件位置
    zoomGesturesEnabled 是否允许缩放手势,默认允许
    scaleControlEnabled 是否显示比例尺控件,默认显示
    scaleControlPosition 设置比例尺控件位置
    logoPosition 设置Logo位置

    • 案例:
    //比如切换地图模式
    //mBaiduMap是地图控制器对象
    mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
    

    百度地图的文档基础功能有几点要注意的:

    首先,很容易定位到一个4.9E-324的值,这可能是你权限问题,因为,手机基本都是6.0以上的,所以要动态申请权限,不然就获取经纬度失败,返回默认值4.9E-324。需要动态添加权限:

    public class PermissionUtil {
    
        public static void request(Activity activity, PermissionInterface listener){
            List<String> per = new ArrayList();
    
    
    
            if(ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION)!= PackageManager.PERMISSION_GRANTED){
                per.add(Manifest.permission.ACCESS_COARSE_LOCATION);
            }
            if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
                per.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
            }
            if(ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED){
                per.add(Manifest.permission.ACCESS_FINE_LOCATION);
            }
            if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE)!= PackageManager.PERMISSION_GRANTED){
                per.add(Manifest.permission.READ_PHONE_STATE);
            }
    
            if(per.size()!=0){
                String permission[]=per.toArray(new String[]{});
                ActivityCompat.requestPermissions(activity,permission,1101);
            }else{
                if(listener!=null){
                    listener.granted();
                }
            }
        }
    }
    

    其次一点是,百度文档上的定位,是会在你的坐标上,多一个点标示,并不会自己把地图移动到你的位置上方,很坑,因为文档上一眼看上去也没有定位到目标位置的方法,所以查了一下方法如下:

    MyLocationData locData = new MyLocationData.Builder()
                .accuracy(location.getRadius())
                // 此处设置开发者获取到的方向信息,顺时针0-360
            .direction(location.getDirection()).latitude(location.getLatitude())
                .longitude(location.getLongitude()).build();
    
    mBaiduMap.setMyLocationData(locData);
    /**
      *
      *------------以上是文档中获得经纬度坐标的方法----------------------
      *
      */
    //将地图移到我所定位的地方
    LatLng latLng=new LatLng(locData.latitude,locData.longitude);
    MapStatusUpdate update= MapStatusUpdateFactory.newLatLng(latLng);
    mBaiduMap.animateMapStatus(update);
    

笔记资料来自书籍《第一行代码》郭霖,无商业目的

🔗 前言
🔗 Android Review 列表
🔗 Android Review—1
🔗 Android Review—2
🔗 Android Review—4
🔗 Android Review—5

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零蚀zero eclipse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值