1. 程式人生 > >Android進階:網路與資料儲存—步驟1:Android網路與通訊(第3小節:ListView上)

Android進階:網路與資料儲存—步驟1:Android網路與通訊(第3小節:ListView上)

內容概要:

一、課程介紹

二、ListView的準備工作

  1. ListView簡介
  2. ListView的實現步驟

三、ListView簡單應用

  1. Adapter的資料繫結
  2. 最簡單ListView效果演示
  3. 獲取系統已安裝應用列表
  4. 優化效能

一、課程介紹

什麼是ListView?

  • 列表檢視

應用場景:

  1. 通訊錄,簡訊列表
  2. 聊天聯絡人,聊天介面,好友動態
  3. 設定介面,各種列表介面
  4. 資料夾列表,應用列表
  5. O2O美食外賣等商家列表,評論列表

二、ListView的準備工作

2-1.ListView簡介

1.adapter建立及原理

(介面卡)它主要用來將資料繫結到相應元件上

二、.ListView的實現步驟

  1. 在Layout中建立ListView
  2. 建每一個行的item的樣式
  3. 建立每一行的資料
  4. 用adapter將資料填充到每一行的檢視

三、ListView簡單應用

程式碼演示:

1、在Layout中建立ListView

<ListView
    android:id="@+id/app_list_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</ListView>

2、新建一個Layout建立每一個行的item的樣式

<?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">
<ImageView
    android:id="@+id/app_icom_image_view"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:src="@mipmap/ic_launcher"/>
    <TextView
        android:id="@+id/app_name_image_view"
        android:text="@string/app_name"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:textSize="20sp"
        android:gravity="center_vertical"
        android:paddingLeft="6dp"/>
</LinearLayout>

3、建立每一行的資料

  List<String> appNames = new ArrayList<>();
        appNames.add("QQ");
        appNames.add("微信");
        appNames.add("慕課網");

4、用adapter將資料填充到每一行的檢視

BaseAdapter基礎的Adapter
//把資料和檢視適配的一個類
    public class appListAdapter extends BaseAdapter {
        //這是我們要填充的資料
        List<String> mAppNames;

        //建構函式初始化資料,將資料傳進來
        public appListAdapter(List<String> appNames) {
            mAppNames = appNames;
        }

        @Override
        public int getCount() {
            //有多少條資料
            return mAppNames.size();
        }

        @Override
        public Object getItem(int position) {
            //返回當前position的資料
            return mAppNames.get(position);
        }

        @Override
        public long getItemId(int position) {
            //返回當前position的資料的id
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            //1.處理View --data適配的過程(填充資料)三個引數(id,item檢視,父元件)
            //LayoutInflater(佈局服務)是用來找res/layout/下的xml佈局檔案,並且例項化
            LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            //2.拿到item佈局
            convertView = layoutInflater.inflate(R.layout.item_app_list, null);
            //3.拿到item佈局的ImageView和TextView
            TextView appNameTextView = convertView.findViewById(R.id.app_name_text_view);
            ImageView appIconImageView = convertView.findViewById(R.id.app_icom_image_view);
            //4.繫結資料
            appNameTextView.setText(mAppNames.get(position));

            return convertView;//返回檢視
        }
    }

在初始化時setAdapter將ListView和資料item進行繫結

  //將ListView設定item的資料
        appListView.setAdapter(new appListAdapter(appNames));

效果演示: 

4、實現獲取系統已安裝應用列表

1、獲取系統應用的資訊的方法


    /**
     * 獲取所有的應用的資訊的方法
     * @return
     */
    private List<ResolveInfo> getAppInfos(){
        Intent intent=new Intent(Intent.ACTION_MAIN,null);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        return getPackageManager().queryIntentActivities(intent,0);
    }

2、介面卡

//把資料和檢視適配的一個類
    public class appListAdapter extends BaseAdapter {
        //這是我們要填充的資料
        List<ResolveInfo> mAppInfos;

        //建構函式初始化資料,將資料傳進來
        public appListAdapter(List<ResolveInfo> appNames) {
            mAppInfos = appNames;
        }
        ....這三個方法和上面一樣

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            //1.處理View --data適配的過程(填充資料)三個引數(id,item檢視,父元件)
            //LayoutInflater(佈局服務)是用來找res/layout/下的xml佈局檔案,並且例項化
            LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            //2.拿到item佈局
            convertView = layoutInflater.inflate(R.layout.item_app_list, null);
            //3.拿到item佈局的ImageView和TextView
            TextView appNameTextView = convertView.findViewById(R.id.app_name_text_view);
            ImageView appIconImageView = 
 convertView.findViewById(R.id.app_icom_image_view);
            //4.繫結系統應用的資料
            appNameTextView.setText(mAppInfos.get(position).activityInfo.loadLabel(getPackageManager()));
            appIconImageView.setImageDrawable(mAppInfos.get(position).activityInfo.loadIcon(getPackageManager()));
            return convertView;//返回檢視
        }
    }

