SELECT * FROM Vzakladke.net

Статьи об автоматизации и программировании

Как создать поиск по сайту в Android используя формат JSON и выводить результат в ListView

 

 

Рассмотрим пример создания поисковой системы по сайту в Android приложении, используя выдачу в формате JSON и отображение результатов в ListView

Понятно, что наше приложение будет обращаться к какому то скрипту на сайте, напишем кусок нашего кода пусть результат запроса в виде массива попадает в в переменную $arr:


$result = array();			
if ($arr) {
  foreach($arr as $id=>$value) {  
    array_push($result, array(								
      "name" => $value['name'],
      "text" => $value['text'],
      "link" => URL.'post/'.$value['link'].'.html'
    ));						
  if($id == 50) {	break; 	}  
  }
} else {
    array_push($result, array(								
      "name" => "Главная страница",
      "text" => "Ничего не найдено. Измените Ваш запрос.",
  	  "link" => URL
    ));	
}

echo '{"all": ' .json_encode( $result  ) . '}';

 

 

Итак, в манифесте нужно разрешить нашему приложению доступ к интернету:

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

Но сразу забегая вперед, мы говорим, что в манифесте назначим наше новое активити, в котором будут появляться результаты нашего поиска. Для этого нужно тоже написать в манифесте следующее активити (иначе приложение при переходе будет вылетать)

       <activity android:name=".SearchList"
                android:label="@string/app_name">
        </activity>

Но и вдогонку, не знаю как Вы, я предпочитаю предоставлять возможность пользователю переносить свои приложения на карту памяти (вдруг у него места уже мало на устройстве).

Поэтому в шапке манифеста не помешает добавить такую строчку:

android:installLocation="auto"

 

Пора перейти к разметке, и заглянем в наш главный файл с текстом для ввода и кнопкой для поиска, назовем его к примеру form.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="vertical" >
     
    <TextView
        android:text=""
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
    />
     
    <EditText
        android:id="@+id/msgTextField"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="Type text"
    />
     
    <Button
        android:text="Search"
        android:id="@+id/sendButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:onClick="search"
    />        
</LinearLayout>

 

Когда мы нажимае кнопку, нам надо будет вызывать интент другого активти, поэтому создадим для него разметку list_search.xml:

< ?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="fill_parent"
    android:orientation="vertical">
	<!-- Main ListView 
		 Always give id value as list(@android:id/list)
	-->
    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

 

В ListView должно что то отображаться... напишем разметку отдельного и тема list_item.xml

 

< ?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="10dp"
    android:paddingLeft="10dp"
    android:paddingRight="10dp" >

    <!-- Name Label -->
    <TextView
        android:id="@+id/nametitle"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="2dip"
        android:paddingTop="6dip"
        android:textColor="#ff6600"
        android:textSize="16sp"
        android:textStyle="bold" />

    <!-- Text label -->
    <TextView
        android:id="@+id/context"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="2dip"
        android:textColor="#166D99" 
        android:textStyle="bold" />

    <!-- Link label -->
    <TextView
        android:id="@+id/linkhttp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="left"
        android:text=""
        android:textColor="#acacac"
         />

</LinearLayout>

 

Перейдем к коду на JAVA и напишем наш главный класс Searcher.java

import java.io.UnsupportedEncodingException;

import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

public class Searcher extends Activity   {

	//create variables for storing message & button objects
    EditText msgTextField;
    Button sendButton;    
    
    private ListView list;
    private ArrayAdapter<String> adapter;
    private ArrayList<String> arrayList;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.form);
        
        //make message text field object
        msgTextField = (EditText) findViewById(R.id.msgTextField);
        //make button object
        sendButton = (Button) findViewById(R.id.sendButton); 
        
        list = (ListView) findViewById(R.id.listViewID);         
 
    } // end onCreate 
    
 
    
    public void search(View v)
    {
        //get message from message box
        String  msg = msgTextField.getText().toString();
         
        //check whether the msg empty or not
        if(msg.length()>1) { 
       			try {
				String textsearch = URLEncoder.encode(msg.trim(), "utf-8");
	            Intent intento = new Intent(Searcher.this, SearchList.class);
	            intento.putExtra("searchtext", textsearch);
	            startActivity(intento);  			
				
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        } else {
            //display message if text field is empty
            Toast.makeText(getBaseContext(),"All fields are required",Toast.LENGTH_SHORT).show();
        }
    } // end search

    
}

