其他分享
首页 > 其他分享> > 从零开始用Andrid Studio开发一个简单的垃圾分类查询APP(4) —完结篇

从零开始用Andrid Studio开发一个简单的垃圾分类查询APP(4) —完结篇

作者:互联网

已经是写这个小APP的第四天了,今天我们继续看看能实现到什么程度。

(续)1.搜索结果页面布局

上个帖子中我们已经决定了就用ListView进行布局,接下来就是我们美化定制这个ListView了。
关于定制ListView,我们尝试跟着课本走一次:
新建一个garbages文件夹,用于放我们的“垃圾”,然后在其中新建一个Garbage_list类,用于作为ListView的适配器的适配类型。
我们在第二个帖子里已经决定了,在这个选项里面放的是“名字”和“分类”,代码如下:

public class Garbage_list {
    private JSONObject search_result= MainActivity.Search_JSON;
    private String name;
    private int garbage_type;           //0是可回收,1是有害垃圾,2是厨余垃圾,3是干垃圾(其它垃圾)
    private String[] garbage_type_string={"可回收垃圾","有害垃圾","厨余垃圾","其它垃圾(干垃圾)"};

    public Garbage_list(JSONObject the_garbage_JSON) throws JSONException {
        name=the_garbage_JSON.getString("name");
        garbage_type=Integer.parseInt(the_garbage_JSON.getString("type"));
    }
    
    public String getName(){
        return name;
    }
    
    public String getType(){
        return garbage_type_string[garbage_type];
    }
}

这里的代码随便写写,很简单的,大家应该都看得懂,其中只涉及到一个字符串转数字。

接下来我们为选项指定一个自定义布局,同样,在layout目录下新建一个garbage_item.xml,代码如下:

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

    <TextView
        android:id="@+id/garbage_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"/>

    <TextView
        android:id="@+id/garbage_type"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"/>
    
</LinearLayout>

我们写了两个TextView,且都设置为竖直居中。

然后我们创建一个自定义适配器,将泛型指定为Garbage_list类,(泛型是甚么东西?不知道,推荐不知道的朋友们百度一下,我也不细说了。)
我们在垃圾文件夹中新建一个类Garbage_adapter,代码如下:

public class Garbage_adapter extends ArrayAdapter {
    private int resourceId;
    
    public Garbage_adapter(Context context, int textViewResourceId, List<Garbage_list> objects){
        super(context,textViewResourceId,objects);
        resourceId=textViewResourceId;
    }
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent){
        Garbage_list garbage_list= (Garbage_list) getItem(position);
        View view= LayoutInflater.from(getContext()).inflate(resourceId, parent,false);
        TextView garbageName=(TextView)view.findViewById(R.id.garbage_name);
        TextView garbageType=(TextView)view.findViewById(R.id.garbage_type);
        garbageName.setText(garbage_list.getName());
        garbageType.setText(garbage_list.getType());
        return view;
    }
}

这里我也不太懂,大概就是把之前的类实时传给布局文件的意思吧。
接下来我们为SearchActivity中修改代码:

public class SearchActivity extends AppCompatActivity {
    private JSONObject search_result=MainActivity.Search_JSON;      //用于接收MainActivity中的搜索结果
    private List<Garbage_list> garbageList=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search);
        ActionBar actionbar=getSupportActionBar();
        if(actionbar!=null){
            actionbar.hide();
        }

        try {
            init_garbage_list();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        Garbage_adapter adapter=new Garbage_adapter(SearchActivity.this, R.layout.garbage_list, garbageList);
        ListView listView=(ListView)findViewById(R.id.search_listview);
        listView.setAdapter(adapter);


    }

    private JSONObject make_the_JSON(int i) throws JSONException {            //用于将JSON转换为字符串数组
        JSONArray newslist=search_result.getJSONArray("newslist");
        String[] name=new String[newslist.length()];
        String newslistString=new String();
        JSONObject the_garbage_JSON=new JSONObject();       //具体某一项的json ,可以通过getstring获得其中具体的项
        newslistString=newslist.getString(i);
        the_garbage_JSON=new JSONObject(newslistString);
//        name[i]=the_garbage_JSON.getString("name");
        return the_garbage_JSON;
    }


    private void init_garbage_list() throws JSONException {
        JSONArray newslist=search_result.getJSONArray("newslist");
        for(int i=0;i<newslist.length();i++){
            Garbage_list the_garbage=new Garbage_list(make_the_JSON(i));
            garbageList.add(the_garbage);
        }
    }
}

运行一下:

好家伙,够接地气,书上的部分就结束了,因为书上是图片加文字,所以什么都不设置都能看,我们这个就不行了。
这里楼主首先试了试把garbage_list.xml改成RelativeLayout,结果发现页面切换不过去了,可能是因为我们现在的适配器没法适配这个的原因吧,所以我们只能回来继续用LinearLayout继续调试了,经过楼主的不断改动,终于是可以看了:如图:

代码如下:

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

    <TextView
        android:id="@+id/garbage_name"
        android:layout_width="245dp"
        android:layout_height="60dp"
        android:layout_alignParentTop="true"
        android:layout_gravity="center_vertical"
        android:layout_marginTop="0dp"
        android:gravity="center_vertical"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        android:textSize="20dp" />

    <TextView
        android:id="@+id/garbage_type"
        android:layout_width="165dp"
        android:layout_height="60dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_gravity="center_vertical"
        android:layout_marginTop="0dp"
        android:layout_marginEnd="-6dp"
        android:layout_marginRight="-6dp"
        android:gravity="center"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium" />

</LinearLayout

接下来我们依次为搜索页面的控件添加事件,首先是上面的搜索组合:
先声明一下控件和url:

	private EditText text_search_garbage;
    private Button btn_search_garbage;
        String url_garbage="https://api.tianapi.com/txapi/lajifenlei/index?key=xxxxxxxxxxxxxxxxxxxxxxxxxx&word=";

然后复制MainActivity中的相应部分过来改一下,基本上把MainActivity改成SearchActivity就可以了,然后加个结束页面,代码如下:

    private void init_search(){
        View view = getWindow().peekDecorView();
        if (view != null) {//这里是网络访问的代码,获取服务
            InputMethodManager inputmanger = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            inputmanger.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
        initData_search();
    }

    Handler handler_search=new Handler(new Handler.Callback() {//首先通过handler发送信息
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            switch (msg.what){
                case 0:
                    Toast.makeText(SearchActivity.this,"网络错误",Toast.LENGTH_LONG).show();
                    break;
                case 1:
                    String json=(String)msg.obj;
                    try{
                        MainActivity.Search_JSON=new JSONObject(json);
                        Intent intent=new Intent();
                        intent.setClass(SearchActivity.this, SearchActivity.class);
                        startActivity(intent);
                        finish();               //结束掉现在的页面,直接返回主页。(假装可以刷新)
                        break;
                    }catch (JSONException e){
                        e.printStackTrace();
                    }
                default:
                    throw new IllegalStateException("Unexpected value: " + msg.what);
            }
            return false;
        }
    });

    private void initData_search(){                 //接着用这个方法调用handler,并把返回的信息放入TextView
//        handler_beauty.sendEmptyMessage(1);
        String data=text_search_garbage.getText().toString();
        if(TextUtils.isEmpty(data)){//如果内容为空,弹出toast消息,不为空则执行164行以后的代码
            Toast.makeText(SearchActivity.this,"垃圾名称不能为空!",Toast.LENGTH_SHORT).show();
        }
        else{
            Okhttp_work.OkHttpGet(url_garbage+data, 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_search.sendMessageDelayed(message,10);
                }
            });
        }
    }

最后在onCreate中加入定义和监听器就完成了:

        text_search_garbage=findViewById(R.id.search_edit_text);
        btn_search_garbage=findViewById(R.id.button_search);

        try {
            init_garbage_list();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        Garbage_adapter adapter=new Garbage_adapter(SearchActivity.this, R.layout.garbage_list, garbageList);
        ListView listView=(ListView)findViewById(R.id.search_listview);
        listView.setAdapter(adapter);

        btn_search_garbage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                init_search();
            }
        });

测试一下是成功的,这里我就不截图了。

接下来是为ListView添加点击事件,让我们能够进入详情页面:
这一段书上又没有介绍了,所以又需要我们操起老本行了,
这里楼主要感谢百度知道 Android开发 关于ListView的点击事件 中的第一个答案,让楼主成功达成了点击事件。
我们依旧是先在SearchActivity中声明两个变量:

    private ListView garbageList_View;
    public int garbage_id;

然后写ListView的点击事件:

garbageList_View=findViewById(R.id.search_listview);
        garbageList_View.setOnItemClickListener(new AdapterView.OnItemClickListener(){
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                garbage_id=i;
                Intent intent=new Intent();
                intent.setClass(SearchActivity.this, DetailActivity.class);
                startActivity(intent);
            }
        });

这样我们在打开新页面的同时,也把点击的选项id放入了全局变量garbage_id中,这样下个页面就可以直接调用这个参数了。

OK!搜索结果页面完成!(有木有想大吼一声啊~)

2.进入详情页面

做到这里,楼主发现一个大问题,我们没有图片,所以这波进入详情之后会是很生硬的文字堆叠,很丑,如果这波有图片,那我们这将会是绝杀,可惜有不得。
有不得的话,那自然是上来一堆TextView,一堆setText,就完事了,虽说这样有点太简单了,不过没关系,我们后面再画个一两个小时专门美化一下就好了。
现在先来实现吧:
先新建一个normal_detail.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="60dp"
    android:background="@drawable/title_bg">

</RelativeLayout>

