Android 垃圾分类APP(二)垃圾分类之手动输入(1)

176dp

177dp

178dp

179dp

180dp

181dp

182dp

183dp

184dp

185dp

186dp

187dp

188dp

189dp

190dp

191dp

192dp

193dp

194dp

195dp

196dp

197dp

198dp

199dp

200dp

201dp

202dp

203dp

204dp

205dp

206dp

207dp

208dp

209dp

210dp

211dp

212dp

213dp

214dp

215dp

216dp

217dp

218dp

219dp

220dp

221dp

222dp

223dp

224dp

225dp

226dp

227dp

228dp

229dp

230dp

231dp

232dp

233dp

234dp

235dp

236dp

237dp

238dp

239dp

240dp

241dp

242dp

243dp

244dp

245dp

246dp

247dp

248dp

249dp

250dp

251dp

252dp

253dp

254dp

255dp

256dp

257dp

258dp

259dp

260dp

261dp

262dp

263dp

264dp

265dp

266dp

267dp

268dp

269dp

270dp

271dp

272dp

273dp

274dp

275dp

276dp

277dp

278dp

279dp

280dp

281dp

282dp

283dp

284dp

285dp

286dp

287dp

288dp

289dp

290dp

291dp

292dp

293dp

294dp

295dp

296dp

297dp

298dp

299dp

300dp

301dp

302dp

303dp

304dp

305dp

306dp

307dp

308dp

309dp

310dp

311dp

312dp

313dp

314dp

315dp

316dp

317dp

318dp

319dp

320dp

321dp

322dp

323dp

324dp

325dp

326dp

327dp

328dp

329dp

330dp

331dp

332dp

333dp

334dp

335dp

336dp

337dp

338dp

339dp

340dp

341dp

342dp

343dp

344dp

345dp

346dp

347dp

348dp

349dp

350dp

351dp

352dp

353dp

354dp

355dp

356dp

357dp

358dp

359dp

360dp

365dp

370dp

399dp

400dp

410dp

420dp

412dp

422dp

472dp

500dp

520dp

550dp

560dp

600dp

640dp

720dp

6sp

7sp

8sp

9sp

10sp

11sp

12sp

13sp

14sp

15sp

16sp

17sp

18sp

19sp

20sp

21sp

22sp

23sp

24sp

25sp

26sp

27sp

28sp

29sp

30sp

31sp

32sp

33sp

34sp

35sp

36sp

37sp

38sp

40sp

42sp

48sp

12dp

二、修改布局


在修改布局之前,先准备好需要的资源,首先是两个图标

在这里插入图片描述

在这里插入图片描述

在drawable中新建search_et_bg.xml,里面的代码如下:

<?xml version="1.0" encoding="utf-8"?>

这是设置输入框的背景

然后再新建一个cursor_style.xml,里面的代码如下:

<?xml version="1.0" encoding="utf-8"?>

<shape xmlns:android=“http://schemas.android.com/apk/res/android”

android:shape=“rectangle”>

这是设置输入框的光标颜色。

下面可以写布局了。

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout 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:layout_width=“match_parent”

android:layout_height=“match_parent”

android:fitsSystemWindows=“true”

android:orientation=“vertical”

tools:context=“.MainActivity”>

<com.google.android.material.appbar.MaterialToolbar

android:id=“@+id/toolbar”

android:layout_width=“match_parent”

android:layout_height=“?attr/actionBarSize”

android:background=“@color/colorPrimaryDark”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_gravity=“center”

android:text=“垃圾分类”

android:textColor=“@color/white”

android:textSize=“18sp” />

</com.google.android.material.appbar.MaterialToolbar>

<LinearLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:background=“@color/white”>

<RelativeLayout

android:layout_width=“match_parent”

android:layout_height=“36dp”

android:layout_marginStart=“@dimen/sp_16”

android:layout_marginTop=“@dimen/dp_12”

android:layout_marginEnd=“@dimen/dp_16”

android:layout_marginBottom=“@dimen/dp_12”

android:background=“@drawable/search_et_bg”

android:orientation=“horizontal”>

<ImageView

android:id=“@+id/iv_search”

android:layout_width=“@dimen/dp_16”

android:layout_height=“@dimen/dp_16”

android:layout_centerVertical=“true”

android:layout_marginStart=“@dimen/dp_12”

android:layout_marginEnd=“@dimen/dp_8”

app:srcCompat=“@mipmap/icon_search” />

<EditText

android:id=“@+id/et_goods”

android:layout_width=“wrap_content”

android:layout_height=“match_parent”

android:layout_toStartOf=“@+id/iv_clear”

android:layout_toEndOf=“@+id/iv_search”

