• Android之Service解析文件


    使用绑定服务(bindService)的方式启动一个解析Json文件的本地服务,并在界面中显示解析结果。

    1.创建一个Activity,界面如图所示,点击“绑定服务”按钮后,启动用来解析文件的本地服务,并在界面中输出简短提示信息“本地服务已经绑定”(使用toast实现)。

    2.点击“解析文件”按钮,解析Json文件的内容,并将数据用列表控件进行显示在界面红色区域内。

    3.点击“解绑服务”按钮,解绑当前服务,并在界面输出简短提示信息“本地服务已经解绑”。

    这部分内容写之前一脸懵,写完之后还是一脸懵

    先说说BinderService,简单来讲就是没有xml的activity。了解这点就动手可以写了,具体写的时候碰到的问题,我会加在注释里

    先上xml

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:orientation="vertical">
     6 
     7     <Button
     8         android:id="@+id/button52"
     9         android:layout_width="match_parent"
    10         android:layout_height="wrap_content"
    11         android:text="绑定服务" />
    12 
    13     <Button
    14         android:id="@+id/button53"
    15         android:layout_width="match_parent"
    16         android:layout_height="wrap_content"
    17         android:text="解析文件" />
    18 
    19     <Button
    20         android:id="@+id/button54"
    21         android:layout_width="match_parent"
    22         android:layout_height="wrap_content"
    23         android:text="解绑服务" />
    24 
    25     <ListView
    26         android:id="@+id/ListView9"
    27         android:layout_width="match_parent"
    28         android:layout_height="wrap_content" />
    29 
    30 
    31 </LinearLayout>

    这个要求是用listview显示,那我还用homework_5_2.xml来提供格式

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     xmlns:app="http://schemas.android.com/apk/res-auto"
     4     android:layout_width="match_parent"
     5     android:layout_height="match_parent">
     6 
     7     <TextView
     8         android:id="@+id/tv"
     9         android:layout_width="match_parent"
    10         android:layout_height="match_parent"/>
    11 
    12 </LinearLayout>

    以上是xml

    然后就是主要的内容了

    写binder需要自己建一个,右键->new->service->service

    建好后里面会自动生成一个onBind方法,在启动service都会同时调用startService和bindService方法,之后会回调onBind()方法,(其实我写了半天也没懂这方法有啥用),然后我自己简单理解了一下,大概就是返回中间人对象

    写的时候最困难的地方就是各种binder传来传去,主要是它这个还是异步,一开始写的时候,绑定和解绑的都不是一个连接,解析的时候各种返回空指针异常,头大。

    还有关于连接的判断,一开始是先设立了一个Boolean的flag,我这辈子再也不做这么愚蠢的事了。就是无法判断有几个连接,而且这时候写的也乱,整个就弄不了了,一直绑定绑定绑定,一直出新的页面,我差点崩了。

    然后解决就直接判断连接是不是null,而且我只建立一个公共连接,绑定和解绑都用这一个,这样就不会出现异步的情况了。

    还有就是调用的时候各种出错,烦的一批。上代码

    package com.example.app;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.annotation.SuppressLint;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.os.*;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.*;
    
    import org.json.JSONException;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.UnsupportedEncodingException;
    
    public class MainActivity extends AppCompatActivity {
    
        private Button onbutton;
        private Button Jsonbutton;
        private Button unbutton;
        private ListView Ls;
        private Myconn conn;
        private String[] Jsons;
        private MyService.MyBinder myBinder;   //公共binder,都用这一个
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.homework_11);
            //1.应该先把绑定和解绑写了,解析留在最后写
            //2.绑定咋写???????
            //3。点击按钮执行绑定或解绑
            onbutton = (Button) findViewById(R.id.button52);
            Jsonbutton = (Button) findViewById(R.id.button53);
            unbutton = (Button) findViewById(R.id.button54);
            Ls = (ListView) findViewById(R.id.ListView9);
    
            onbutton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //4.在这里面写绑定??应该是调用
                    if(conn == null){
                        Intent intent = new Intent(MainActivity.this,MyService.class);
                        conn = new Myconn();
                        bindService(intent,conn,BIND_AUTO_CREATE);  //以上三条是固定写法,就这样写就对了
                        Toast.makeText(MainActivity.this, "正在绑定。。。绑定完成", Toast.LENGTH_SHORT).show();
                    }else {
                        Toast.makeText(MainActivity.this, "已绑定", Toast.LENGTH_SHORT).show();
                    }
                }
            });
    
            Jsonbutton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //这里愁死我了,打算先这样写:这里调用服务的一个方法,然后服务里不解析json,而是服务再调用一个类来解析,中间的过程只传值,至于如何显示,那就是这里需要写的的了,应该可以
                    //好像更复杂了,还是先在服务里写一下试试
                    if(conn == null){
                        Toast.makeText(MainActivity.this, "请先绑定service", Toast.LENGTH_SHORT).show();
                    }else {
                        try {
                            InputStream json=getResources().openRawResource(R.raw.json_multiple);  //获取json文件
                            Jsons = myBinder.GetJson(json);    //将json文件传过去,并且获取返回值
                            MyBaseAdapter mAdapter = new MyBaseAdapter();  //设置listview各式
                            Ls.setAdapter(mAdapter); //将返回值显示出来
                        } catch (IOException e) {
                            e.printStackTrace();
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
    
            unbutton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(conn != null){
                        unbindService(conn);  //固定写法
                        conn = null;
                        Toast.makeText(MainActivity.this, "解除绑定", Toast.LENGTH_SHORT).show();
                    }else {
                        Toast.makeText(MainActivity.this, "未绑定", Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    
        private class Myconn implements ServiceConnection {   //这部分内容就是中间人连接了,可以通过myBinder来获取service里的方法了
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                // TODO Auto-generated method stub
            }
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                // TODO Auto-generated method stub
                myBinder = (MyService.MyBinder)service;
            }
        }
    
        class MyBaseAdapter extends BaseAdapter{ //不解释
    
            @Override
            public int getCount() {
                return Jsons.length;
            }
            @Override
            public Object getItem(int position) {
                return null;
            }
            @Override
            public long getItemId(int position) {
                return 0;
            }
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder holder;
                if(convertView == null){
                    convertView = LayoutInflater.from(getApplicationContext()).inflate(R.layout.homework_five_2,parent,false);
                    holder = new ViewHolder();
                    holder.mTextView = (TextView) convertView.findViewById(R.id.tv);
                    convertView.setTag(holder);
                }else {
                    holder = (ViewHolder) convertView.getTag();
                }
                holder.mTextView.setText(Jsons[position]);
                return convertView;
            }
            class ViewHolder {
                TextView mTextView;
            }
        }
    
    }

    然后是binder的代码

    package com.example.app;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.Binder;
    import android.os.IBinder;
    import android.widget.Toast;
    
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    
    public class MyService extends Service {
        public MyService() {
        }
        @Override
        public IBinder onBind(Intent intent) {  //3.返回定义的中间人对象
            // TODO: Return the communication channel to the service.
            return new MyBinder();
        }
        String jsonData = "";
        String[] Jsons;
        public class MyBinder extends Binder{  //1.定义中间人对象
            public String[] GetJson(InputStream json) throws IOException, JSONException {  //2.定义一个方法,调用方法
                byte[] buffer=new byte[json.available()];   //上面那个(InputStream json)json就是传过来的json文件
                json.read(buffer);
                String jsonData=new String(buffer,"UTF-8");  //一直到这里,就是把文件内容提取出来,弄成string格式
                if (jsonData != ""){
                    int a=0;
                    Jsons = new String[100];
                    JSONArray jsonArray = new JSONArray(jsonData);
                    for (int i=0;i<jsonArray.length();i++){
                        JSONObject jsonObject = jsonArray.getJSONObject(i);
                        String name = jsonObject.getString("name");
                        String age = jsonObject.getString("age");
                        String birthday = jsonObject.getString("birthday");
                        String school = jsonObject.getString("school");
                        String car = jsonObject.getString("car");
                        String house = jsonObject.getString("house");
                        Jsons[a] = "name:"+name;
                        Jsons[a+1] = "age:"+age;
                        Jsons[a+2] = "birthday:"+birthday;
                        Jsons[a+3] = "school:"+school;
                        Jsons[a+4] = "car:"+car;
                        Jsons[a+5] = "house:"+house;
                        a = a+6;   //if内的内容就是把提取出来的内容转成数组格式的
                    }
                }else {
                    Toast.makeText(MyService.this,"error",Toast.LENGTH_SHORT).show();
                }
                return Jsons;  //通过返回,把数组传回去
            }
        }
    }

    我写的时候思考的过程中加的注释就不删了,

    还有,一开始写的时候,绑定和解绑都是单独写在方法里,调来调去经常出错,为了直观就直接写在了点击按钮的事件下了。真的,一开始写的时候我是拒绝的

    这个图一定要理解

    还有几点,onBind方法里写的return,这个就是返回你的中间人对象,你的中间人对象是个变量,就返回变量,如果是方法,就返回方法

    然后你要写的具体完成的功能,都写在中间人对象里。

    我一开始写的时候,所有操作都在binder上,包括显示listview,但是出了很多错(比如它能找到xml文件,但是就是会报错),就放弃了

    小i总结一下,就是不要整太多变量,简简单单就好,理清思路,到底是哪个值在传递

    客户端绑定到服务步骤:

    1.实现ServiceConnection,重写两个回调方法:onServiceConnected()---系统会调用该方法以传递服务的onBind()返回的IBinder;onServiceDisconnected()---Android系统会在与服务的连接以外中断(或者随着activity 的生命周期stop)时调用该方法,当客户端取消绑定的时候,不会回调该方法

    2.调用bindService(),传递ServiceConnection

    3.当系统调用onServiceConnected()的回调方法时,可以使用接口定义的方法开始调用服务

    4.要断开与服务的连接,请调用unBindService()

    如果应用在客户端与服务仍然绑定的状态下被销毁了,则销毁会导致客户端取消绑定。

     最后来张结果图

    加油!未来可期!!!

  • 相关阅读:
    cookie操作和代理
    发起post请求
    scrapy核心组件
    爬取多个url页面数据--手动实现
    scrapy之持久化存储
    selenium + phantomJs
    scrapy框架简介和基础使用
    校验验证码 实现登录验证
    beautifulsoup解析
    xpath
  • 原文地址:https://www.cnblogs.com/rebirther/p/13038483.html
Copyright © 2020-2023  润新知