Поиск работать будет если, Вы введете текст, иначе сообщение о необходимости заполнить все поля. Введенное слово обрезает пробелы по краям с помощью .trim() и кодируются в строку для поиска (чтобы не возникало ошибки). Далее мы передаем его в качестве параметра для следующего активити.

 

Для работы с форматом JSON нам поможет класс ServiceHandler.java

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

public class ServiceHandler {

	static String response = null;
	public final static int GET = 1;
	public final static int POST = 2;

	public ServiceHandler() {

	}

	/*
	 * Making service call
	 * @url - url to make request
	 * @method - http request method
	 * */
	public String makeServiceCall(String url, int method) {
		return this.makeServiceCall(url, method, null);
	}

	/*
	 * Making service call
	 * @url - url to make request
	 * @method - http request method
	 * @params - http request params
	 * */
	public String makeServiceCall(String url, int method,
			List<NameValuePair> params) {
		try {
			// http client
			DefaultHttpClient httpClient = new DefaultHttpClient();
			HttpEntity httpEntity = null;
			HttpResponse httpResponse = null;
			
			// Checking http request method type
			if (method == POST) {
				HttpPost httpPost = new HttpPost(url);
				// adding post params
				if (params != null) {
					httpPost.setEntity(new UrlEncodedFormEntity(params));
				}

				httpResponse = httpClient.execute(httpPost);

			} else if (method == GET) {
				// appending params to url
				if (params != null) {
					String paramString = URLEncodedUtils
							.format(params, "utf-8");
					url += "?" + paramString;
				}
				HttpGet httpGet = new HttpGet(url);

				httpResponse = httpClient.execute(httpGet);

			}
			httpEntity = httpResponse.getEntity();
			response = EntityUtils.toString(httpEntity);

		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return response;

	}
}

 

Теперь отобразим результаты поиска в нашем приложении, рассмотрим класс SearchList.java:

 
//import org.asksql.androidjson.R;
import java.util.ArrayList;
import java.util.HashMap;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;

public class SearchList extends ListActivity {

	private ProgressDialog pDialog;
	
	// JSON Node names
	private static final String TAG_ALL = "all";
	private static final String TAG_LINK = "link";
	private static final String TAG_NAME = "name";
	private static final String TAG_TEXT = "text";


	// contacts JSONArray
	JSONArray alls = null;

	// Hashmap for ListView
	ArrayList<HashMap<String, String>> textList;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		Intent intentstr = getIntent();
		String textsearch = intentstr.getStringExtra("searchtext");
		
		String url = "http://asksql.org/ajax/jsonsearch?q="+textsearch.trim();
		
		Toast.makeText(getBaseContext(),"Searching... ",Toast.LENGTH_SHORT).show();
		
		setContentView(R.layout.list_search);
		textList = new ArrayList<HashMap<String, String>>();

		ListView lv = getListView();

