码迷,mamicode.com
首页 > 其他好文 > 详细

低门槛入门——图灵机器人开发

时间:2015-07-20 19:45:27      阅读:321      评论:0      收藏:0      [点我收藏+]

标签:android   图灵   圆形头像   listview优化   多布局   

空闲之余,想到上次看过的一个图灵机器人开发视频。直接上其官网看开发者手册,自己动手写了一个图灵机器人小应用。编写的思路基本和网上的一些开发视频不谋而合,都是网络访问+json解析,再者就是设计出好看的界面。有兴趣的同学可以根据自己的需求进行更改甚至细化里面的查询功能,完全可以做出一款完整的app应用。先上图看看我的demo效果:


技术分享  技术分享 


这个项目主要包括三个部分:UI设计与开发、调用图灵API获取数据json解析封装成Bean、listview的优化显示。


UI设计与开发

先看下整个xml的UI布局

技术分享


布局很简单,从左上角可以看到整个布局的排版。这对于android开发者来说很easy,其中listview使用了以下设置是为了填满中间空间。


        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"


整个UI设计主要考虑的重点在于聊天边框的实现以及shape和selector的使用。

使用圆角的边缘shape文件(拿EditText为例)


<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <gradient
        android:endColor="#ffffff"
        android:startColor="#ffffff" />

    <corners
        android:bottomLeftRadius="5dp"
        android:bottomRightRadius="5dp"
        android:topLeftRadius="5dp"
        android:topRightRadius="5dp" />

    <stroke
        android:width="1dip"
        android:color="#ffffff" />

</shape>


使用圆角并实现selector文件(拿Button为例)


<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_focused="true"
        android:state_pressed="true"
        android:drawable="@drawable/start_clickafter" />

    <item android:state_focused="false"
        android:state_pressed="true"
        android:drawable="@drawable/start_clickafter" />

    <item
        android:state_selected="true"
        android:drawable="@drawable/start_clickafter"
        />

    <item
        android:state_focused="true"
        android:drawable="@drawable/start_clickafter"
        />

    <!-- 默认时的背景图片-->

    <item android:state_focused="false" android:drawable="@drawable/start_clickbefore" />

</selector>

对于聊天框的配置,我们需要实现左边和右边聊天框效果(如下图所示)


技术分享


我们需要配置左右两个xml布局。

左布局如下:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/id_time"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="10sp"
        android:layout_alignParentTop="true"
        android:gravity="center"/>

    <com.example.yummylau.turingrobot.ui.CircularImage
        android:layout_below="@+id/id_time"
        android:id="@+id/id_iv"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:padding="10dp"
        />

    <TextView
        android:layout_below="@+id/id_time"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="50dp"
        android:layout_toRightOf="@+id/id_iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/id_tv"
        android:gravity="center_vertical"
        android:textSize="17sp"
        android:background="@drawable/aio_friend_bg_nor_11"
        />

</RelativeLayout>


右布局如下:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/id_time"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="10sp"
        android:layout_alignParentTop="true"
        android:gravity="center"/>

    <com.example.yummylau.turingrobot.ui.CircularImage
        android:layout_below="@+id/id_time"
        android:layout_alignParentRight="true"
        android:id="@+id/id_iv"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:padding="10dp"
        />

    <TextView
        android:layout_below="@+id/id_time"
        android:layout_marginTop="10dp"
        android:layout_marginRight="5dp"
        android:layout_marginLeft="50dp"
        android:layout_toLeftOf="@+id/id_iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/id_tv"
        android:gravity="center_vertical"
        android:textSize="17sp"
        android:background="@drawable/aio_user_bg_nor_11"
        />

</RelativeLayout>


其中com.example.yummylau.turingrobot.ui.CircularImage是我自己实现的一个圆形头像。有兴趣的同学可以在最下方下载源码进行参考。而其实这些布局并不难,最主要的是处理好“聊天气泡”的制作。本人是使用android studio自带工具(强烈推荐)


技术分享

上述时我在实现聊天气泡时用.9.png工具来实现。如果不是android studio IDE的可以自己的Android SDK\tools目录下双击draw9.path.bat来启动这个工具。

