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

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

內容概括:

一、網路下載資料並顯示在ListView上

  • 使用非同步訪問網路
  • 解析獲取的Json資料
  • 載入資料到ListView上

二、不同item的引用

  • 引用不同行佈局

一、網路下載資料並顯示在ListView上

1.1-使用非同步訪問網路

 //非同步訪問網路
    public class RquestDataAsyncTask extends AsyncTask<Void, Void, String> {
        //請求開始之前
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            //loading
        }

        @Override
        protected String doInBackground(Void... voids) {//子執行緒耗時操作
          
            }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            //loading 消失,資料處理,重新整理介面
        }

    }

在AndroidManifest.xml中新增訪問網路許可權:

<uses-permission android:name="android.permission.INTERNET"/>

在doInbackground中進行網路訪問


        @Override
        protected String doInBackground(Void... voids) {//子執行緒耗時操作
           return request("http://www.imooc.com/api/teacher?type=2&page=1");//呼叫request
            }

            //返回獲取到的String內容
        private String request(String urlString) {
            try {
                URL url = new URL(urlString);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(300000);
                connection.setRequestMethod("GET");
                connection.connect();

                int responseCode = connection.getResponseCode();

                if (responseCode == HttpURLConnection.HTTP_OK) {//如果訪問成功
                    InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream());
                    //包裝類,它可以包裝字元輸入流,將字元流放入快取裡,先把字元讀到快取裡
                    // 到快取滿了或者你flush的時候,再讀入記憶體,就是為了提供讀的效率而設計的
                    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                    StringBuilder stringBuilder = new StringBuilder();
                    String line;
                    //每次讀一行,直到它為空,並把當前這一個的資料賦值給line
                    while ((line = bufferedReader.readLine()) != null) {
                        stringBuilder.append(line);
                    }
                    return stringBuilder.toString();//返回拼接的資料
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;//如果訪問失敗返回null
        }

1.2-解析獲取的Json資料

拿到資料後要將資料做成一個物件,展示出來(解析)

執行將上面拿到的資料進行轉化成物件:

1-建立一個封裝json資料的類LessonResult.java

/**
 * 這個類封裝整個json物件的屬性
 */
public class LessonResult {
    //跟json的格式一致
    private String mMessage;
    private int mStatus;
    private List<LessonInfo> mLessonInfoList=new ArrayList<>();//裝每個數組裡面的內容

    public String getmMessage() {
        return mMessage;
    }

    public void setmMessage(String mMessage) {
        this.mMessage = mMessage;
    }

    public int getmStatus() {
        return mStatus;
    }

    public void setmStatus(int mStatus) {
        this.mStatus = mStatus;
    }

    public List<LessonInfo> getmLessonInfoList() {
        return mLessonInfoList;
    }

    public void setmLessonInfoList(List<LessonInfo> mLessonInfoList) {
        this.mLessonInfoList = mLessonInfoList;
    }

}

這個 LessonInfo封裝的是data數組裡面的屬性


/**
 * 這個類封裝陣列data裡面每一個物件的屬性
 */
public class LessonInfo {
    String mName;
    String mDescription;
    //僅拿了2個屬性

    public String getmName() {
        return mName;
    }

    public void setmName(String mName) {
        this.mName = mName;
    }

    public String getmDescription() {
        return mDescription;
    }

    public void setmDescription(String mDescription) {
        this.mDescription = mDescription;
    }
}

3-在onPostExecute中進行UI更新,將拿到的資料進行資料轉換(封裝顯示)

  //將執行後返回的結果(就是拼接的資料)進行處理
        /**
         * 執行資料轉換功能
         * @param result
         */
        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            //loading 消失,資料處理,重新整理介面
            LessonResult lessonResult=new LessonResult();
            try {
                //得到的json資料的物件
                JSONObject jsonObject=new JSONObject(result);
                //為lessonResult裡面的Status賦值
                //status:1 表示是int型的;“ ”表示是字串型的;true or false表示是boolean型別的
                lessonResult.setmStatus(jsonObject.getInt("status"));
                //拿到json資料裡面的message
                lessonResult.setmMessage(jsonObject.getString("msg"));
                //用這個List裝數組裡面的資料
                List<LessonInfo> lessonInfos=new ArrayList<>();
                //拿到陣列data裡面的資料
                JSONArray dataArray=jsonObject.getJSONArray("data");
                for(int index=0;index<dataArray.length();index++){
                    //給lessonInfo賦值
                    LessonInfo  lessonInfo=new LessonInfo();
                    //陣列data裡面又有10個物件{},所以要先把每一個物件拿出來
                    JSONObject tempJsonObject= (JSONObject) dataArray.get(index);
                    //給lessonInfo裡的name賦值
                    lessonInfo.setmName( tempJsonObject.getString("name"));
                    lessonInfos.add(lessonInfo);
                }
                //迴圈結束lessonResult賦值
                lessonResult.setmLessonInfoList(lessonInfos);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

1-3載入資料到ListView上

新建一個Adapter類繼承baseAdapter

public class RequestDataAdapter extends BaseAdapter {
    private List<LessonInfo> mLessonInfos;//定義一個全域性變數,在構造器中獲取初始值
    Context mcontext;

    //帶參構造,將List<LessonInfo>資料傳進來,只要顯示資料的資料
    public RequestDataAdapter(Context context, List<LessonInfo> infos) {

        this.mLessonInfos = infos;
        this.mcontext = context;
    }

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

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

    @Override
    public long getItemId(int position) {
        //可以獲取它的資料裡面的屬性返回
        // return mLessonInfos.get(position).getmName();
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder = new ViewHolder();
        //需要Context才有getSystem的方法
        //實現快取優化
        if (convertView == null) {
            LayoutInflater layoutInflater = (LayoutInflater) mcontext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.item_app_list, null);
            viewHolder.appNameTextView = convertView.findViewById(R.id.app_name_text_view);
            viewHolder.appIconImageView = convertView.findViewById(R.id.app_icom_image_view);
            convertView.setTag(viewHolder);

        } else {
            viewHolder = (ViewHolder) convertView.getTag();
            //將這個資料裡面的Name顯示到ListViewItem上每一個TextView
        }
        viewHolder.appNameTextView.setText(mLessonInfos.get(position).getmName());
        viewHolder.appIconImageView.setVisibility(View.GONE);//讓這個元件消失
        return convertView;
    }

    public class ViewHolder {
        public TextView appNameTextView;
        public ImageView appIconImageView;

    }
}

在onPostExecute方法後,繫結介面卡

            //listView繫結介面卡(資料)
            listView.setAdapter(new RequestDataAdapter(RequestDataActivity.this,lessonResult.getmLessonInfoList()));

在初始化時執行AsyncTask

        //執行AsyncTask
        new RquestDataAsyncTask().execute();

完成。

            convertView=LayoutInflater.from(mcontext).inflate(R.layout.item_app_list,null);

上面這一行,可以替換下面這種寫法: 

LayoutInflater layoutInflater = (LayoutInflater) mcontext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
          convertView = layoutInflater.inflate(R.layout.item_app_list, null);

 

二、不同item的引用

/**
 * 做一個模仿聊天介面的ListView
 * 首先,建立檢視
 * 然後,設定資料
 * 最後,繫結介面卡顯示
 */

主介面ChatActivity.java

public class ChatActivity extends AppCompatActivity {

    private ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);
        //1建立檢視 和兩個item佈局
        listView = findViewById(R.id.chat_list_view);
        //2設定資料
        //新建一個動態陣列裝資料
        ArrayList<Chat_Data> arrayList=new ArrayList<>();
        arrayList.add(new Chat_Data(
                1,2,
                "我","8:58",
                "在嗎",false));
        arrayList.add(new Chat_Data(
                1,2,
                "小米","8:59",
                "在",true));
        arrayList.add(new Chat_Data(
                1,2,
                "我","8:59",
                "天氣怎麼樣",false));
        arrayList.add(new Chat_Data(
                1,2,
                "小米","9:00",
                "熱成狗了",true));
        arrayList.add(new Chat_Data(
                1,2,
                "小米","9:00",
                "哇哇哇",true));
        //設定介面卡
        listView.setAdapter(new ChatAdapter(arrayList,ChatActivity.this));
    }

