Android开发实例-健康食谱应用(二)

转载请注明出处:http://blog.csdn.net/einarzhang/article/details/44806975

本系列文章主要介绍如何利用Android开发一个简单的健康食谱软件。用到的相关技术如下所示:

  • 提供GridView和ListView的基本使用
  • 利用universal-image-loader异步加载网络图片
  • 通过HttpClient获取网络http请求数据
  • 滑动分页加载数据

软件所用的所有数据均来源于http://doc.yi18.net/cookwendang提供的食谱接口,感谢他们!

软件文件结构如下所示:

MainActivity:主界面Acitivity

MListActivity:子分类列表Acitivity

CListActivity:食谱列表Activity

DetailActivity:食谱详情Activity

MainGridAdapter:主界面食谱分类适配器

CListAdapter:食谱列表适配器

Cook:用于保存食谱信息的pojo

HttpUtils:提供Http请求相关功能

MUtils:提供食谱相关的处理逻辑功能

搜索食谱

我们在主界面提供了搜索食谱功能,当用户输入食谱名称时,软件将给用户展现出想要的食谱列表。搜索食谱我们主要用到http://api.yi18.net/cook/search接口。

我们在MUtils方法增加搜索食谱方法:

public static ArrayList<Cook> search(final String keyword, final int page) {
		String url = "http://api.yi18.net/cook/search";
		String result = HttpUtils.httpGet(url, new HashMap<String, Object>(){{
			put("keyword", URLEncoder.encode(keyword));
			put("page", page);
			put("limit", 20);
		}});
		ArrayList<Cook> dataMap = new  ArrayList<Cook>();
		if(result != null) {
			try {
				JSONObject root = new JSONObject(result);
				if(root.getBoolean("success")) {
					JSONArray datas = root.getJSONArray("yi18");
					for(int i = 0, len = datas.length(); i < len; i++) {
						JSONObject obj = datas.getJSONObject(i);
						Cook c = new Cook();
						c.id = obj.optInt("id");
						c.name = obj.optString("name");
						if(c.name != null) {
							c.name = c.name.replace("<font color=\"red\">", "").replace("</font>", "");
						}
						c.food = obj.optString("description");
						c.img = obj.optString("img");
						c.tag = obj.optString("keywords");
						dataMap.add(c);
					}
				}
			} catch (Exception e) {
			}
		}
		return dataMap;
	}

该搜索方法提供了食谱名称和分页页码参数,便于前端实现分页刷新功能,因为返回的食谱名称中包含Html信息,我们将其过滤掉。搜索结果将进入食谱列表界面,界面展示出搜索的结果信息

获取分类食谱

当用户点击某一子分类时,将获取出分类下的食谱列表,主要用到http://api.yi18.net/cook/list接口

我们在MUtils中增加如下方法:

public static ArrayList<Cook> getCooks(final int classId, final int page, final int sortType) {
		String url = "http://api.yi18.net/cook/list";
		String result = HttpUtils.httpGet(url, new HashMap<String, Object>(){{
			put("id", classId);
			put("page", page);
			put("limit", 20);
			put("type", sortType == SORT2 ? "count" : "id");
		}});
		ArrayList<Cook> dataMap = new  ArrayList<Cook>();
		if(result != null) {
			try {
				JSONObject root = new JSONObject(result);
				if(root.getBoolean("success")) {
					JSONArray datas = root.getJSONArray("yi18");
					for(int i = 0, len = datas.length(); i < len; i++) {
						JSONObject obj = datas.getJSONObject(i);
						Cook c = new Cook();
						c.id = obj.optInt("id");
						c.name = obj.optString("name");
						c.count = obj.optInt("count");
						c.fcount = obj.optInt("fcount");
						c.rcount = obj.optInt("rcount");
						c.food = obj.optString("food");
						c.img = obj.optString("img");
						c.tag = obj.optString("tag");
						dataMap.add(c);
					}
				}
			} catch (Exception e) {
			}
		}
		return dataMap;
	}