android:background=“@null”

android:hint=“请输入物品”

android:imeOptions=“actionSearch”

android:singleLine=“true”

android:textColor=“@color/black”

android:textColorHint=“@color/hint_color”

android:textCursorDrawable=“@drawable/cursor_style”

android:textSize=“@dimen/sp_14” />

<ImageView

android:id=“@+id/iv_clear”

android:layout_width=“@dimen/dp_36”

android:layout_height=“@dimen/dp_36”

android:layout_alignParentEnd=“true”

android:padding=“@dimen/dp_10”

android:src=“@mipmap/icon_clear”

android:visibility=“invisible” />

<androidx.recyclerview.widget.RecyclerView

android:id=“@+id/rv_result”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:overScrollMode=“never”

android:scrollbars=“none” />

三、使用Mvp框架


下面设置接口的访问地址,打开mvplibrary下的NetworkApi类,修改正式环境的访问地址

mBaseUrl = “http://api.tianapi.com”;

如下图所示

在这里插入图片描述

下面回到app模块,在com.llw.goodtrash包下新建NetworkRequiredInfo类,里面代码如下;

package com.llw.goodtrash;

import android.app.Application;

import com.llw.mvplibrary.BuildConfig;

import com.llw.mvplibrary.network.INetworkRequiredInfo;

/**

  • 网络访问信息

  • @author llw

*/

public class NetworkRequiredInfo implements INetworkRequiredInfo {

private Application application;

public NetworkRequiredInfo(Application application){

this.application = application;

}

/**

  • 版本名

*/

@Override

public String getAppVersionName() {

return BuildConfig.VERSION_NAME;

}

/**

  • 版本号

*/

@Override

public String getAppVersionCode() {

return String.valueOf(BuildConfig.VERSION_CODE);

}

/**

  • 是否为debug

*/

@Override

public boolean isDebug() {

return BuildConfig.DEBUG;

}

/**

  • 应用全局上下文

*/

@Override

public Application getApplicationContext() {

return application;

}

}

之后再新建一个TrashApplication类,代码如下:

package com.llw.goodtrash;

import com.llw.mvplibrary.BaseApplication;

import com.llw.mvplibrary.network.NetworkApi;

/**

  • 自定义Application

*/

public class TrashApplication extends BaseApplication {

@Override

public void onCreate() {

super.onCreate();

//初始化网络框架

NetworkApi.init(new NetworkRequiredInfo(this));

}

}

自定义的Application需要到AndroidManifest.xml中去配置才会生效,如下图所示:

在这里插入图片描述

现在你就可以访问网络了,这虽然看起来是单独使用Okhttp要麻烦,但实际上是要方便很多的,你可能现在不明白,以后你会懂得。

我在天行API中请求接口使用的KEY,这里我新建了一个全局常量类,放在里面,在com.llw.goodtrash包下新建一个utils包。包下的代码如下:

package com.llw.goodtrash.utils;

/**

  • 全局常量

  • @author llw

  • @date 2021/3/30 15:14

*/

public class Constant {

/**

  • 垃圾分类的key 请替换为自己的

*/

public static final String KEY = “783da68c7ea7e10fcd259db651cc550b”;

/**

  • 请求成功码

*/

public static final int SUCCESS_CODE = 200;

}

之前通过返回的数据可以生成一个返回数据实体,在com.llw.goodtrash包下新建一个model包,包下新建一个TrashResponse类,代码如下:

package com.llw.goodtrash.model;

import java.util.List;

/**

  • 垃圾分类返回数据

*/