設定資料封裝:Chat_Data.java

public class Chat_Data {
    private  int mID;
    private  int mFriendID;
    private  String mName;
    private  String mDate;
    private  String mContent;
    boolean mIsComMessage;
    //構造方法賦值
    public Chat_Data(int mID, int mFriendID, String mName,String mDate, String mContent, boolean mIsComMessage) {
        this.mID = mID;
        this.mFriendID = mFriendID;
        this.mName = mName;
        this.mDate=mDate;
        this.mContent = mContent;
        this.mIsComMessage = mIsComMessage;
    }

    public String getmDate() {
        return mDate;
    }

    public void setmDate(String mDate) {
        this.mDate = mDate;
    }

    public int getmID() {
        return mID;
    }

    public void setmID(int mID) {
        this.mID = mID;
    }

    public int getmFriendID() {
        return mFriendID;
    }

    public void setmFriendID(int mFriendID) {
        this.mFriendID = mFriendID;
    }

    public String getmName() {
        return mName;
    }

    public void setmName(String mName) {
        this.mName = mName;
    }

    public String getmContent() {
        return mContent;
    }

    public void setmContent(String mContent) {
        this.mContent = mContent;
    }

    public boolean ismIsComMessage() {
        return mIsComMessage;
    }

    public void setmIsComMessage(boolean mIsComMessage) {
        this.mIsComMessage = mIsComMessage;
    }
}

 設定介面卡ChatAdapter.java

public class ChatAdapter extends BaseAdapter {
    ArrayList<Chat_Data> mChat_Data = new ArrayList<>();
    Context mContext;

    //定義一個介面實現判斷是哪個檢視
    interface MessageViewType {
        int COM_MESSAGE = 0;
        int TO_MESSAGE = 1;
    }

