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()

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

 最后来张结果图

 

 

加油!未来可期!!!

posted @ 2020-06-03 16:42  非凡的静静  阅读(644)  评论(1编辑  收藏  举报