Android小程序-发短信-图灵机器人-简单浏览器的设计与实现

版权声明:本文为博主原创文章,未经博主允许也可随意转载。 https://blog.csdn.net/qq_35619409/article/details/80030654

少废话,先看东西【还在编辑中…】

这里写图片描述
代码链接:点这里
APK链接::点这里
首先,纯小白起步,参考了很多代码,如有抄袭……我也没干嘛,分享下经验嘛…
侧滑相关参考:

https://blog.csdn.net/s1674521/article/details/62220187

toolbar相关参考:

https://blog.csdn.net/tideseng/article/details/52804277?locationNum=3

Toolbar、侧滑布局及其功能的实现

  1. 主界面(activity_main)
    Toolbar(内嵌文字标题 ‘使用自己的标题不好居中’)+FrameLayout(点击侧滑菜单的选项即时更换FrameLayout内容)+DrawerLayout(实现侧滑,通过NavigationView添加上下两部分布局)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:theme="@style/AppTheme"
    tools:context="com.example.big_god.text.MainActivity">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="新短信"
            android:textSize="18sp"
            android:textColor="#FFF"
            android:layout_gravity="center"/>
    </android.support.v7.widget.Toolbar>
    <FrameLayout
        android:id="@+id/frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
    </LinearLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/nav"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        app:headerLayout="@layout/head"
        app:menu="@menu/my_menu"
        app:itemBackground="@color/white"
        android:layout_gravity="start"
        ></android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>

这里说明一下,Toolbar的图标自动变形想自己实现挺难…找好久才找到一个简单的方法,不用自己加图标。

//我这里声明的Toolbar 为toollbar,DrawerLayout为dl
 setSupportActionBar(toolbar);
            // 参数:开启抽屉的activity、DrawerLayout的对象、toolbar按钮打开关闭的对象、描述open drawer、描述close drawer
        ActionBarDrawerToggle abdt = new ActionBarDrawerToggle(MainActivity.this, dl, toolbar,R.string.dl_open,R.string.dl_close){
                @Override
                public void onDrawerSlide(View drawerView, float slideOffset) {
                    super.onDrawerSlide(drawerView, slideOffset);
                    //根据滑动百分比计算内容部分应该向右边移动的距离
                    int marginLeft = (int) (drawerView.getMeasuredWidth()* slideOffset);
                    //获得内容部分的View对象(内容View对象是第一个,所以是0)
                     LinearLayout contentView = (LinearLayout) dl.getChildAt(0);
                     //修改内容部分的左边距
                    contentView.setLeft(marginLeft);
            }
        };
        // 添加抽屉按钮,通过点击按钮实现打开和关闭功能; 如果不想按钮有点急功能可以不写此行代码
        adbt.syncState();
        // 设置按钮的动画效果; 如果不想要打开关闭抽屉时的箭头动画效果,可以不写此行代码
        dl.addDrawerListener(abdt);

另外设置侧栏滑出后去掉原界面的阴影需要用到这个方法

dl.setScrimColor(Color.TRANSPARENT);    //dl为DrawerLayout的对象

Fragment的切换实现

首先,要明白我只有一个Activity,动态加载Fragment到FrameLayout,这就涉及Activity获取Fragment中控件以及动态加载Fragment,要实现Fragment中的功能就有两种方法:

    1、Fragment每次加载完成时Activity获取对应Fragment的所有控件并初始化而且还要实现其事件(代码全在Activity中),我折腾了2天放弃了,要么能获取控件不能响应事件,要么程序直接崩,同时请教下这个问题;
    2、Fragment控件及其功能在Fragment中完成,Activity只负责切换Fragmnet,不扯它的控件。

下面是切换Fragment的实现

