ListView控件是Android中经常用到的,谈到ListView的利用,相比大家都很清楚了,那么大家是否对ListView的性能优化比较清楚呢,这也是很多面试中经常会问到的问题。另外本文也会说到如何获取手机中的所有应用程序的icon和name。
下面主要介绍代码
1. 获取当前设备所运行的应用程序的图标和名称[system]和[com.Android.phone]来过滤系统级别和电话级别的应用程序,并使用ListView进行显示,显示效果为:左边[应用程序图标]和右边[应用程序名称],该MainActivity主要继承ListView类
package com.untech.gridview;
import java.util.ArrayList;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ListActivity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import com.untech.gridview.adapter.ListAdapter;
import com.untech.gridview.entity.PackagesInfo;
import com.untech.gridview.entity.Program;
public class MainActivity extends ListActivity {
private final String TAG = MainActivity.class.getName();
private Context m_ctx;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
m_ctx = this;
List<Program> programs = getRunningProcess();
Log.d(TAG, "应用程序数量:" + programs.size());
ListAdapter listAdapter = new ListAdapter(m_ctx, programs);
getListView().setAdapter(listAdapter);
}
/**
* 获取正在运行的应用程序
*
* @return List<Program>
*/
private List<Program> getRunningProcess() {
List<Program> programs = new ArrayList<Program>();
// 检索所有的应用程序
PackagesInfo pi = new PackagesInfo(m_ctx);
PackageManager pm = m_ctx.getPackageManager();
ActivityManager am = (ActivityManager) m_ctx.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> rapis = am.getRunningAppProcesses();
if (null != rapis && !rapis.isEmpty()) {
for (RunningAppProcessInfo rapi : rapis) {
String processName = rapi.processName;
Log.d(TAG, "processName:" + processName);
if (!TextUtils.isEmpty(processName)) {
if (processName.equals("system") || processName.equals("com.Android.phone")) {
continue;
}
Program program = new Program();
if (null != pi) {
ApplicationInfo applicationInfo = pi.getInfo(processName);
if (null != applicationInfo) {
// 设置图标
program.setIcon(applicationInfo.loadIcon(pm));
// 设置程序名称
program.setName(applicationInfo.loadLabel(pm).toString());
programs.add(program);
}
}
}
}
}
return programs;
}
}
2. 其中ListView Adapter[主要用来加载并显示数据]代码如下:
/**
*
*/
package com.untech.gridview.adapter;
import java.util.List;
import com.untech.gridview.R;
import com.untech.gridview.entity.Program;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
/**
* @author apple
*
*/
public class ListAdapter extends BaseAdapter {
private Context m_ctx;
private List<Program> m_programs;
private LayoutInflater m_inflater;
public ListAdapter(Context ctx, List<Program> programs) {
this.m_ctx = ctx;
this.m_programs = programs;
if (null != m_ctx)
this.m_inflater = LayoutInflater.from(m_ctx);
}
@Override
public int getCount() {
return null != m_programs ? m_programs.size() : 0;
}
@Override
public Object getItem(int position) {
return null != m_programs ? m_programs.get(position) : null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
// 重用convertView,通过判断convertView是否为null,是的话需要产生一个视图,然后给这个视图数据并展现出来
if (null == convertView) {
convertView = m_inflater.inflate(R.layout.ut_view_listview, null);
if (null != convertView) {
// viewHodler和tag的使用,避免了重复使用findViewById去加载相应的控件
viewHolder = new ViewHolder();
viewHolder.m_iv = (ImageView) convertView.findViewById(R.id.ut_iv_listview);
viewHolder.m_tv = (TextView) convertView.findViewById(R.id.ut_tv_listview);
convertView.setTag(viewHolder);
}
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
setData(position, viewHolder.m_iv, viewHolder.m_tv);
return convertView;
}
private void setData(int position, ImageView iv, TextView tv) {
if (null != m_programs && !m_programs.isEmpty()) {
Program program = m_programs.get(position);
if (null != program) {
Drawable icon = program.getIcon();
iv.setImageDrawable(icon);
String name = program.getName();
tv.setText(name);
}
}
}
class ViewHolder {
public ImageView m_iv;
public TextView m_tv;
}
}
3. 布局文件ut_view_listview.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:orientation="horizontal" >
<!-- 应用程序图标 -->
<ImageView
android:id="@+id/ut_iv_listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp" />
<!-- 应用程序图标 end -->
<!-- 应用程序名称 -->
<TextView
android:id="@+id/ut_tv_listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp" />
<!-- 应用程序名称 end -->
</LinearLayout>
下面说一下ListView是如何优化的:
1. 重用getView方法中的convertView,通过判断convertView是否为null,是的话需要产生一个视图,然后给这个视 图数据并展现出来;
2. 使用viewHodler和tag,避免了重复使用findViewById去加载相应的控件,当第一次通过findViewById获取到控 件对象后,将viewHodler添加到convertView的tag中;第二次直接使用getTag获取viewHolder对象;
3. 如果有bitmap需要加载最好使用imageLoader框架或者使用Lurcache去缓存加载相应的bitmap,避免OOM(内存 溢出)的出现;
4. 当外部有数据发生更新时可以使用istAdapter.notifyDataSetChanged();或 者listAdapter.notifyDataSetInvalidated();去自动刷新数据。
Android中ListView中使用了Java中的设计模式[观察者模式],这个面试的时候,很多做过3~4年的Android开发人员都居然不知道。其中notifyDataSetChanged()和notifyDataSetInvalidated()的区别如下:
a. notifyDataSetChanged()该方法内部实现了在每个观察者上面调用onChanged事件。每当发现数据集有改变的情况,或者读取到数据的新状态时,就会调用此方法[主要是指数据源发生改变]
b. notifyDataSetInvalidated()该方法内部实现了在每个观察者上面调用onInvalidated事件。每当发现数据集监控有改变的情况,就会调用此方法[主要是指数据源出现失效]
QQ技术交流群:248566653