(1)上和左各划了1dp的长度,长度是用来拉伸的。如果你图片内内容太宽或者太高,则会按照你划的高度的内容来等量延伸。举个例子,比如说你的内容在竖直方向多出了300dp,那么图片就在话的左边的点(我们是1dp)自动增加300x1dp的长度来适配你的内容。

(2)右和下一般画得比较长。上述图片中看到两个矩形相重叠,重叠部分就是我们用户用来存放内容的。点击“Show content”可以看到右侧有内容填充的演示效果。

学会了.9.png的处理,再也不用担心图片变形了。而整个应用的UI设计和开发大致也就这么多。


调用图灵API获取数据json解析封装成Bean

打开图灵机器人官网 http://www.tuling123.com/openapi/,先注册自己的账号,之后进如个人中心。找到自己的API KEY,然后保存在自己本地。而个人中心里面还有很多功能:机器人设定、机器人调教等等。可以让自己的图灵机器人自主学习,回答指定问题等等。有兴趣的朋友可以继续研究。
调用官方的API十分简单,只需要用get方法,把key和需要发送的消息(String)整合到url然后进行访问,取得系统返回的string再进行json解析就ok了。只需要以下几个步骤

(1)重写自己的网络访问类(根据自己的爱好),代码如下:

package com.example.yummy.turingrobot;

import android.os.AsyncTask;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * 异步网络访问类
 * Created by yummy on 2015/7/12.
 */
public class MyAsync extends AsyncTask<String,Void,String>{


    private String url;
    private HttpClient httpClient;
    private HttpGet httpGet;
    private HttpResponse httpResponse;
    private HttpEntity httpEntity;
    private InputStream inputStream;

    //使用回调的方法
    private CallData data;



    public MyAsync(String url, CallData data) {
        this.url = url;
        this.data = data;
    }

    /**
     * 实现后台网络访问获取数据
     * @param params
     * @return
     */
    @Override
    protected String doInBackground(String... params) {

        try{
            httpClient = new DefaultHttpClient();
            httpGet = new HttpGet(url);
            httpResponse = httpClient.execute(httpGet);
            httpEntity = httpResponse.getEntity();
            httpResponse.getStatusLine();
            inputStream = httpEntity.getContent();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String line = null;
            StringBuffer stringBuffer = new StringBuffer();
            while ((line = bufferedReader.readLine())!=null){
                stringBuffer.append(line);
            }

            return stringBuffer.toString();
        }catch(Exception e){
            return new String("亲,访问出错哦!");
        }
    }

    @Override
    protected void onPostExecute(String s) {
        data.getDataUrl(s);

    }
}