//nv为NavigationView的对象
nv.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(MenuItem item) {
                switch (item.getItemId()) {
                    case (R.id.about_item):
                    //About_fragment()为对应Fragment的Java类,内容见下段
                        getFragmentManager().beginTransaction().replace(R.id.frame, new About_Fragment()).commit();
                        title.setText("关于");
                        break;
                    case (R.id.Turing_item):
                        getFragmentManager().beginTransaction().replace(R.id.frame, new Turing_Fragment()).commit();
                        title.setText("图灵机器人");
                        break;
                    case (R.id.direction_item):
                        getFragmentManager().beginTransaction().replace(R.id.frame, new Direction_Fragment()).commit();
                        title.setText("说明");
                        break;
                    default:
                        getFragmentManager().beginTransaction().replace(R.id.frame, new Text_Fragment()).commit();
                        title.setText("新短信");
                        break;
                }
                dl.closeDrawer(nv);
                return true;
            }
        });

Fragment的Java代码
这里只举个最简单的例子看看。About_Fragment 中没有相关事件,不用对控件进行初始化,如果有控件,必须在onViewCreated()中初始化(切记)。

public class About_Fragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_about,container,false);
    }
}

浏览器功能的实现

这里浏览器功能实现得很简陋,没有按钮什么的,只实现了返回键返回上一页面这个功能,首先跳转到我自己搭建的一个服务器页面,然后提供按钮跳转到百度,到了百度然后不就可以随便去了吗?
首先看浏览器布局代码

<WebView
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></WebView>

就一个Webview,再看它的实现,包括传说中的ERR_UNKNOWN_URL_SCHEME错误的解决方法。

//申请权限
        if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.INTERNET}, 1);
        } else {
            WebSettings webSettings = webView.getSettings();
                webSettings.setJavaScriptEnabled(true);//支持js
                webSettings.setDomStorageEnabled(true);//支持dom缓存
            webView.setWebViewClient(new WebViewClient(){
                @Override
                public boolean shouldOverrideUrlLoading(WebView view, String request) {
                //关于那个错误,查了很久据说是Webview不认除http和https之外的链接导致的
                //看见过一种“解决方法”就是在这个方法中判断协议不为http和https的直接丢给外部浏览器解析,但我想要的是在这个控件中完成所有操作。
                //然后就发现这个方法只要返回true就调用外部浏览器,返回false则自己执行,于是...
                //直接返回false就莫名其妙好了,,反正我的没问题
                            return false;
                }
            });
            webView.loadUrl(url);
        }
        //返回键监听,实现页面后退功能,返回到最初的页面再按返回直接退出程序
        webView.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View view, int i, KeyEvent keyEvent) {
                if(keyEvent.getAction()==KeyEvent.ACTION_DOWN)
                    if(i==KeyEvent.KEYCODE_BACK&&webView.canGoBack()){
                            webView.goBack();
                            return true;
                }
                return false;
            }
        });

发短信

这个网上的教程很详细了,但我测试发现小米的机器发送不了,猜测应该是MIUI把Android魔改得太严重了……
如果想监听短信发送状态需要设置广播,这个……懒得做…

扫描二维码关注公众号,回复: 3012753 查看本文章
  public void sendMsg(String phoneNumber, String message) {
        //获取短信管理器
        android.telephony.SmsManager smsManager = android.telephony.SmsManager.getDefault();
        //拆分短信内容(手机短信长度限制)
        List<String> divideContents = smsManager.divideMessage(message);
        for (String text : divideContents) {
                smsManager.sendTextMessage(phoneNumber, null, text, null, null);//小米的这一行报错
        }
    }

图灵机器人模块的实现

其实也很简单,HttpURLConnection发送个链接再解析并截取它返回的数据就可以了,纯文本,特别简单,就是要注意Android是不能在主线程中发送HTTP请求的,这时候就涉及到多线程,多线程就需要用到同步。

