使用绑定服务(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()
如果应用在客户端与服务仍然绑定的状态下被销毁了,则销毁会导致客户端取消绑定。
最后来张结果图
加油!未来可期!!!