Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 安卓開發前後台通信,從數據庫中取數據並在前台以表格形式顯示,以json格式傳輸

安卓開發前後台通信,從數據庫中取數據並在前台以表格形式顯示,以json格式傳輸

編輯:關於Android編程

最近做了一個Android開發小demo,主要功能是在手機的ActionBar中的搜索欄,根據用戶輸入的名字從後台(java+Tomcat)數據庫中取出該名字對應的一系列信息,然後通過json形式傳到前台,並用表格的形式顯示到前台。
跟大家分享一下,並且列出幾個比較坑的點。但是只是列出了java文件和layout中的xml文件,drawable以及bean類沒有列
涉及的知識點主要有:

利用HttpUrlConnection進行通信 數據庫相關操作 利用json傳輸數據 後台代碼的mvc模式 Android中用列表顯示數據(表格是自己畫的)

前台

前台主要涉及兩個Activity,一個是SearchActivity,一個是SearchResultActivity。

SearchActivity

SearchActivity,它的主要功能是在ActionBar中的搜索欄可以接收用戶輸入的數據,並且可以動態提示,點擊回車後,會將數據傳到SearchResultActivity。
話不多說,上代碼:

package com.wzy.search.aty;

import java.util.ArrayList;

import com.wzy.search.R;
import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.Activity;
import android.app.SearchManager;
import android.app.SearchableInfo;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Color;
import android.opengl.Visibility;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.SearchView.OnCloseListener;
import android.widget.SearchView.OnQueryTextListener;
import android.widget.TextView;

/**
 * 該Activity執行前台搜索功能,具備自動提示
 * @author wzy
 * @version V1.0
 */
@SuppressLint("DefaultLocale")
public class SearchActivity extends Activity {

    SearchView searchView = null;
    EditText searchText = null;        
    private ListView searchListView = null; 
    private ArrayAdapter searchAdapter = null;
    private String[] searchNames = null; 
    private ArrayList searchList = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search_person);

        ActionBar actionBar = getActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);  // 給左上角圖標左邊加上一個返回圖標
        }

        searchListView = (ListView) findViewById(R.id.searchListView);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {     

        // 自定義菜單,設置搜索欄
        getMenuInflater().inflate(R.menu.search_menu, menu);
        //獲取SearchView對象
        searchView = (SearchView) menu.findItem(R.id.search).getActionView();
        if (searchView == null) {
            Log.e("SearchView", "Fail to get Search");
            return true;
        }

        // 獲得searchview文本對象
        int search_text_id = searchView.getContext().getResources().getIdentifier("android:id/search_src_text", null, null);
        searchText = (EditText) searchView.findViewById(search_text_id);

        searchView.setOnSearchClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                searchListView.setVisibility(View.VISIBLE);
            }
        });

        searchView.setOnCloseListener(new OnCloseListener() {

            @Override
            public boolean onClose() {
                // TODO Auto-generated method stub
                searchListView.setVisibility(View.INVISIBLE);
                return false;
            }
        });     

        searchNames = new String[]{"abc","bcd","cde","def","efg","wxy","xyz"};
        searchAdapter = new ArrayAdapter(getApplicationContext(), android.R.layout.simple_expandable_list_item_1,searchNames);

        searchListView.setAdapter(searchAdapter);
        searchListView.setTextFilterEnabled(true);

        searchListView.setOnItemClickListener(new OnItemClickListener() {

            @Override 
            public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) {
                // TODO Auto-generated method stub
                searchText.setText(((TextView)arg1).getText().toString());
                searchText.setSelection(((TextView)arg1).getText().toString().length());
                Log.e("string", ((TextView)arg1).getText().toString());
            }

        });

        searchView.setOnQueryTextListener(new OnQueryTextListener() {

            @Override
            public boolean onQueryTextSubmit(String query) {
                // TODO Auto-generated method stub
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                // TODO Auto-generated method stub
                if (newText.length() != 0) {
                    setFilterText(newText);
                } else {
                    clearTextFilter();
                }
                return false;
            }
        });

        //設置搜索圖標。設置為false的時候icon固定於文字左邊,設置為true在文字右邊,隨文字動
        searchView.setIconified(true);

        //獲取SearchView文本對象

        searchText.setTextColor(Color.WHITE);
        //核心代碼
        //獲取搜索服務管理器
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        // searchable activity的component name,由此系統可通過intent進行喚起
        ComponentName componentName = new ComponentName(this, SearchResultActvity.class);
        // 通過搜索管理器,從searchable activity中獲取相關搜索信息,就是searchable的xml設置。如果返回null,表示該activity不存在,或者不是searchable
        SearchableInfo searchableInfo = searchManager.getSearchableInfo(componentName);
        if (searchableInfo == null) {
            Log.e("SearchableInfo", "Fail to get SearchableInfo");
        }
        // 將searchable activity的搜索信息與search view關聯
        searchView.setSearchableInfo(searchableInfo);
        return true;
    }

    @SuppressLint("DefaultLocale")
    public void setFilterText(String filterText) {
        ArrayList list = new ArrayList();
        String[] tempStr;
        for (int i = 0; i < searchNames.length; i++) {

            String searchNameIgnoreCase = searchNames[i].toLowerCase();
            String filterTextIgnoreCase = filterText.toLowerCase();
            if (searchNameIgnoreCase.contains(filterTextIgnoreCase)) {
                list.add(searchNames[i]);
            }
        }
        if (list.size() >= 0) {
            tempStr = new String[list.size()];
            int j = 0;
            for (String str : list) {
                tempStr[j++] = str;
            }
            searchAdapter = new ArrayAdapter(getApplicationContext(),
                    android.R.layout.simple_expandable_list_item_1, tempStr);
            searchListView.setAdapter(searchAdapter);
        }
    }

    public void clearTextFilter() {
        searchAdapter = new ArrayAdapter(getApplicationContext(),
                android.R.layout.simple_expandable_list_item_1, searchNames);
        searchListView.setAdapter(searchAdapter);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // TODO Auto-generated method stub
        switch (item.getItemId()) {
        case android.R.id.home:
            overridePendingTransition(R.anim.tran_return_in, R.anim.tran_return_out);
            finish();
            break;

        case R.id.search:

            break;

        default:
            break;
        }
        return super.onOptionsItemSelected(item);
    }

    long lastClickTime = 0;
    @Override
    public void onBackPressed() {
        overridePendingTransition(R.anim.tran_return_in, R.anim.tran_return_out);
        finish();
    }
}