这个CommonException 是我自定义的异常类,我用的是JSON解析的返回值。
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class HttpData {
    private static String API_KEY = "d8c6461d3956425e95b498534705554d";
    private static String URL = "http://www.tuling123.com/openapi/api";
    private StringBuilder sb;

    /*
        得到消息
     */
    public Message sendMsg(String msg) throws CommonException {
        Message message = new Message();
        String url = setParams(msg);
        String temp = Getdo(url);
        if (sb.toString().equals(url)) {
            return null;
        }
        message.setMsg(temp);
        message.setFlag(Message.RECEIVED);
        message.setTime(new SimpleDateFormat("MM月dd日 HH:mm:ss", Locale.getDefault()).format(new Date(System.currentTimeMillis())));
        return message;
    }

    /*
     * 拼接Url
     */
    private String setParams(String msg) throws CommonException {
        /** 利用Java中URLEncoder对其进行编码,如果不能实现,抛出异常 */
        try {
            msg = URLEncoder.encode(msg, "UTF-8");
        } catch (Exception e) {
            throw new CommonException("编码异常");
        }
        return URL + "?key=" + API_KEY + "&info=" + msg;
    }

    private String Getdo(String msg){
            sb = new StringBuilder(msg);
        try {
            HttpURLConnection urlConnection = (HttpURLConnection) new URL(sb.toString()).openConnection();
            urlConnection.setConnectTimeout(5 * 1000);
            urlConnection.connect();
            if (urlConnection.getResponseCode() == 200) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "utf-8"));
                String line = "";
                sb = new StringBuilder();
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
                urlConnection.disconnect();
            } else {
                throw new CommonException("连接超时");
            }
            JSONObject json = new JSONObject(sb.toString());
            if (json.getInt("code") == 100000) {
                sb = new StringBuilder(json.getString("text"));
            } else {
                throw new CommonException("提交格式出錯");
            }
        } catch (Exception e) {
        }
        return sb.toString();
    }
}

线程的处理

         try {
                                Thread thread = new Thread(){
                                    @Override
                                    public void run() {
                                        try {
                                            receive = httpData.sendMsg(msg.getText().toString());
                                        } catch (CommonException e) {
                                            Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
                                        }
                                    }
                                };
                                    thread.start();//启动线程
                                    thread.join();//子线程加入主线程的进程,意思就是主线程等子线程跑完再继续

                                if(receive==null){
                                    Toast.makeText(getActivity(), "连接出错", Toast.LENGTH_SHORT).show();
                                    return;
                                }
                                writeFile(message);//这几个函数分别是写入发送消息到文件,写入收到的消息到文件以及刷新列表视图
                                writeFile(receive);
                                bindData();
                            }catch (Exception e) {
                                Toast.makeText(getActivity(), "发送失败", Toast.LENGTH_SHORT).show();
                            }

点9图处理

这个其实没什么好讲的,就两点:

  • 1.如何生成点9图
    导入一张图片到drawable文件夹下,右键它,选择Create 9-Patch file(应该是倒数第二个),生成完就在名字后面类型名前面加上了.9的后缀,然后就可以编辑了。
  • 2.点9图的编辑
    上、左为缩放区域,下右为文本显示区域。然后就是拖拖拖,一般把缩放的区域弄成一个像素的小点就可以了。

JSON数据处理

首先,有两个包,安卓下面org那个包不太好用,只能完成Json对象与字符串的转化(注意我说的是安卓),google那个GSON包可以轻松完成bean实体类对象与字符串之间的转化,所以我直接写成了静态类。

对象《=》json字符串

public class JsonDAO {
    //传入bean对象,转为json字符串返回
    //存储时调用
    public static String getJson(Object object){
        return new Gson().toJson(object);
    }

    //传入json字符串,转为对象返回
    //读取时调用
    public static Object getObjt(String jj,Class type){
        Object o = new Gson().fromJson(jj,type);
       return o;
    }
}

json字符串《=》普通字符串

 JSONObject json = new JSONObject(sb.toString());
            if (json.getInt("code") == 100000) {
                sb = new StringBuilder(json.getString("text"));
            } else {
                throw new CommonException("提交格式出錯");
            }

猜你喜欢

转载自blog.csdn.net/qq_35619409/article/details/80030654