public class TrashResponse {

/**

  • code : 200

  • msg : success

  • newslist : [{“name”:“羽毛球”,“type”:3,“aipre”:0,“explain”:“干垃圾即其它垃圾,指除可回收物、有害垃圾、厨余垃圾(湿垃圾)以外的其它生活废弃物。”,“contain”:“常见包括砖瓦陶瓷、渣土、卫生间废纸、猫砂、污损塑料、毛发、硬壳、一次性制品、灰土、瓷器碎片等难以回收的废弃物”,“tip”:“尽量沥干水分;难以辨识类别的生活垃圾都可以投入干垃圾容器内”},{“name”:“羽毛球拍”,“type”:0,“aipre”:0,“explain”:“可回收垃圾是指适宜回收、可循环利用的生活废弃物。”,“contain”:“常见包括各类废金属、玻璃瓶、易拉罐、饮料瓶、塑料玩具、书本、报纸、广告单、纸板箱、衣服、床上用品、电子产品等”,“tip”:“轻投轻放;清洁干燥,避免污染,费纸尽量平整;立体包装物请清空内容物,清洁后压扁投放;有尖锐边角的、应包裹后投放”}]

*/

private int code;

private String msg;

private List newslist;

public int getCode() {

return code;

}

public void setCode(int code) {

this.code = code;

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

public List getNewslist() {

return newslist;

}

public void setNewslist(List newslist) {

this.newslist = newslist;

}

public static class NewslistBean {

/**

  • name : 羽毛球

  • type : 3

  • aipre : 0

  • explain : 干垃圾即其它垃圾,指除可回收物、有害垃圾、厨余垃圾(湿垃圾)以外的其它生活废弃物。

  • contain : 常见包括砖瓦陶瓷、渣土、卫生间废纸、猫砂、污损塑料、毛发、硬壳、一次性制品、灰土、瓷器碎片等难以回收的废弃物

  • tip : 尽量沥干水分;难以辨识类别的生活垃圾都可以投入干垃圾容器内

*/

private String name;

private int type;

private int aipre;

private String explain;

private String contain;

private String tip;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getType() {

return type;

}

public void setType(int type) {

this.type = type;

}

public int getAipre() {

return aipre;

}

public void setAipre(int aipre) {

this.aipre = aipre;

}

public String getExplain() {

return explain;

}

public void setExplain(String explain) {

this.explain = explain;

}

public String getContain() {

return contain;

}

public void setContain(String contain) {

this.contain = contain;

}

public String getTip() {

return tip;

}

public void setTip(String tip) {

this.tip = tip;

}

}

}

下面设置api接口,在com.llw.goodtrash包下新建一个api包,包下新建一个ApiService接口。

package com.llw.goodtrash.api;

import com.llw.goodtrash.model.TrashResponse;

import io.reactivex.Observable;

import retrofit2.http.GET;

import retrofit2.http.Query;

import static com.llw.goodtrash.utils.Constant.KEY;

/**

  • API接口

  • @author llw

  • @date 2021/3/30 15:13

*/

public interface ApiService {

/**

  • 垃圾分类

  • @param word 物品名

  • @return TrashResponse 结果实体

*/

@GET(“/txapi/lajifenlei/index?key=” + KEY)

Observable searchGoods(@Query(“word”) String word);

}

这里通过Observable观察TrashResponse,当获取到返回数据时,会解析成TrashResponse,就不需要手动去转了,而searchGoods标识方法名,后面的@Query(“word”) String word表示请求API时会把word作为参数拼接到请求地址后面。

下面构建页面访问网络的订阅类

在com.llw.goodtrash包下新建一个contract包,这个包下新建一个MainContract类。

package com.llw.goodtrash.contract;

import android.annotation.SuppressLint;

import com.llw.goodtrash.api.ApiService;

import com.llw.goodtrash.model.TrashResponse;

import com.llw.mvplibrary.base.BasePresenter;

import com.llw.mvplibrary.base.BaseView;

import com.llw.mvplibrary.network.NetworkApi;

import com.llw.mvplibrary.network.observer.BaseObserver;

/**

  • 主页面访问网络

*/

public class MainContract {

public static class MainPresenter extends BasePresenter {

/**

  • 搜索物品

  • @param word 物品名

*/

@SuppressLint(“CheckResult”)

public void searchGoods(String word) {

ApiService service = NetworkApi.createService(ApiService.class);

service.searchGoods(word).compose(NetworkApi.applySchedulers(new BaseObserver() {

@Override

public void onSuccess(TrashResponse groupResponse) {

if (getView() != null) {

getView().getSearchResponse(groupResponse);

}

}

@Override

public void onFailure(Throwable e) {

if (getView() != null) {

getView().getSearchResponseFailed(e);

}

}

}));

}

}

public interface MainView extends BaseView {

/**

  • 搜索物品返回

  • @param response

*/

void getSearchResponse(TrashResponse response);

/**

  • 搜索物品异常返回

  • @param throwable

*/

void getSearchResponseFailed(Throwable throwable);

}

}

下面回到MainActivity,先删掉上一篇添加的代码,然后修改代码如下图所示:

在这里插入图片描述

之后你需要重写五个方法。

@Override

public void initData(Bundle savedInstanceState) {

}

@Override

public int getLayoutId() {

return 0;

}

@Override

protected MainContract.MainPresenter createPresenter() {

return null;

}

@Override

public void getSearchResponse(TrashResponse response) {

}

@Override

public void getSearchResponseFailed(Throwable throwable) {

}

下面会一一修改这五个方法。

四、列表适配器


在上一篇文章中说到返回的是一个可变数组数据,那么是采用列表来显示,有列表,自然要有列表适配器,而列表适配器里面使用了item的布局。在layout下创建item_search_rv.xml,里面的代码如下:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:id=“@+id/item_search_goods”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_marginTop=“@dimen/dp_1”

android:background=“@color/white”

android:foreground=“?attr/selectableItemBackground”

android:orientation=“vertical”

android:padding=“@dimen/dp_12”>

<TextView

android:id=“@+id/tv_name”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“物品名称”

android:textColor=“@color/black”

android:textSize=“@dimen/sp_16” />

<TextView

android:id=“@+id/tv_type”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_alignParentEnd=“true”

android:text=“垃圾类型”

android:textColor=“@color/black”

android:textSize=“@dimen/sp_14” />

<TextView

android:id=“@+id/tv_explain”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_below=“@+id/tv_name”

android:layout_marginTop=“@dimen/dp_8”

android:text=“解释”

android:textColor=“@color/hint_color”

android:textSize=“@dimen/sp_14” />

然后写适配器,在com.llw.goodtrash包下新建一个adapter包,包下新建一个SearchGoodsAdapter类,代码如下:

package com.llw.goodtrash.adapter;

import android.widget.TextView;

import androidx.annotation.Nullable;

import com.chad.library.adapter.base.BaseQuickAdapter;

import com.chad.library.adapter.base.BaseViewHolder;

import com.llw.goodtrash.R;

import com.llw.goodtrash.model.TrashResponse;

import java.util.List;

/**

  • 搜索物品结果列表适配器

*/

public class SearchGoodsAdapter extends BaseQuickAdapter<TrashResponse.NewslistBean, BaseViewHolder> {

public SearchGoodsAdapter(int layoutResId, @Nullable List<TrashResponse.NewslistBean> data) {

super(layoutResId, data);

}

@Override

protected void convert(BaseViewHolder helper, TrashResponse.NewslistBean item) {

helper.setText(R.id.tv_name, item.getName())

.setText(R.id.tv_explain, item.getExplain())

.addOnClickListener(R.id.item_search_goods);

TextView tvType = helper.getView(R.id.tv_type);

switch (item.getType()) {

case 0:

tvType.setText(“可回收垃圾”);

break;

case 1:

tvType.setText(“有害垃圾”);

break;

case 2:

tvType.setText(“厨余垃圾”);

break;

case 3:

//干垃圾即其他垃圾

tvType.setText(“干垃圾”);

break;

default:

break;

}

}

}

五、页面初始化


当我们进入这个页面时要完成页面的初始化,之前是写在onCreate中完成的,现在用initData中完成。而布局id在getLayoutId中返回。

@Override

public int getLayoutId() {

return R.layout.activity_main;

}

你的onCreate方法可以删掉了,之后创建变量

private static final String TAG = “MainActivity”;

总结

最后小编想说:不论以后选择什么方向发展,目前重要的是把Android方面的技术学好,毕竟其实对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

这里附上我整理的几十套腾讯、字节跳动,京东,小米,头条、阿里、美团等公司19年的Android面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

技术进阶之路很漫长,一起共勉吧~
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
List;

/**

  • 搜索物品结果列表适配器

*/

public class SearchGoodsAdapter extends BaseQuickAdapter<TrashResponse.NewslistBean, BaseViewHolder> {

public SearchGoodsAdapter(int layoutResId, @Nullable List<TrashResponse.NewslistBean> data) {

super(layoutResId, data);

}

@Override

protected void convert(BaseViewHolder helper, TrashResponse.NewslistBean item) {

helper.setText(R.id.tv_name, item.getName())

.setText(R.id.tv_explain, item.getExplain())

.addOnClickListener(R.id.item_search_goods);

TextView tvType = helper.getView(R.id.tv_type);

switch (item.getType()) {

case 0:

tvType.setText(“可回收垃圾”);

break;

case 1:

tvType.setText(“有害垃圾”);

break;

case 2:

tvType.setText(“厨余垃圾”);

break;

case 3:

//干垃圾即其他垃圾

tvType.setText(“干垃圾”);

break;

default:

break;

}

}

}

五、页面初始化


当我们进入这个页面时要完成页面的初始化,之前是写在onCreate中完成的,现在用initData中完成。而布局id在getLayoutId中返回。

@Override

public int getLayoutId() {

return R.layout.activity_main;

}

你的onCreate方法可以删掉了,之后创建变量

private static final String TAG = “MainActivity”;

总结

最后小编想说:不论以后选择什么方向发展,目前重要的是把Android方面的技术学好,毕竟其实对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

这里附上我整理的几十套腾讯、字节跳动,京东,小米,头条、阿里、美团等公司19年的Android面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

[外链图片转存中…(img-dWn79iTE-1714679198690)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

技术进阶之路很漫长,一起共勉吧~
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值