Android ListView 和 ***Adapter 从本地/网络获取歌曲列表
本文内容
- 环境
- 项目结构
- 测试数据
- 演示 1:SimpleAdapter
- 演示 2:BaseAdapter
- 演示 3:CustomLazyList
- 演示 4:CustomLazyCompleteList
本文主要给出演示的概要,只贴出核心代码,主要是自己下载调试一下,点击此处下载。
本文通过四个示例,循序渐进地演示,将歌曲列表加载到 ListView 控件,歌曲列表,包括缩略图、歌手名、歌曲名等信息,或存放在本地,或以 JSON 形式存放在网络。
下载最新 Demo v.3.0
环境
- Windows 2008 R2 64 位
- Eclipse ADT V22.6.2,Android 4.4.3
- 三星 GT-S6818,Android OS 4.1.2
项目结构
图 1 项目结构-Java 包
图 1 是该演示的相关 Java 包:
- com.example.listviewdemo.ui 包,是所有的 UI,包括主 UI 和其他四个,相当于 UI 层;
- com.example.listviewdemo.adapter 包,是所有的 adapter;
- com.example.listviewdemo.dao 包,相当于业务,用来获得控件需要显示的数据,相当于业务层;
- com.example.listviewdemo.data 包,是演示 1、2 中使用的测试数据;
- com.example.listviewdemo.utils 包,工具类都在这里,包括文件缓存、内存缓存、加载图片、网络请求和流工具。
图 2 项目结构-资源和页面
- res/drawable-hdpi 是项目所需的图片、图标资源;
- res/layout 是程序界面,其中 main.xml 是主程序界面;item.xml 是 ListView 中每行的页面,该页面是这几个演示通用的。
图 3 程序主
图 4 四个演示的结果
(第一个:SimpleAdapter 演示;
第二个:BaseAdapter 演示;
第三个:CustomLazyList 演示;
第四个:CustomCompleteLazyList 演示)
测试数据
演示 1、2,以及演示 3 的部分,使用的测试数据如下所示:
- package com.example.listviewdemo.data;
- import com.example.listviewdemo.R;
- public class TestData {
- public static String[] title = new String[] { "Someone Like You",
- "Space Bound", "Stranger In Moscow", "Love The Way You Lie",
- "Khwaja Mere Khwaja", "All My Days", "Life For Rent",
- "Love To See You Cry", "The Good, The Bad And The Ugly",
- "Show me the meaning", "Someone Like You", "Space Bound",
- "Stranger In Moscow", "Love The Way You Lie", "Khwaja Mere Khwaja",
- "All My Days", "Life For Rent", "Love To See You Cry",
- "The Good, The Bad And The Ugly", "Show me the meaning" };
- public static String[] artist = new String[] { "Adele", "Eminem",
- "Michael Jackson", "Rihanna", "A R Rehman", "Alexi Murdoch",
- "Dido", "Enrique Iglesias", "Ennio Morricone", "Backstreet Boys",
- "Adele", "Eminem", "Michael Jackson", "Rihanna", "A R Rehman",
- "Alexi Murdoch", "Dido", "Enrique Iglesias", "Ennio Morricone",
- "Backstreet Boys" };
- public static int[] thumb = new int[] { R.drawable.adele,
- R.drawable.eminem, R.drawable.mj, R.drawable.rihanna,
- R.drawable.arrehman, R.drawable.alexi_murdoch, R.drawable.dido,
- R.drawable.enrique, R.drawable.ennio, R.drawable.backstreet_boys,
- R.drawable.adele, R.drawable.eminem, R.drawable.mj,
- R.drawable.rihanna, R.drawable.arrehman, R.drawable.alexi_murdoch,
- R.drawable.dido, R.drawable.enrique, R.drawable.ennio,
- R.drawable.backstreet_boys };
- public static String[] thumb_url = {
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_adele.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_dido.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_ennio.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_mj.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_alexi_murdoch.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_eminem.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_enrique.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_rihanna.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_arrehman.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_backstreet_boys.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_adele.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_dido.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_ennio.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_mj.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_alexi_murdoch.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_eminem.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_enrique.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_rihanna.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_arrehman.png",
- "http://images.cnblogs.com/cnblogs_com/liuning8023/591411/o_backstreet_boys.png" };
- }
四个一维数组,每个数组 20 个数据,从上到下分别表示歌曲名、歌手名、本地缩略图,以及网络缩略图(是链接,位于本博客的相册中)。
另一个测试数据是 json 格式数组,点击此处下载,在演示 4 中使用。
演示 1:SimpleAdapter
该演示直接利用 android.widget.SimpleAdapter,把歌曲列表(包括缩略图、歌手名字、歌曲名称)添加到 ListView 控件。
假设 XML 文件上有一个 ID 为 myslist 的 ListView 列表控件,以及一个代表列表每行的 item.xml 页面文件(该页面是之后演示通用的),核心代码如下所示:
- package com.example.listviewdemo.ui;
- import java.util.List;
- import java.util.Map;
- import com.example.listviewdemo.R;
- import com.example.listviewdemo.biz.SimpleAdapterDao;
- import com.example.listviewdemo.data.TestData;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.AdapterView;
- import android.widget.AdapterView.OnItemClickListener;
- import android.widget.AdapterView.OnItemSelectedListener;
- import android.widget.ListView;
- import android.widget.SimpleAdapter;
- import android.widget.Toast;
- public class SimpleAdapterTest extends Activity {
- private SimpleAdapterDao sa;
- private List<Map<String, Object>> musicList;
- private ListView list;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_simpleadapter);
- initClass();
- initControl();
- initData();
- initListView();
- }
- private void initClass() {
- sa = new SimpleAdapterDao();
- }
- private void initControl() {
- list = (ListView) findViewById(R.id.mylist_a);
- }
- private void initData() {
- musicList = sa.getData();
- }
- private void initListView() {
- SimpleAdapter simpleAdapter = new SimpleAdapter(this, musicList,
- R.layout.item, new String[] { "artist", "title", "thumb" },
- new int[] { R.id.item_artist, R.id.item_title,
- R.id.item_imagethumb });
- list.setAdapter(simpleAdapter);
- list.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view,
- int position, long id) {
- Toast.makeText(getApplicationContext(),
- TestData.artist[position], Toast.LENGTH_SHORT).show();
- }
- });
- list.setOnItemSelectedListener(new OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view,
- int position, long id) {
- Toast.makeText(getApplicationContext(),
- TestData.artist[position], Toast.LENGTH_SHORT).show();
- }
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
- }
- }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
将测试数据的三个一维数组,转换成 List 泛型的集合,每个集合采用 Map 泛型键值对的形式;创建 SimpleAdapter 对象,并指定 XML 页面文件以及测试数据和其相对应的控件;最后设置 ListView 的适配器。
演示 2:BaseAdapter
该演示利用一个更底层、功能更强大的 android.widget.BaseAdapter 类,重写相应的方法,尤其是 public View getView(int position, View convertView, ViewGroup parent) 方法,把歌曲列表添加到 ListView 控件。
假设 XML 文件上有一个 ID 为 myblist 的 ListView 列表控件,以及一个代表列表每行的 item.xml 页面文件(该页面是之后演示通用的),核心代码如下所示:
- package com.example.listviewdemo.ui;
- import com.example.listviewdemo.R;
- import com.example.listviewdemo.adapter.NewBaseAdapter;
- import android.os.Bundle;
- import android.app.Activity;
- import android.widget.ListView;
- public class BaseAdapterTest extends Activity {
- private ListView list;
- private NewBaseAdapter adapter;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_baseadapter);
- initClass();
- initControl();
- initListView();
- }
- private void initClass() {
- adapter = new NewBaseAdapter(this);
- }
- private void initControl() {
- list = (ListView) findViewById(R.id.myList_b);
- }
- private void initListView() {
- list.setAdapter(adapter);
- }
- }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
- package com.example.listviewdemo.adapter;
- import android.app.Activity;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ImageView;
- import android.widget.LinearLayout;
- import android.widget.TextView;
- import com.example.listviewdemo.data.TestData;
- public class NewBaseAdapter extends BaseAdapter {
- private Activity activity;
- public NewBaseAdapter(Activity a) {
- activity = a;
- }
- @Override
- public int getCount() {
- return 20;
- }
- @Override
- public Object getItem(int position) {
- return null;
- }
- @Override
- public long getItemId(int position) {
- return position;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- LinearLayout line = new LinearLayout(activity);
- line.setOrientation(0);
- ImageView image = new ImageView(activity);
- image.setImageResource(TestData.thumb[position]);
- LinearLayout lineinner = new LinearLayout(activity);
- lineinner.setOrientation(1);
- TextView tvtitle = new TextView(activity);
- tvtitle.setText(TestData.title[position]);
- tvtitle.setTextSize(15);
- // tvtitle.setTextColor(Color.rgb(0, 240, 240));
- tvtitle.setPadding(10, 0, 0, 0);
- TextView tvartist = new TextView(activity);
- tvartist.setText(TestData.artist[position]);
- tvartist.setTextSize(10);
- tvartist.setPadding(10, 0, 0, 0);
- lineinner.addView(tvtitle);
- lineinner.addView(tvartist);
- line.addView(image);
- line.addView(lineinner);
- return line;
- }
- }
演示 1 和演示 2,加载歌曲列表(包括缩略图、歌手名字、歌曲名称)都在本地。下面两个演示,缩略图都是通过网络获取的,演示 3 的歌曲列表信息存放在本地,通过连接获得并缓存图片,显示在 ListView 控件,而演示 4 是通过网络获得歌曲列表的 JSON,这种方式更普遍,在客户端解析 org.json.JSONArray,获得图片并缓存,显示在 ListView 控件。
另外,歌曲列表的地址是 http://files.cnblogs.com/liuning8023/Android_Music_Demo_json_array.xml,虽然是 XML 文件,但内部是 JSON 格式,这对程序不会造成任何影响,cnblog 不让上传 .json 格式的文件。
总之,演示 1、2 与演示 3、4 相比,只是获得歌曲列表的途径不同,运行结果几乎一样。这四个演示是循序渐进的,也是本人的研究和思考的过程。下一步可以尝试实现“下拉获得最新”以及“上拉加载更多”的功能。
演示 3:CustomLazyList
与前两个演示相比,除了歌手名、歌曲名通过本地资源显示外,缩略图是通过网络访问并显示的。而且缩略图可以缓存在外存和内存中。
演示 4:CustomLazyCompleteList
与之前的演示相比,歌曲列表以 JSON 格式保存在网络,通过网络获得歌曲列表后,在本地解析成 org.json.JSONArray,利用缩略图链接通过网络获得缩略图,并缓存在外存和内存中。若缓存已存在,则从缓存获得并显示在 ListView 控件,否则从网络获取,缓存并显示。
若 Android 访问网络,一定要使用异步。
- package com.example.listviewdemo.ui;
- import org.json.JSONArray;
- import org.json.JSONException;
- import com.example.listviewdemo.R;
- import android.app.Activity;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.widget.ListView;
- import com.example.listviewdemo.adapter.CompleteLazyAdapter;
- import com.example.listviewdemo.biz.CustomCompleteLazyListDao;
- public class CustomCompleteLazyListTest extends Activity {
- private ListView list;
- private CompleteLazyAdapter adapter;
- private CustomCompleteLazyListDao customCompleteLazyListDao;
- /* Button btn; */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_customcompletelazylist);
- initClass();
- InitControl();
- new MyTask().execute(customCompleteLazyListDao);
- }
- private void initClass() {
- customCompleteLazyListDao = new CustomCompleteLazyListDao();
- }
- private void InitControl() {
- list = (ListView) findViewById(R.id.mylist_d);
- }
- public class MyTask extends
- AsyncTask<CustomCompleteLazyListDao, String, String> {
- private boolean mUseCache;
- public MyTask() {
- mUseCache = true;
- }
- public MyTask(boolean useCache) {
- mUseCache = useCache;
- }
- /* 执行前,相关页面处理 */
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- }
- /* 执行中 */
- @Override
- protected String doInBackground(CustomCompleteLazyListDao... params) {
- CustomCompleteLazyListDao dao = params[0];
- String result = dao.getData();
- return result;
- }
- @SuppressWarnings("unchecked")
- @Override
- protected void onPostExecute(String result) {
- // TODO Auto-generated method stub
- super.onPostExecute(result);
- if (!result.isEmpty()) {
- JSONArray jsonArray;
- try {
- jsonArray = new JSONArray(result);
- adapter = new CompleteLazyAdapter(
- CustomCompleteLazyListTest.this, jsonArray);
- list.setAdapter(adapter);
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
- }
- package com.example.listviewdemo.adapter;
- import org.json.JSONArray;
- import org.json.JSONException;
- import org.json.JSONObject;
- import com.example.listviewdemo.R;
- import com.example.listviewdemo.utils.ImageLoader;
- import android.app.Activity;
- import android.content.Context;
- import android.os.Handler;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ImageView;
- import android.widget.TextView;
- public class CompleteLazyAdapter extends BaseAdapter {
- private Activity activity;
- private JSONArray data;
- private static LayoutInflater inflater = null;
- public ImageLoader imageLoader;
- public CompleteLazyAdapter(Activity a, JSONArray jsonArr) {
- activity = a;
- data = jsonArr;
- inflater = (LayoutInflater) activity
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- imageLoader = new ImageLoader(activity.getApplicationContext());
- }
- public int getCount() {
- return data == null ? 0 : data.length();
- }
- public Object getItem(int position) {
- return position;
- }
- public long getItemId(int position) {
- return position;
- }
- public View getView(int position, View convertView, ViewGroup parent) {
- View vi = convertView;
- if (convertView == null)
- vi = inflater.inflate(R.layout.list_row, null);
- JSONObject song = null;
- ImageView image = (ImageView) vi.findViewById(R.id.imagethumb);
- TextView tvartist = (TextView) vi.findViewById(R.id.artist);
- TextView tvtitle = (TextView) vi.findViewById(R.id.title);
- TextView tvduration = (TextView) vi.findViewById(R.id.duration);
- try {
- song = data.getJSONObject(position);
- imageLoader.DisplayImage(song.getString("thumb_url"), image);
- tvartist.setText(song.getString("artist"));
- tvtitle.setText(song.getString("title"));
- tvduration.setText(song.getString("duration"));
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return vi;
- }
- }
另外,别忘了,在 AndriodManifest.xml 文件中添加允许 android 访问网络和外存的相关小节。
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
演示 3、4 都自定义了自己的 Adapter 类,它们都继承了 android.widget.BaseAdapter 。
更新历史
- 2014-12-24 【第一次】【修复 v.2.0 版本 bug】
- 2014-12-25 【第二次】【包结构调整,更像正式的项目】
下载 Demo v.2.0 (有 bug)
Android ListView 和 ***Adapter 从本地/网络获取歌曲列表的更多相关文章
- Android listview与adapter用法(BaseAdapter + getView)
Android listview与adapter用法http://www.cnblogs.com/zhengbeibei/archive/2013/05/14/3078805.html package ...
- Android代码优化----PullToRefresh+universal-image-loader实现从网络获取数据并刷新
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- Android listview与adapter用法
listview与adapter用法 博客分类: android 一个ListView通常有两个职责. (1)将数据填充到布局. (2)处理用户的选择点击等操作. 第一点很好理解,ListView ...
- 【转】Android listview与adapter用法
一个ListView通常有两个职责. (1)将数据填充到布局. (2)处理用户的选择点击等操作. 第一点很好理解,ListView就是实现这个功能的.第二点也不难做到,在后面的学习中读者会发现,这非常 ...
- [Android]ListView的Adapter.getView()方法中延迟加载图片的优化
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4139998.html 举个例子吧,以好友列表为例 ListVi ...
- Android ListView 自定义 Adapter
自定义Adapter类 public class ListViewAdapter extends BaseAdapter { private static final String TAG = Mai ...
- [Android] ListView关于adapter多种view设置
使用的关键点是在adapter覆盖两个方法 public int getItemViewType(int position) public int getViewTypeCount() 其它的可另go ...
- android listview用adapter.notifyDataSetChanged()无法刷新每项的图标
http://blog.csdn.net/caizhegnhao/article/details/41318575 今天在开发中遇到一个很奇怪的listview的问题. 这个问题情景是我的应用需要做一 ...
- Android -- ListView与Adapter
ListView在Android中有着很重要的作用.Android开发中ListView是比较常用的组件,它以列表的形式展示具体内容,并且能够根据数据的长度自适应显示. 背景 ...
随机推荐
- MyEclipse10安装Log4E插件
一. Log4E插件下载 下载地址:http://log4e.jayefem.de/content/view/3/2/ 二.安装Log4E插件 将下载下来的压缩包解压缩,如下图所示: 解压缩生成的[d ...
- 自定义一个可以被序列化的泛型Dictionary<TKey,TValue>集合
Dictionary是一个键值类型的集合.它有点像数组,但Dictionary的键可以是任何类型,内部使用Hash Table存储键和值.本篇自定义一个类型安全的泛型Dictionary<TKe ...
- Jquery 验证 validate
官网地址:http://bassistance.de/jquery-plugins/jquery-plugin-validation jQuery plugin: Validation 使用说明 转载 ...
- Quartz:不要重复造轮子,一款企业级任务调度框架。
背景 第一次遇到定时执行某些任务的需求时,很多朋友可能设计了一个小类库,这个类图提高了一个接口,然后由调度器调度所有注册的接口类型,我就是其中之一,随着接触的开源项目越来越多,我的某些开发习惯受到了影 ...
- mysql 比较函数和操作符
MYSQL之中的比较函数和操作符: 1.[NOT] BETWEEN ... AND ... Check whether a value is within a range of values 说明: ...
- Build Web Apps in Node and Express视频下载
上传到百度云了,点击这里下载>> 作者使用的是Mac系统,不过Windows也差不多,主要理解express一些基本配置和使用,讲的比较基础,希望对node.js.express有兴 ...
- 获取AppStore上架后的应用版本号
应用通过审核以后,由开发者设置应用上架,但何时能在appstore搜索到该应用,这个时间不等,有时候15分钟左右有时候2个多小时,以前就是隔一段时间打开网页然后刷新一下,或者搜索一下,查看版本号,操作 ...
- SVG.js 基础图形绘制整理(一)
一.矩形 //指定width和height 画矩形 //返回rect对象 var draw = SVG('svg1').size(300, 300); var rect = draw.rect(100 ...
- [转]如何在本地apache上架设多个站点
http://dongxin1390008.blog.163.com/blog/static/3179247820094279581256/ 通常情况下,我们有时候需要架设多个站点 比如 我的web站 ...
- 要恢复页面吗?Chrome未正确关闭
谷歌chrome浏览器每次打开提示"要恢复页面吗"怎么办? 谷歌chrome浏览器每次打开提示"要恢复页面吗"怎么办? 如下图所示: 每次打开启动谷歌chrom ...