    public ChatAdapter(ArrayList<Chat_Data> mArrayList, Context mContext) {
        this.mChat_Data = mArrayList;
        this.mContext = mContext;
    }

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

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

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

    @Override
    public int getItemViewType(int position) {
        Chat_Data chat_data = mChat_Data.get(position);
        //拿到訊息型別
        boolean MSG = chat_data.ismIsComMessage();
        //返回訊息型別
        return MSG ? MessageViewType.COM_MESSAGE : MessageViewType.TO_MESSAGE;
    }

    //有2種顯示型別的檢視
    @Override
    public int getViewTypeCount() {
        return 2;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Chat_Data chat_data = mChat_Data.get(position);
        boolean IsComMsg = chat_data.ismIsComMessage();
        ViewHolder viewHolder = new ViewHolder();
        if (convertView == null) {
            if (chat_data.ismIsComMessage()) {//如果是來的訊息
                convertView = LayoutInflater.from(mContext).inflate(R.layout.chat_left_item, null);
            } else {//
                convertView = LayoutInflater.from(mContext).inflate(R.layout.chat_right_item, null);
            }
            viewHolder.mIcon = convertView.findViewById(R.id.iv_user_head);
            viewHolder.mName = convertView.findViewById(R.id.tv_username);
            viewHolder.mContent = convertView.findViewById(R.id.tv_chat_content);
            viewHolder.mDate = convertView.findViewById(R.id.tv_send_time);
            viewHolder.mContent.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
            viewHolder.IsComMsg = IsComMsg;
            convertView.setTag(viewHolder);

        } else
            viewHolder = (ViewHolder) convertView.getTag();
        viewHolder.mName.setText(chat_data.getmDate());
        viewHolder.mDate.setText(chat_data.getmDate());
        viewHolder.mContent.setText(chat_data.getmContent());
        if (IsComMsg) {
            viewHolder.mIcon.setImageResource(R.mipmap.ic_launcher);
        } else {
            viewHolder.mIcon.setImageResource(R.mipmap.ic_launcher_round);
        }
        return convertView;
    }

    public class ViewHolder {
        public TextView mContent, mName, mDate;
        public ImageView mIcon;
        public boolean IsComMsg;
    }
}

佈局左:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="6dp">

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

        <TextView
            android:id="@+id/tv_send_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="2dp"
            android:text="18:20"
            android:textColor="#CCCCCC" />
    </LinearLayout>

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="5dp">

        <ImageView
            android:id="@+id/iv_user_head"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:background="@mipmap/ic_launcher"
            android:clickable="true" />

        <TextView
            android:id="@+id/tv_chat_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:layout_toRightOf="@id/iv_user_head"
            android:background="#ffff"
            android:gravity="left|center"
            android:lineSpacingExtra="2dp"
            android:minHeight="36dp"
            android:minWidth="50dp"
            android:text="@string/app_name"
            android:textColor="#494949"
            android:textSize="18sp" />

        <TextView
            android:id="@+id/tv_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:layout_toRightOf="@id/tv_chat_content"
            android:clickable="true"
            android:focusable="true"
            android:gravity="left|center"
            android:lineSpacingExtra="2dp"
            android:minHeight="50dp"
            android:textColor="#ff000000"
            android:textSize="15sp" />

        <TextView
            android:id="@+id/tv_username"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_below="@id/iv_user_head"
            android:layout_toLeftOf="@id/tv_chat_content"
            android:gravity="center"
            android:singleLine="true"
            android:text=""
            android:textColor="#818181"
            android:textSize="14sp"
            android:visibility="visible" />
    </RelativeLayout>

佈局右:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="6dp" >

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

        <TextView
            android:id="@+id/tv_send_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="2dp"
            android:textColor="#ffffff"
            android:textSize="12sp"
            android:background="#bfbfbf"/>

    </LinearLayout>

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_marginRight="5dp" >


        <ImageView
            android:id="@+id/iv_user_head"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:focusable="false"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:background="@mipmap/ic_launcher"/>

        <TextView
            android:id="@+id/tv_chat_content"
            android:layout_toLeftOf="@id/iv_user_head"
            android:layout_marginRight="10dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:minWidth="50dp"
            android:textColor="#000"
            android:background="#fff"
            android:textSize="15sp"
            android:gravity="left|center"
            android:minHeight="40dp"
            android:lineSpacingExtra="2dp"
            android:clickable="true"
            android:focusable="true"/>

        <TextView
            android:id="@+id/tv_time"
            android:layout_toLeftOf="@id/tv_chat_content"
            android:layout_marginRight="10dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15sp"
            android:textColor="#ff000000"
            android:gravity="left|center"
            android:minHeight="50dp"
            android:lineSpacingExtra="2dp"
            android:clickable="true"
            android:focusable="true"/>


        <TextView
            android:id="@+id/tv_username"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/iv_user_head"
            android:layout_alignParentRight="true"
            android:layout_toRightOf="@id/tv_chat_content"
            android:textSize="15sp"
            android:gravity="center"
            android:textColor="#818181"/>

    </RelativeLayout>

</LinearLayout>