同搜索食谱功能一致,这里提供page对象,便于提供分页加载

食谱列表界面

食谱列表界面用于展示匹配相应结果的食谱列表,为了用户更好的了解食谱,在列表中我们提供缩略图展示。当用户搜索食谱或者点击某一分类时,将进入食谱列表界面。

食谱列表界面最终效果图如下所示:

每个列表展示出食谱的缩略图、食谱名称和食谱涉及的材料。列表布局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="match_parent"
    android:background="@drawable/list_item_bg"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@drawable/title_bg" >

        <ImageView
            android:id="@+id/clist_return"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="20dp"
            android:src="@drawable/arrowl" />

        <TextView
            android:id="@+id/clist_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textColor="@android:color/white"
            android:textSize="18sp"
            android:textStyle="bold" />
    </RelativeLayout>

    <ListView
        android:id="@+id/clist"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="none" >
    </ListView>

</LinearLayout>

每个Item的布局clist_item.xml如下所示:

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

    <ImageView
        android:id="@+id/clist_item_icon"
        android:layout_width="100dp"
        android:layout_height="60dp"
        android:layout_margin="10dp"
        android:scaleType="fitCenter"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
         />

    <LinearLayout
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/clist_item_icon"
        android:layout_toLeftOf="@+id/clist_item_arrow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/clist_item_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@android:color/white"
            android:textSize="18sp" />
        <TextView
            android:id="@+id/clist_item_detail"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:lines="1"
            android:ellipsize="end"
            android:textColor="@color/clist_item_tag"
            android:textSize="14sp" />
    </LinearLayout>

    <ImageView
        android:id="@+id/clist_item_arrow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="20dp"
        android:layout_marginLeft="10dp"
        android:src="@drawable/arrowr" />

</RelativeLayout>

我们利用clist_item.xml渲染自定义的ListAdapter,取名CListApdater,其代码如下所示:

import java.util.List;

import android.content.Intent;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;

public class CListAdapter extends BaseAdapter {

	private CListActivity activity;

	private List<Cook> dataList;

	public CListAdapter(CListActivity activity, List<Cook> dataList) {
		this.activity = activity;
		this.dataList = dataList;
		//初始化Android-Universal-Image-Loader框架
		ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(activity));
	}

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

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

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

	@Override
	public View getView(final int position, View convertView, ViewGroup parent) {
		convertView = LayoutInflater.from(activity).inflate(R.layout.clist_item, null);
		final Cook c = dataList.get(position);
		((TextView)convertView.findViewById(R.id.clist_item_title)).setText(c.name);
		((TextView)convertView.findViewById(R.id.clist_item_detail)).setText(c.tag);
		//设置图片显示格式(我们可以设置圆角、缓存等一些列配置)
		DisplayImageOptions options = new DisplayImageOptions.Builder()
	        .showImageOnLoading(R.drawable.loading)  	//加载中显示的正在加载中的图片
	        .showImageOnFail(R.drawable.loading)  		//为了方便,加载失败也显示加载中的图片
	        .cacheInMemory(true)  					//在内存中缓存图片
	        .cacheOnDisk(true)
	        .bitmapConfig(Bitmap.Config.RGB_565)
	        .imageScaleType(ImageScaleType.EXACTLY)		//设置图片以如何的编码方式显示
	        .build();
		//异步加载图片,并渲染到指定的控件上
		ImageLoader.getInstance().displayImage(MUtils.PREFIX_IMG + c.img, (ImageView)convertView.findViewById(R.id.clist_item_icon), options);
		//Item点击后进入食谱详情界面
		convertView.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent intent = new Intent(activity, DetailActivity.class);
				intent.putExtra("id", c.id);
				intent.putExtra("title", c.name);
				activity.startActivity(intent);
			}
		});
		return convertView;
	}

	//为Adapter增加新的食谱数据,当分页加载时,用于更新分页信息
	public void add(List<Cook> newData) {
		dataList.addAll(newData);
	}
}

