Android ListView的使用优化以及获取手机所有应用程序

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值