作为空白的导航栏,然后修改activity_detail.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context=".DetailActivity">

    <include
        android:id="@+id/include_detail_title"
        layout="@layout/normal_title"
        app:layout_constraintBottom_toTopOf="@+id/main_image" />

    <TextView
        android:id="@+id/detail_garbage_name"
        android:layout_width="266dp"
        android:layout_height="69dp"
        android:layout_below="@+id/include_detail_title"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_marginStart="0dp"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="3dp"
        android:text="暂时没有网络连接~" />

    <TextView
        android:id="@+id/detail_garbage_type"
        android:layout_width="146dp"
        android:layout_height="69dp"
        android:layout_below="@+id/include_detail_title"
        android:layout_marginStart="0dp"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="3dp"
        android:layout_toEndOf="@+id/detail_garbage_name"
        android:layout_toRightOf="@+id/detail_garbage_name"
        android:text="暂时没有网络连接~" />

    <TextView
        android:id="@+id/detail_garbage_explain"
        android:layout_width="match_parent"
        android:layout_height="135dp"
        android:layout_below="@+id/include_detail_title"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_marginStart="0dp"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="74dp"
        android:text="暂时没有网络连接~" />

    <TextView
        android:id="@+id/detail_garbage_contain"
        android:layout_width="match_parent"
        android:layout_height="122dp"
        android:layout_below="@+id/include_detail_title"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_marginStart="0dp"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="210dp"
        android:text="暂时没有网络连接~" />

    <TextView
        android:id="@+id/detail_garbage_tips"
        android:layout_width="match_parent"
        android:layout_height="78dp"
        android:layout_below="@+id/include_detail_title"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_marginTop="332dp"
        android:layout_marginEnd="0dp"
        android:layout_marginRight="0dp"
        android:text="暂时没有网络连接~" />

</RelativeLayout>

看着多,其实就是随便拖了五个TextView,字体什么的我们先不管,随便放一下,后面再改。最后修改DetailActivity代码如下:

public class DetailActivity extends AppCompatActivity {
    private TextView garbage_name;
    private TextView garbage_type;
    private TextView garbage_explain;
    private TextView garbage_contain;
    private TextView garbage_tips;
    private JSONObject search_result=MainActivity.Search_JSON;
    private int detail_garbage_id=SearchActivity.garbage_id;
    private String[] garbage_type_string={"可回收垃圾","有害垃圾","厨余垃圾","其它垃圾(干垃圾)"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);
        ActionBar actionbar=getSupportActionBar();
        if(actionbar!=null){
            actionbar.hide();
        }

        garbage_name=findViewById(R.id.detail_garbage_name);
        garbage_type=findViewById(R.id.detail_garbage_type);
        garbage_explain=findViewById(R.id.detail_garbage_explain);
        garbage_contain=findViewById(R.id.detail_garbage_contain);
        garbage_tips=findViewById(R.id.detail_garbage_tips);


        try {
            garbage_name.setText(make_the_String("name"));
        } catch (JSONException e) {
            e.printStackTrace();
        }
        try {
            garbage_type.setText(garbage_type_string[Integer.parseInt(make_the_String("type"))]);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        try {
            garbage_explain.setText(make_the_String("explain"));
        } catch (JSONException e) {
            e.printStackTrace();
        }
        try {
            garbage_contain.setText(make_the_String("contain"));
        } catch (JSONException e) {
            e.printStackTrace();
        }
        try {
            garbage_tips.setText(make_the_String("tip"));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }


    private String make_the_String(String need) throws JSONException {            //用于将JSON转换为字符串数组
        JSONArray newslist=search_result.getJSONArray("newslist");
//        String[] name=new String[newslist.length()];
        String newslistString=new String();
        JSONObject the_garbage_JSON=new JSONObject();       //具体某一项的json ,可以通过getstring获得其中具体的项
        newslistString=newslist.getString(detail_garbage_id);
        the_garbage_JSON=new JSONObject(newslistString);
//        name[i]=the_garbage_JSON.getString("name");
        return the_garbage_JSON.getString(need);
    }
}

相信对于一直看到这里的朋友们这个已经很简单了,我也就不细说了,其实就是用之前编写的方法工具复制过来用罢了。测试一下:

成功显示,没有bug。

接下来就到我们的三岔路口了,我们是该开始着手美化APP呢,还是继续研究添加数据库的功能呢?
楼主想了想,还是算了吧,头已经在发热了,急需一个水冷来降温了,就不做什么数据库了,从刚开始接触数据库一直到现在,楼主真的一听到数据库就头大,什么连接什么的,当时用python连接数据库差点没把我送走。
所以我的下一步就是轻松愉快的美化APP啦!(“我要补充”,删~;“EditActivity”,删。)

美化的步骤我就不放在这里啦,毕竟也没剩多少技术含量了。

大家如果有兴趣可以用我博客里的代码自己操作一番,源码都在博客里面附着,所以楼主就不单独给大家打包源码了,毕竟楼主也是为了自己完成作业嘛,哈哈^ _ ^。

完结

(ps:楼主以后也会不断更新更多有意思的小知识的,所以就点一下辣个大拇指和关注吧,它们会亮的哇!QωQ)

最后附上楼主美化完的截图(加了几个无伤大雅的简单页面):


另外主页的按钮点进去是相应的介绍,“了解更多”按钮是打开百度网页(/捂脸)。是不是感觉好多了QwQ

标签:完结篇,search,String,garbage,Andrid,private,Studio,new,id
来源: https://blog.csdn.net/qq_44178379/article/details/110589712