CListAcitivity同时实现了搜索和分类进入的展示功能,并加入下拉分页加载,其代码如下所示:

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;

public class CListActivity extends Activity implements OnClickListener, OnItemClickListener, Runnable {

	int lastVisibleIndex = 0;	//滚动的最后可见条目
	int page = 1;	//当前分页页码
	int cId;		//分类ID
	String keyword;	//搜索关键词
	CListAdapter mAdapter;
	List<Cook> cList;
	ListView mlistView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.clist);
		findViewById(R.id.clist_return).setOnClickListener(this);
		mlistView = (ListView) findViewById(R.id.clist);
		mlistView.setOnItemClickListener(this);
		mlistView.setOnScrollListener(scrollListener);
		cId = getIntent().getIntExtra("id", 0);
		if(cId == 0) {
			//食谱搜索
			keyword = getIntent().getStringExtra("keyword");
			((TextView)findViewById(R.id.clist_title)).setText(keyword);
		} else {
			//分类进入
			((TextView)findViewById(R.id.clist_title)).setText(getIntent().getStringExtra("title"));
		}
		cList = new ArrayList<Cook>();
		new Thread(this).start();
	}

	@Override
	public void onItemClick(AdapterView<?> av, View arg1, int arg2, long arg3) {

	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.clist_return:
			CListActivity.this.finish();
			break;

		default:
			break;
		}
	}

	@Override
	public void run() {
		loadData();
		handler.sendEmptyMessage(0);
	}

	public void loadData() {
		List<Cook> results;
		if(cId == 0) {
			results = MUtils.search(keyword, page++);
		} else {
			results = MUtils.getCooks(cId, page++, MUtils.SORT1);
		}
		//获取成功,则更新数据列表
		cList.addAll(results);
	}

	Handler handler = new Handler(new Callback() {
		@Override
		public boolean handleMessage(Message msg) {
			//更新列表界面
			if(mAdapter == null) {
				mAdapter = new CListAdapter(CListActivity.this, cList);
				mlistView.setAdapter(mAdapter);
			} else {
				mAdapter.notifyDataSetChanged();
			}
			return false;
		}
	});

	OnScrollListener scrollListener = new OnScrollListener() {

		@Override
		public void onScrollStateChanged(AbsListView view, int scrollState) {
			int itemsLastIndex = mAdapter.getCount() - 1; // 数据集最后一项的索引
			if ((scrollState == SCROLL_STATE_TOUCH_SCROLL || scrollState == SCROLL_STATE_IDLE)
					&& lastVisibleIndex == itemsLastIndex) {
				//当滚动最后一项时,加载新的一页数据
				new Thread(CListActivity.this).start();
			}
		}

		@Override
		public void onScroll(AbsListView view, int firstVisibleItem,
				int visibleItemCount, int totalItemCount) {
			//滚动过程中更新最后可见索引
			lastVisibleIndex = firstVisibleItem + visibleItemCount - 1;
		}
	};
}

从代码中可以看到,我们通过为ListView定制OnScrollListener来实现滚动的分页加载逻辑

食谱详情

食谱详情用户展示食谱的详细信息,用户可以在详情里面看到食物的具体制作方法。

最终效果图如下所示:

我们首先在MUtils加上获取详情的功能:

public static Cook show(final int id) {
		String url = "http://api.yi18.net/cook/show";
		String result = HttpUtils.httpGet(url, new HashMap<String, Object>(){{
			put("id", id);
		}});
		if(result != null) {
			try {
				JSONObject root = new JSONObject(result);
				if(root.getBoolean("success")) {
					JSONObject obj = root.getJSONObject("yi18");
					Cook c = new Cook();
					c.id = obj.optInt("id");
					c.name = obj.optString("name");
					c.count = obj.optInt("count");
					c.fcount = obj.optInt("fcount");
					c.rcount = obj.optInt("rcount");
					c.food = obj.optString("food");
					c.img = obj.optString("img");
					c.tag = obj.optString("tag");
					c.message = obj.optString("message");
					return c;
				}
			} catch (Exception e) {
			}
		}
		return null;
	}
	