		// Listview on item click listener
		lv.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView< ? > parent, View view,
					int position, long id) {
				// getting values from selected ListItem
				String name = ((TextView) view.findViewById(R.id.nametitle))
						.getText().toString();
				String text = ((TextView) view.findViewById(R.id.context))
						.getText().toString();
				String link = ((TextView) view.findViewById(R.id.linkhttp))
						.getText().toString();
								
	        	  try {
	                 	Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(link));
	                   	startActivity(browserIntent); 
	              } catch (Exception e) {
	                  e.printStackTrace();
	              }				

			}
		});

		// Calling async task to get json
		new GetLists().execute();
	}

	/**
	 * Async task class to get json by making HTTP call
	 * */
	private class GetLists extends AsyncTask<Void, Void, Void> {

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			// Showing progress dialog
			pDialog = new ProgressDialog(SearchList.this);
			pDialog.setMessage("Please wait...");
			pDialog.setCancelable(false);
			pDialog.show();

		}

		@Override
		protected Void doInBackground(Void... arg0) {
			// Creating service handler class instance
			ServiceHandler sh = new ServiceHandler();

			
			Intent intentstr = getIntent();
			String textsearch = intentstr.getStringExtra("searchtext");
			
			String url = "http://asksql.org/ajax/jsonsearch?q="+textsearch.trim();
			
			
			// Making a request to url and getting response
			String jsonStr = sh.makeServiceCall(url, ServiceHandler.GET);

			Log.d("Response: ", "> " + jsonStr);

			if (jsonStr != null) {
				try {
					JSONObject jsonObj = new JSONObject(jsonStr);
					
					// Getting JSON Array node
					alls = jsonObj.getJSONArray(TAG_ALL);

					// looping through All Contacts
					for (int i = 0; i < alls.length(); i++) {
						JSONObject c = alls.getJSONObject(i);
						
						String s_link = c.getString(TAG_LINK);
						String s_name = c.getString(TAG_NAME);
						String s_text = c.getString(TAG_TEXT);


						// tmp hashmap for single contact
						HashMap<String, String> maptext = new HashMap<String, String>();

						// adding each child node to HashMap key => value
						maptext.put(TAG_LINK, s_link);
						maptext.put(TAG_NAME, s_name);
						maptext.put(TAG_TEXT, s_text);

						// adding contact to contact list
						textList.add(maptext);
					}
				} catch (JSONException e) {
					e.printStackTrace();
				}
			} else {
				Log.e("ServiceHandler", "Couldn't get any data from the url");
			}

			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			// Dismiss the progress dialog
			if (pDialog.isShowing())
				pDialog.dismiss();
			/**
			 * Updating parsed JSON data into ListView
			 * */
			ListAdapter adapter = new SimpleAdapter(
					SearchList.this, textList,
					R.layout.list_item, new String[] 
							{ TAG_NAME, TAG_TEXT,	TAG_LINK }, 
							new int[] 
							{ R.id.nametitle, R.id.context, R.id.linkhttp });

			setListAdapter(adapter);
		}

	}

}

 

Остальное Вам должно быть понятно из кода, если владеете уровнем элементарного английского языка и имеете хоть какой то опыт в программировании. 

Дата публикации: 2015-06-14 10:01:29

JAVA, Android

0

Отзывы:

Евгений Славянин
на самом деле как то так <activity android:name="MainActivity" android:screenOrientation="portrait" android:configChanges="keyboardHidden|orientation|screenSize">
Диман
В манифесте для активити нужно прописать, чтобы при повороте экрана оно не пересоздавалось, такой код: android:configChanges="orientation|keyboardHidden|screenSize"
Диман
И вместо TextView можно использовать WebView: WebView lblText= (WebView) findViewById(R.id.artist_label); String start = "<html><head><meta http-equiv='Content-Type' content='text/html' charset='UTF-8' /></head><body>"; String end = "</body></html>"; lblText.loadData(start+ text + end, "text/html; charset=UTF-8", null);
Любитель виски
Было бы разумным дописать такой код в onCreate, если нужна подгрузка контента: // LoadMore button Button btnLoadMore = new Button(this); btnLoadMore.setText("Показать ещё"); // Adding Load More button to lisview at bottom lv.addFooterView(btnLoadMore); /** * Listening to Load More button click event * */ btnLoadMore.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // Starting a new async task new GetLists().execute(); Toast.makeText(getApplicationContext(), "Страница "+Integer.toString(current_page+1), Toast.LENGTH_SHORT).show(); } }); понятно что нужно было переменные сначала объявить: int current_page = 0; int currentPosition; а в doInBackground(Void... arg0) дописать: current_page += 1; и в onPostExecute(Void result) дописать: ListView lv = getListView(); // get listview current position - used to maintain scroll position int currentPosition = lv.getFirstVisiblePosition(); ... /// setListAdapter(adapter); if ( current_page > 1 ) { // Setting new scroll position lv.setSelectionFromTop(currentPosition + 1, 0); }

Ваше имя:

Ваш e-mail (необязательно):

Сообщение:

Captcha