系列目录
从零开始用Andrid Studio开发一个简单的垃圾分类查询APP(1)
从零开始用Andrid Studio开发一个简单的垃圾分类查询APP(2)
从零开始用Andrid Studio开发一个简单的垃圾分类查询APP(3)
从零开始用Andrid Studio开发一个简单的垃圾分类查询APP(4)-完结篇
正文
时隔几天了,我终于回来更新了,(没有想好什么理由那就只能“啊哈哈”一下了)
书接上回
上回书说到,我们在首页通过新建并引用布局文件添加了一个顶部导航栏,并在上面随便放了两个按钮。
回到现在
那么接下来我们该做什么呢?
当然是继续做首页的布局啦,距离我们目标首页,还差一张图,一个输入框,一个搜索按钮,以及一个引用句子。
那么现在就开始插入图片吧。
1.首页布局
插入图片很简单,在activity_main.xml文件中写一个ImageView就可以了,
<ImageView
android:id="@+id/main_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/protectenvironment"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/include" />
接下来是添加搜索用的单行输入框和搜索按钮,
这里用一个EditText和一个Button来实现,很简单,不过楼主这之前发现了一个很有意思的东西,ConstraintLayout库,我们一般的AS的可视化操作很拉胯,基本什么都做不到,但是有了这个,我们可以直接用可视化工具来放控件了,说着楼主就试了试。
具体和这个库相关的可以移步看下面这个链接:
Android新特性介绍,ConstraintLayout完全解析
关于如何引入依赖的问题,楼主试了很多次,发现在build.gradle文件里直接输入几乎没有成功过(可能是楼主确实手残),和楼主一样的朋友们,大家可以在 “ File-Project Structure“ 中的 Dependencies 的中间
点击这个加号按钮,然后在搜索框中输入库名,注意:一定要输入尽可能完整地名字!
这个搜索系统很怪,楼主以前有次用这个搜索,只输入关键词,结果根本找不到,直到后面输入了全名,打开了新世界的大门。
找到之后哦双击就可以导入了,AS会自动下载引用这个库。
完成之后,我们就可以直接切换成Design模式,然后拖控件和控制缩放了(当然,控件的动作还是要用代码的啦)(这里把能拖的边都拖一拖,不然会有提示报错,不过这个错没什么影响)
最后再拖入一个textview,我们首页的初步布局就做好了。
在连接api前,我发现一个问题:我们首页要什么返回啊歪?
所以我把返回删了,另外删了之后,我发现之前的LinourLayout线性布局就不行了,我们的“补充”按钮会自己跑到前面,除非我留着一个文本框把它怼在后面,所以我把title改成了RelativeLayout,
改后代码如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:background="@drawable/title_bg">
<Button
android:id="@+id/title_add"
android:layout_width="108dp"
android:layout_height="55dp"
android:layout_gravity="center"
android:layout_marginStart="298dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:background="@drawable/add_bg"
android:text="我有补充"
android:textColor="#fff" />
</RelativeLayout>
用margin来控制button的位置,很怪(大概有问题),不过能成功就行了。
2.连接API
好了,回到正题,如何连接API呢?
好了,这是一个大问题,我不会了(菜鸡的我)。
还是继续查吧~
课本上的API导入示例是百度地图的API,看了一下,发现和我们要用的天行数据API用法差距好大,至少天行数据没有提供给我们什么专用的sdk,好了,课本没用了(丢)。
经过楼主半个多小时的查询,最终还是没有查到什么详细的答案
(此贴完结,楼主已跳楼)(误)
但是,天无绝人之路,感谢这位大佬的博客
以及附带的源码,让我重新看到了希望。
话不多说,这就下载下来看看大佬是怎么导入API的。
导入大佬的APP看一下,
好家伙,还要重新下gradle,我哭了。还记得当时刚装这个的时候,额,我好像没遇到问题。
还记得刚开始帮朋友装AS的时候,他的gradle一直下载不了,不管怎么改。
这个下载的好慢,但是真的不敢动。
2S.所以在下载的时候,我们再来梳理一下现在的思路:
我们现在完成了两个xml,分别是一个导航栏的,一个是首页布局的。
首页的布局我们已经完成了,其中“补充”按钮我们打算通向一个单独的页面,其中可以输入“垃圾名称”、“垃圾描述”、“垃圾分类”的内容,并包含一个按钮用来把信息放入数据库,还有一个按钮用来返回。完成后,会在页面下方出现完成的小提示。
“搜索”按钮用于向网页API发送数据,并返回到一个新的结果页面,结果页面可以把返回结果按列表排列,列表上显示“名称”、“分类”,进一步点开显示“名称”、“分类”、“分类解释”、“包含信息”、“小提示”,至于为什么这么多,因为它返回的信息就这么多。另外这两个页面也都需要有返回按钮,但不需要发布按钮。
“美句”模块导入api后,还需要一个计时器,比如每隔多久自动发送一次数据换一个句子,做不到的话就切换页面换个句子也行。
暂定的页面就这么多,也就是还需要4个页面包含单独的布局和活动及一个包含返回的导航栏。
额,好吧,下载完gradle好像也没什么用,没有办法打开,看了一下是因为什么东西只适配我现在的6.1.1版本,所以我在弹出的窗口改成了6.1.1,结果就成了,试了下,可以打开大佬的app了。(为了测试我还专门给模拟器里装了一个搜狗)
package aclass.com.example.garbgeapp.Untils;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
public class OkhttpUntils {//封装的网络访问的代码
public static void OkHttpPost(String url, String json, Callback callback){//这个是post方法访问数据,这里没有使用,不需要管
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(MediaType.parse("application/json;charset=utf-8"),json);
Request request = new Request.Builder().url(url).post(body).build();
client.newCall(request).enqueue(callback);
}
public static void OkHttpGet(String url, Callback callback){//这里APP访问采用的是get获取数据的方法,向网络发送请求
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(callback);
}
}
从上面的代码中可以看出,大佬用了一个Okhttp包,关于get和post两种请求方式,我这里就不赘述了,我大概的理解就是get传数据少而且不安全,post可以传大文件且较安全一点,但是get更方便,直接挂在url后面就可以了。
那~我们这个肯定就用get方法了。
我在java文件夹下创建了一个For_API的文件夹用于专门放和api相关的文件,然后新建了一个java class用于封装get方法。
不过在这之前,我们还需要下载一个Okhttp的jar包,这个包网上随便就能找到离线包,(CSDN已经有了,我也上传不了,所以大家自己找找吧)
package For_API;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class Okhttp_work {
public static void OkHttpGet(String url, Callback callback){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(callback);
}
}
封装完成后,下一步就是操作首页了,先依次声明一下我们的控件,
private EditText text_search_garbage;
private Button btn_add_garbage,btn_search_garbage;
private TextView tv_beauty;
接下来我们用美句来学习怎么调用网页API,
首先定义两个字符串用来放我们的url头部(大概这么叫可以吧)
String url_beauty="http://api.tianapi.com/txapi/sentence/index?key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&";//“xxxxxxxxxxx..."替换为APIkey
String url_garbage="http://api.tianapi.com/txapi/lajifenlei/index?key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&word=";
接着定义一个handler,用来发送信息,同时初始化网络:
public void intn() {
View view = getWindow().peekDecorView();
if (view != null) {//这里是网络访问的代码,获取服务
InputMethodManager inputmanger = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputmanger.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
Handler handler_beauty=new Handler(new Handler.Callback() {//首先通过handler发送信息
@Override
public boolean handleMessage(@NonNull Message msg) {
switch (msg.what){
case 0:
Toast.makeText(MainActivity.this,"网络错误",Toast.LENGTH_LONG).show();
break;
case 1:
String json=(String)msg.obj;
try{
JSONObject js=new JSONObject(json);
String content=js.getString("content");
tv_beauty.setText(content);
break;
}catch (JSONException e){
e.printStackTrace();
}
}
return false;
}
});
private void initData_beauty(){ //接着用这个方法调用handler,并把返回的信息放入TextView
handler_beauty.sendEmptyMessage(0);
Okhttp_work.OkHttpGet(url_beauty, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String content=response.body().string();
Message message=new Message();
message.what=1;
message.obj=content;
}
});
}
最后在定义一个handler_time用于不断重复刷新我们的美句:
private Handler handler_time=new Handler();
private Runnable task=new Runnable() {
@Override
public void run() {
handler_time.postDelayed(this,5*1000);
initData_beauty();//这里放重复操作
}
};
最后在onCreate方法里调用handler_time:
handler_time.post(task);
好了,大功告成了,现在来测试一下,
… … … …
不出意外,我们的程序,成功闪退了。
现在就是debug时间了,我先试着把这次添加的内容全部注释了,测试一下原程序可不可以跑,因为一直切换两个不同环境的程序让我有点害怕,不过结果很喜人,是可以跑的。
也就是说,错误出在我们添加的这一段代码上。
我的第一个猜测,就是没有申请网络服务,玩过手机盗版游戏的都知道,一些老游戏在打开之后会闪退,因为它不会自己申请权限,我们在设置里给它权限,就可以play了。所以我们先试试给权限之后,我们的程序能不能打开。
很明显问题没有那么简单,
我发现还要在AndroidManifest.xml中声明一下网络权限,所以在其中添加了如下代码:
<uses-permission-sdk-23 android:name="android.permission.INTERNET"/>
再打开程序,好了一点,尽管依旧闪退,但是它发了一个提示:“网络错误”。是我们handler_beauty里面的第一种情况。
在手机中看数据,发现我们的程序用了805b的网络:
发生甚么事了????
在我测试了一个小时之后,还是没找到问题。
楼主决定今天就更新到这里了(因为已经12点30了)。