详情的布局xml如下所示:

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

    <RelativeLayout
        android:id="@+id/detail_layout"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentTop="true"
        android:background="@drawable/title_bg" >

        <ImageView
            android:id="@+id/detail_return"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="20dp"
            android:src="@drawable/arrowl" />

        <TextView
            android:id="@+id/detail_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textColor="@android:color/white"
            android:textSize="18sp"
            android:textStyle="bold" />
    </RelativeLayout>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/detail_layout"
        android:scrollbars="none" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:orientation="vertical" >

            <ImageView
                android:id="@+id/detail_img"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="10dp" >
            </ImageView>

            <TextView
                android:id="@+id/detail_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:textColor="@color/clist_item_tag"
                android:textSize="20sp" />

            <TextView
                android:id="@+id/detail_food"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:textSize="14sp" />

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:background="@drawable/lines" />

            <TextView
                android:id="@+id/detail_text"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginBottom="10dp"
                android:padding="20dp"
                android:textSize="16sp" />
        </LinearLayout>
    </ScrollView>
</RelativeLayout>

DetailActivity的完整实现代码如下所示:

import com.nostra13.universalimageloader.core.ImageLoader;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.TextView;

public class DetailActivity extends Activity implements OnClickListener, Runnable {

	private TextView titleView, contentView, foodView, nameView;
	private ImageView imgView;
	private int id;
	private Cook cook;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.detail);
		titleView = (TextView) findViewById(R.id.detail_title);
		contentView = (TextView) findViewById(R.id.detail_text);
		foodView = (TextView) findViewById(R.id.detail_food);
		nameView = (TextView) findViewById(R.id.detail_name);
		imgView = (ImageView) findViewById(R.id.detail_img);
		findViewById(R.id.detail_return).setOnClickListener(this);
		initData();
	}

	private void initData() {
		titleView.setText(getIntent().getStringExtra("title"));
		id = getIntent().getIntExtra("id", 1);
		new Thread(this).start();
	}

	@Override
	public void run() {
		cook = MUtils.show(id);
		handler.sendEmptyMessage(0);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.detail_return:
			DetailActivity.this.finish();
			break;

		default:
			break;
		}
	}

	Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			//异步显示图片
			ImageLoader.getInstance().displayImage(MUtils.PREFIX_IMG + cook.img, imgView);
			nameView.setText(cook.name);
			foodView.setText(cook.food);
			//内容以Html的方式展示
			contentView.setText(Html.fromHtml(cook.message));
		}
	};
}

至此,完整的健康食谱软件开发完成

时间: 2024-10-19 13:18:33

Android开发实例-健康食谱应用(二)的相关文章

Android开发实例-健康食谱应用(一)

转载请注明出处:http://blog.csdn.net/einarzhang/article/details/44774635 本系列文章的重点是如何使用Android开发一个简单的健康食谱软件.使用了以下相关技术中见例如: 提供GridView和ListView的基本使用 利用universal-image-loader异步载入网络图片 通过HttpClient获取网络http请求数据 滑动分页载入数据 软件所用的全部数据均来源于http://doc.yi18.net/cookwendang

android for vs (二)visual studio android 开发实例

android for vs (一)visual studio android 开发实例 相关 vs 的 android 开发环境安装配置可以看我的前一篇文章 这里使用 vs2010 自带的实例进行开发与调试 一.新建项目 文件 -> 新建 -> 项目,我们选择Blank App(Android)项目,如下图 二.项目目录结构 1)AndroidManifest.xml 项目配置描述文件,项目名.图标.运行程序需要的权限都可以在这里声明 2)Main.axml 界面布局及元素定义文件 3)Ma

Android开发实例之miniTwitter登录界面的实现

原文: http://www.jizhuomi.com/android/example/134.html 本文要演示的Android开发实例是如何完成一个Android中的miniTwitter登录界面,下面将分步骤讲解怎样实现图中的界面效果,让大家都能轻松的做出美观的登录界面. miniTwitter登录界面效果图 先贴上最终要完成的效果图: miniTwitter登录界面的布局分析 首先由界面图分析布局,基本可以分为三个部分,下面分别讲解每个部分. 第一部分是一个带渐变色背景的LinearL

Android开发实例之多点触控程序

智能终端设备的多点触控操作为我们带来了种种炫酷体验,这也使得很多Android开发者都对多点触控程序的开发感兴趣.实际上多点触控程序的实现并不是那么遥不可及,而是比较容易.本文就主要通过一个实例具体讲解多点触控程序的实现. 首先来了解一下Android中多点触控的原理. Android多点触控在本质上需要LCD驱动和程序本身设计上支持,目前市面上HTC.Motorola和Samsung等知名厂商只要使用电容屏触控原理的手机均可以支持多点触控Multitouch技术,对于网页缩放.手势操作上有更好

配置好的android开发环境 带实例---Android 开发实例教程一

一.版本说明 JDK:jdk1.7.0_15 ADT:v22.3.0-887826 已经配置好的开发环境(jdk1.7+adt22+api19+eclipse4.2.1)平台,打开即可用,同时workspace已经存在可以直接运行的实例(仿美团.淘宝格式). 真真的方便快捷. 二.下载地址 链接:http://pan.baidu.com/s/1bcy7O 密码:mo8a  好用别忘点赞,方便大家使用 三.配置说明 1.adt-bundle-windows-x86-20131030 解压到D盘根目

Android开发——进程间通信之AIDL(二)

0.  前言 不论是Android还是其他操作系统,都会有自己的IPC机制,所谓IPC(Inter-Process Communication)即进程间通信.首先线程和进程是很不同的概念,线程是CPU调用的最小单元,进程一般在PC和移动设备上指一个程序或者一个应用,一个进程可以包含多个线程. IPC方式有很多,在Android中常用的IPC方式包括Bundle.文件.Messenger.AIDL.ContentProvider和Socket等方式. Android开发--进程间通信之AIDL(一

Android开发中遇到的问题(二)——新建android工程的时候eclipse没有生成MainActivity和layout布局

一.新建android工程的时候eclipse没有生成MainActivity和layout布局 最近由于工作上的原因,开始学习Android开发,在入门的时候就遇到了不少的坑,遇到的第一个坑就是"新建android工程的时候eclipse没有自动生成MainActivity和layout布局”,项目的创建过程如下图所示: 展开HelloAndroid项目,可以看到创建好的项目的目录结构,如下图所示: 我的项目是采用的是官方集成了ADT的Eclipse(adt-bundle-windows-x8

Android开发实例透明效果设置方法

没什么android开发经验的朋友来说,实现透明效果是有一定难度的,我看见麦子学院android开发视频上面讲了三种方法来实现透明效果,这三种方法非常不错,嘿嘿,就抄下来分享给大家. 1.设置alpha View v = findViewById(R.id.content);/到你要设透明背景的layout 的id  v.getBackground().setAlpha(100);//0~255透明度值  2.用ARGB来控制 半透明<Button android:background="

Android开发实例总结

写一个修改密码的界面 1画界面总结: 需要弄清楚什么地方用相对布局,什么地方使用线性布局 希望这过后自己花时间去弄清楚他们内嵌的的所有组件以及组件的属性包括用法. 2逻辑总结: 逻辑描述总是那么几步的,我之前看老师给的例子我是慢慢看懂了一点,但是我总觉得差点什么东西.我欠一个彻底弄清楚,我肯定可以的. 3思想总结: 我认为我可以的.开发安卓,尽管我现在还是刚刚起步,我似乎和它有一种似曾相识的熟悉感.或许这个就是缘分.我不可以放弃Android开发."世界上最忠诚的就是自然界的物,只要你想他,他就