3、為item新增點選效果

方法1:在getView方法中為

  1. 整個item新增監聽事件
  2. ImageView新增監聽事件將convertView修改成 appIconImageView即可(點選圖片才跳轉)
  3. TextView新增監聽(同上)
   //item佈局的點選事件
            convertView.setOnClickListener(new View.OnClickListener() {


                @Override
                public void onClick(View v) {
                    //拿出包名
                    String packageName=mAppInfos.get(position).activityInfo.packageName;
                    //應用本身的名字
                    String className=mAppInfos.get(position).activityInfo.name;
                    //用包名和應用的名稱構造一個元件
                    ComponentName componentName=new ComponentName(packageName,className);
                    final Intent intent = new Intent();
                    intent.setComponent(componentName);
                    startActivity(intent);
                }
            });

方法2:直接在初始化時新增監聽給ListView直接新增OnItemClickListener

    final List<ResolveInfo> appInfos = getAppInfos();
        appListView.setAdapter(new appListAdapter(appInfos));
        appListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //拿出包名
                String packageName=appInfos.get(position).activityInfo.packageName;
                //應用本身的名字
                String className=appInfos.get(position).activityInfo.name;
                //構造一個元件
                ComponentName componentName=new ComponentName(packageName,className);
                final Intent intent = new Intent();
                intent.setComponent(componentName);
                startActivity(intent);
            }
        });

4、給ListView頭部新增一個圖片,圖片隨著列表一起滑動

        //得到專們解析佈局的layoutInflater
        LayoutInflater layoutInflater= (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View headerView=layoutInflater.inflate(R.layout.header_list,null);
        //給ListView頭部新增一張隨之滑動的圖片(佈局)
        appListView.addHeaderView(headerView);

圖片固定不動:

直接在ListView所在的佈局新增一個圖片就可以了。

4、優化效能

getView就是當前每一條item,所以滑動的時候一直在執行執行很多次,多了就會卡頓,出來一個就執行一次

每一次都要執行getView的操作重新拿到佈局,重新找到控制元件id....很耗記憶體

  @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            //1.處理View --data適配的過程(填充資料)三個引數(id,item檢視,父元件)
            //LayoutInflater(佈局服務)是用來找res/layout/下的xml佈局檔案,並且例項化
            LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            //2.拿到item佈局
            convertView = layoutInflater.inflate(R.layout.item_app_list, null);
            //3.拿到item佈局的ImageView和TextView
            TextView appNameTextView = convertView.findViewById(R.id.app_name_text_view);
            ImageView appIconImageView = convertView.findViewById(R.id.app_icom_image_view);
            //4.繫結資料
......

解決方法:使用ViewHolder進行快取

首先,新建一個ViewHolder類

  //建立一個ViewHolder來快取,讓每次getView不用執行這麼多重複操作
        public class ViewHolder{
            public  TextView appNameTextView;
            public ImageView appIconImageView;
        }

在getView方法中

  ViewHolder viewHolder=new ViewHolder();
            if(convertView==null){//如果item為空
                //1.處理View --data適配的過程(填充資料)三個引數(id,item檢視,父元件)
                //LayoutInflater(佈局服務)是用來找res/layout/下的xml佈局檔案,並且例項化
                LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                //2.拿到item佈局
                convertView = layoutInflater.inflate(R.layout.item_app_list, null);
                //3.拿到item佈局的ImageView和TextView
                //將這兩個控制元件賦值給viewHolder,相當於它儲存了兩個檢視
                viewHolder.appNameTextView = convertView.findViewById(R.id.app_name_text_view);
                viewHolder.appIconImageView = convertView.findViewById(R.id.app_icom_image_view);
                convertView.setTag(viewHolder);//這個view檢視儲存起來給它個標籤

            }
            else{
                //如果不為空直接把上次存的viewHolder取出來:
                // 它裡面儲存的appNameTextView、和appIconImageView
                viewHolder=(ViewHolder) convertView.getTag();
            }
            //4.通過viewHolder繫結資料
            viewHolder.appNameTextView.setText(mAppInfos.get(position).activityInfo.loadLabel(getPackageManager()));
            viewHolder.appIconImageView.setImageDrawable(mAppInfos.get(position).activityInfo.loadIcon(getPackageManager()));

這樣它每次就省掉了上面幾步操作,直接出viewHolder快取拿就好。