search_person.xml如下:




    

SearchResultActivity

上面的代碼就把數據傳到SearchResultActivity了。下面看該類代碼:

package com.wzy.search.aty;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.wzy.search.R;
import com.wzy.search.bean.Person;
import com.wzy.search.util.HttpUtil;
import com.wzy.search.util.Material;
import com.wzy.search.util.SerializableMap;
import com.wzy.search.StringUtil;
import com.wzy.bean.PersonData;
import com.wzy.bean.StringBean;

import android.app.ActionBar;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.os.DropBoxManager.Entry;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

/**
 * 該類返回搜索的結果,並以表格的形式顯示
 * @author wzy
 *
 */
public class SearchResultActvity extends Activity{

    private List datas;
    private ListView listView = null;

    private List> personDatas = null;
    private SimpleAdapter simpleAdapter = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        setContentView(R.layout.result_names_new);

        ActionBar actionBar = getActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);// 給左上角圖標左邊加上一個返回圖標
        actionBar.setDisplayShowHomeEnabled(true);// 設置ActionBar程序圖標不可見

        listView = (ListView) findViewById(R.id.personList); // 獲取Listview的引用

        personDatas = new ArrayList>();

        doSearchQuery(getIntent());

        // 將獲取到的名稱包裝為SimpleAdapter
        simpleAdapter = new SimpleAdapter(SearchResultActvity.this, personDatas, R.layout.nameitems,
                new String[] { PersonData.NAME , PersonData.AGE, PersonData.ADDRESS },
                new int[] { R.id.tv_name, R.id.tv_age, R.id.tv_address });

        // 為ListView設置Adapter
        listView.setAdapter(simpleAdapter);
        // 為ListView的列表項的單擊事件綁定事件監聽器
        listView.setOnItemClickListener(new OnItemClickListener() {
            // 這裡可以自己寫點擊事件
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            finish();
            break;

        default:
            break;
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     *  activity重新置頂
     */
    @Override
    protected void onNewIntent(Intent intent) {
        // TODO Auto-generated method stub
        doSearchQuery(intent);
    }

    /**
     * 對searchable activity的調用仍是標准的intent,我們可以從intent中獲取信息,即要搜索的內容
     * @param intent
     */
    private void doSearchQuery(Intent intent){  
        if(intent == null) 
            return; 

        String queryAction = intent.getAction(); 
        if( Intent.ACTION_SEARCH.equals( intent.getAction())){  //如果是通過ACTION_SEARCH來調用,即如果通過搜索調用 
            String queryString = intent.getStringExtra(SearchManager.QUERY); //獲取搜索內容
            Log.e("yep", queryString);

            datas = null;           
            final Map params = new HashMap();
            params.put(StringBean.NAME, queryString);

            new Thread(new Runnable() {
                @Override
                public void run() {

                    String encode = "utf-8";
                    try {
                        datas = HttpUtil.sendHttpRequst(params, encode);
                        if (datas == null) {
                            Log.e("connect result", "返回結果異常");
                        }else {
                            for (PersonData data : datas) {
                                System.out.println(data.getAge() + " " + data.getName() + " " + data.getAddress());
                                Map newData = new HashMap();
                                newData.put(PersonData.NAME, data.getName());
                                newData.put(PersonData.AGE, data.getAge());
                                newData.put(PersonData.ADDRESS, data.getAddress());
                                personDatas.add(newData);
                            }

                            for (Map map : personDatas) {
                                for (Map.Entry entry : map.entrySet()) {
                                    System.out.println(entry.getKey() + " --> " + entry.getValue());
                                }
                            }

                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

            }).start();

        }  

    }  
}

result_names_new.xml如下所示:




    <framelayout android:id="@+id/id_fl" android:layout_height="20dip" android:layout_margintop="10dip" android:layout_width="match_parent">

        
    </framelayout>

    

        

        

        
    

    
    

nameitems如下所示:




    

    

    

從xml可以看出來,表格是自己畫的,先是畫出表頭,然後再用ListView,再將list化成和表頭一樣的框,就成了表格了。只不過需要調整一下間距,否則比較難看。
這裡還有幾個點:
一是調用HttpUtil方法時,必須使用線程,否則會報錯;
二是對於listview的操作,比如初始化和setAdapter,必須放在onCreate方法裡,否則會出現問題。

通信

本例使用HttpUrlConnection進行通信,在com.wzy.util包下新建HttpUtil類,主要用於發送前台傳到後台的參數,並且接受後台傳過來的數據,並且把數據包裝成PersonData的形式。

package com.wzy.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
i   mport java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.siemens.bean.MaterialData;

import android.util.Log;

/**
 * 該類用於與後台進行通信,通過json方式,將結果以PersonData形式進行封裝
 * @author wzy
 *
 */
public class HttpUtil {

    private final static String PATH = "http://127.0.0.1:8088/PersonServlet/QueryController";
    private static URL url;

    private static List datas = null;

    public HttpUtil() {

    }

    @SuppressWarnings("deprecation")
    public static List sendHttpRequst(Map params, String encode) throws Exception {

        datas = new ArrayList();

        // 對查詢的參數進行封裝
        StringBuffer buffer = new StringBuffer();
        if (params != null && !params.isEmpty()) {
            for (Map.Entry entry : params.entrySet()) {
                buffer.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue())).append("&");
            }
            buffer.deleteCharAt(buffer.length() - 1);
        }

        // 打印傳遞的參數
        Log.e("data", buffer.toString());

        try {
            url = new URL(PATH);
//          System.out.println("url:" + url.toString());
            if (url != null) {
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                Log.e("TEST", urlConnection+"");
                if (urlConnection == null) {
                    System.out.println("urlConnection: " + urlConnection);
                    return null;
                }
                urlConnection.setConnectTimeout(3000);
                urlConnection.setRequestMethod("POST"); // 設置請求方式
                urlConnection.setDoInput(true); // 表示從服務器獲取數據
                urlConnection.setDoOutput(true); // 表示向服務器發送數據
                byte[] data = buffer.toString().getBytes();

//              System.out.println("buffer:" + data.toString());

                // 設置請求體的是文本類型
                urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                urlConnection.setRequestProperty("Content-Length", String.valueOf(data.length));

                // 獲得輸出流
                OutputStream outputStream = urlConnection.getOutputStream();
                outputStream.write(data);
                outputStream.close();

                // 獲得服務器的響應結果和狀態碼
                int responseCode = urlConnection.getResponseCode();
                Log.e("RESCODE", responseCode + "");
                // 服務器響應成功
                if (responseCode == 200) {
                    // 獲取查詢結果
                    InputStream in = urlConnection.getInputStream();

                    // 結果為JSON格式,對JSON進行解析
                    datas = parseJSON(in);
                }
            }
            return datas;
        } catch (IOException e) {
            e.printStackTrace();
            Log.e("my error", "這裡肯定發生了錯誤");
        }
        return null;
    }

    private static List parseJSON(InputStream in) throws Exception {

        String str = read(in);

        Gson gson = new Gson();
        datas = gson.fromJson(str, new TypeToken>(){}.getType());
        return datas;
    }

    private static String read(InputStream in) throws IOException {
        byte[] data;
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = in.read(buf)) != -1) {
            bout.write(buf, 0, len);
        }
        data = bout.toByteArray();
        return new String(data, "utf-8");
    }

}