(2)写一个数据接口,使得AsyncTask能够回调MainActivity组件进行显示。(一般也可以通过在AsyncTask的构造器中传进MainActivity引用来调用其组件

package com.example.yummy.turingrobot;

/**
 * 数据回调接口
 * Created by yummy on 2015/7/12.
 */
public interface CallData {
    void getDataUrl(String data);
}

(3)MainActivity实现接口并进行网络请求(部分代码)

    @Override
         public void getDataUrl(String data) {
        System.out.println(data);
        lists.add(dataParse(data));
        //通知改变
        adapter.notifyDataSetChanged();
    }

            MyAsync myAsync = (MyAsync)new MyAsync("http://www.tuling123.com/openapi/api?" +
                    "key=<自己的key>"+"发送内容",this).execute();

(4)数据解析封装成Bean

    /**
     * 解析数据
     * @param result
     * @return
     */
    public Bean dataParse(String result){

        try{
            if(result.equals("亲,你还没有联网哦!")){
                Bean listData = new Bean(result, Bean.RECEIVER,getTime());
                return listData;
            }else{
                JSONObject jsonObject = new JSONObject(result);
                Bean listData = new Bean(jsonObject.getString("text"), Bean.RECEIVER,getTime());
                return listData;
            }
        }catch (Exception e){
            return null;
        }
    }

listview的优化显示

由于左右两边布局,传统的listview优化方法需要进行改进。一般我们使用viewholder来进行缓存,不过由于多布局适配,所以应该对应多布局缓存。
策略:使用多个viewholder进行缓存,并且根据不同布局给予不同标志,然后在getView方法中进行判断。具体代码如下:

package com.example.yummy.turingrobot;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.example.yummylau.turingrobot.ui.CircularImage;

import java.util.List;

/**
 * 适配器
 * Created by yummy on 2015/7/12.
 */
public class Adapter extends BaseAdapter{

    private List<Bean> lists;
    private Context context;
    private LayoutInflater inflater;
    private ViewHolderLeft left;
    private ViewHolderRight right;

    //布局数目
    private final int VIEW_TYPE = 2;
    //0为发送
    private final int TYPE_0 = 0;
    //1为接受
    private final int TYPE_1 = 1;



    public Adapter(List<Bean> lists,Context context) {
        this.lists = lists;
        this.context = context;
    }

    @Override
    public int getCount() {
        return lists.size();
    }

    @Override
    public Object getItem(int position) {
        return lists.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }


    /**
     * 说明下这个方法。每一个view被调用的时候都会调用此方法,获取当前所需要的view样式
     * @param position
     * @return
     */
    @Override
    public int getItemViewType(int position) {
        return (lists.get(position).getFlag()== Bean.SEND)?TYPE_0:TYPE_1;
    }


    /**
     * 返回布局类型
     * @return
     */
    @Override
    public int getViewTypeCount() {
        return VIEW_TYPE;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        left = null;
        right = null;

        inflater = LayoutInflater.from(context);

        int tpye = getItemViewType(position);
       //System.out.print(tpye+"                             ddd            ");

        //初始化布局
        if(convertView == null){

            switch (tpye){

                //0为发送
                case TYPE_0:
                    convertView = inflater.inflate(R.layout.rightitem,null);
                    right = new ViewHolderRight();
                    right.rtextView = (TextView)convertView.findViewById(R.id.id_tv);
                    right.rtime = (TextView)convertView.findViewById(R.id.id_time);
                    right.riv = (CircularImage)convertView.findViewById(R.id.id_iv);
                    convertView.setTag(right);
                    break;

                //1为接受
                case TYPE_1:
                    convertView = inflater.inflate(R.layout.leftitem,null);
                    left = new ViewHolderLeft();
                    left.ltextView = (TextView)convertView.findViewById(R.id.id_tv);
                    left.ltime = (TextView)convertView.findViewById(R.id.id_time);
                    left.liv = (CircularImage)convertView.findViewById(R.id.id_iv);
                    convertView.setTag(left);
                    break;
            }

        }else{

            switch (tpye){

                //0为发送
                case TYPE_0:
                    right = (ViewHolderRight)convertView.getTag();
                    break;

                //1为接收
                case TYPE_1:
                    left = (ViewHolderLeft)convertView.getTag();
                    break;

            }

        }


        /**
         * 设置每个布局的资源
         */
        switch (tpye){

            //0为发送
            case TYPE_0:
                right.rtextView.setText(lists.get(position).getContent());
                right.rtime.setText(lists.get(position).getTime());
                right.riv.setImageResource(R.drawable.youtouxiang);
                break;

                //1为接收
            case TYPE_1:
                left.ltextView.setText(lists.get(position).getContent());
                left.ltime.setText(lists.get(position).getTime());
                left.liv.setImageResource(R.drawable.zuotouxiang);
                break;

        }


        return convertView;

    }


    //左侧缓冲类
    static class ViewHolderLeft{
        TextView ltextView;
        TextView ltime;
        CircularImage liv;
    }

    //右侧缓冲类
    static class ViewHolderRight{
        TextView rtextView;
        TextView rtime;
        CircularImage riv;
    }


}

getViewTypeCount方法是返回我们布局的个数;
getItemViewType方法是根据数据的position来判断我们需要选哪个布局,所以这个方法的逻辑需要自己来实现。

其他的操作基本和listview的优化操作是一样。先判断convertView是否为空,空则初始化holder,不同则拿到对应标志的holder,最后适配数据进去就好了。

到从,整个图灵机器人的开发基本就结束了。

CSDN项目下载链接:图灵机器人下载链接
github项目链接:图灵机器人github链接









版权声明:本文为博主原创文章,未经博主允许不得转载。

低门槛入门——图灵机器人开发

标签:android   图灵   圆形头像   listview优化   多布局   

原文地址:http://blog.csdn.net/u010794180/article/details/46969599

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!