這裡就沒什麼好說的了,需要注意的是,這裡用Gson進行的數據解析,講json轉化為PeronData,傳給SearchResultActivity

後台

後台代碼結構

本例中,後台不需要view層,所以只需要以下包
-com.wzy.bean,封裝數據庫的表;
-com.wzy.service,對某個表進行操作;
-com.wzy.controller,控制某個service進行操作;
-com.wzy.util,有SqlHelper類,進行數據庫的增刪改查操作,涉及數據庫的都可以用這個類,也可以叫com.wzy.dao包;
本例中,用QueryController接受前台傳過來的數據,並用PersonService進行查詢操作,返回PersonData數據

QueryController

代碼如下:

package com.wzy.controller;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.Gson;
import com.wzy.bean.PersonData;
import com.wzy.bean.StringBean;
import com.wzy.service.PersonService;

/**
 * 該類用於控制查詢相關事務,不包括單表查詢。即需要查詢多個表,通過該controller,調用相關service進行處理
 * @author wzy
 *
 */
public class QueryController extends HttpServlet {
    private static final long serialVersionUID = 1L;

    private String materialName = "";

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doPost(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub

        request.setCharacterEncoding("utf-8");
        response.setContentType("text/json;charset=utf-8");
        response.setContentType("utf-8");

        OutputStream out = response.getOutputStream();

        ArrayList datas = null; //定義需要返回的數據

        if (request != null) {
            name = request.getParameter(StringBean.NAME);

            // 調用PersonService的方法,根據名字得到需要返回的ArrayList
            PersonService personService = new PersonService();
            datas = personService.getPersonByName(name);

            // 測試代碼,輸出查詢到的數據
            for (PersonData data : datas) {
                System.out.println(data);
            }

            // 通過gson返回數據
            Gson gson = new Gson();
            out.write(gson.toJson(datas).getBytes("utf-8"));

            out.flush();
            out.close();
        }

    }

}

需要注意的是,要用json的話,需要導包,這個可以百度一下,有一個主要包,還有幾個支持包,都要導

MaterialService類

package com.wzy.service;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

import com.google.gson.Gson;
import com.wzy.bean.PersonData;
import com.wzy.bean.Person_name;
import com.wzy.utils.DBString;
import com.wzy.utils.SqlHelper;

/**
 * 對涉及多表的業務進行操作
 * @author wzy
 *
 */
public class PersonService {

    private String sql = "";
    private String[] params = null;
    private PersonData data = null;
    private ArrayList datas = null;

    /**
     * 根據name查找,並返回封裝name,age,address的數據結構
     * @param name
     * @return 封裝name,age,address的對象的ArrayList
     */
    public ArrayList getPersonByName (String name) {


        params = new String[]{"%" + name + "%"};

        sql = "select "+Person_name.NAME+","+Person_name.AGE+","
                +Person_name.ADDRESS+" from "+DBString.TABLE_Person_NAME
                +" where "+Person_name.PERSON_NAME+" like ?";
        System.out.println("sql test:" + sql);

        ResultSet rs = SqlHelper.executeQuery(sql,params);

        datas = new ArrayList<>();

        try {
            while (rs.next()) {
                data = new PersonData();
                data.setPersonAge(rs.getString(Person_name.PERSON_AGE));
                data.setPersonName(rs.getString(Person_name.PERSON_NAME));
                data.setPersonAddress(rs.getString(Person_name.ADDRESS));
                datas.add(data);
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            SqlHelper.close(SqlHelper.getConn(), SqlHelper.getStat(), rs);
        }

        return datas;
    }

}

這裡又有一個坑:
當preparestatement語句中,有?又有%時,需要把%放在params定義中,而不能夠放在?旁邊,這個錯誤檢查了半天,始終找不出來,最後還是慢慢試出來的。
另外,上面代碼提到的Person_name是一個表,裡面僅僅存放了所有人的名字,方便用於查找用的。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved