Поиск по этому блогу

среда, 13 февраля 2013 г.

Соединяемся с сервером и обрабатываем полученный json

Не думаю что я буду оригинальным в этой теме так как в интернете полным полно примеров которые должны вроде бы как показать как правильно работать, но у меня как у криворукого говнокодера примеры почему-то запускаются только с сайта stackowerflow, поэтому я решил сделать так называемую заметку на будущее если понадобится работать еще с json и с post / get запросами, всегда будет готовый пример / код под рукой. 
И так начнем, для начала нам нужен сервер который нам будет возвращать что либо, для этого нам понадобитсяwamp server который будет эмулировать наш сервер на компьютере, что бы не покупать хостинг за большие деньги, и конечно же нам нужно его настроить, настройка очень простая, запусукаем инсталятор, ждем пока проинсталируется и запускаем наш сервер, дальше по пути где вы установили открываем папку wamp/www/ и закидываем туда login.php к которому мы будем обращаться. 

Так как мы пишем приложение с работой с удаленным сервером я напишу небольшой скрипт который будет при правильном логине и пароле выдавать нам json строку которую позже мы будем парсить на телефоне.

Открываем в блокноте наш login.php и пишем вот этот код:

login.php
<?php // серверная часть вывода json

$login = $_POST['login'];
$pass = $_POST['pass'];
if($login == "user" & $pass == "pass") {
?>      {
"data":[
{
"firstName":"John",
"lastName":"Doe"
},
{
"firstName":"Anna",
"lastName":"Smith"
},
{
"firstName":"Peter",
"lastName":"Jones"
}
]
}<?php }
?> 


Тут все просто, при получении данных постом сервер их обрабатывает и сравнивает с теми данными которые у него есть, то есть user и pass, если они сходятся значит все отлично и можно отдавать json.

Теперь закидывайте этот файл в wamp/www/ и можно начинать писать клиентскую часть приложения. Создайте андроид проект и начнем.

Первая активность у нас будет посылать post запрос на сервер с логином и паролем, вторая активность принимает ответ от сервера и обрабатываем его для вывода в листвью.

MainActivity
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import org.apache.http.NameValuePair;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity {

        public EditText login;
        public EditText pass;
        private ProgressDialog dialog;
        private InputStream is;
        SecondActivity url;

        @Override
        public void onCreate(Bundle savedInstanceState) {

                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);
                Button btn = (Button) findViewById(R.id.button1);
                login = (EditText) findViewById(R.id.editText1);
                pass = (EditText) findViewById(R.id.editText2);
                btn.setOnClickListener(new OnClickListener() {

                        @Override
                        public void onClick(View v) {
                                //тут указываем куда будем конектится, для примера я привел удаленных хост если у вас не получилось освоить wamp (:
                                new RequestTask().execute("http://myhomepage.hol.es/login.php");
                        }
                });
        }

        class RequestTask extends AsyncTask<String, String, String> {

                @Override
                protected String doInBackground(String... params) {

                        try {
                                //создаем запрос на сервер
                                DefaultHttpClient hc = new DefaultHttpClient();
                                ResponseHandler<String> res = new BasicResponseHandler();
                                //он у нас будет посылать post запрос
                                HttpPost postMethod = new HttpPost(params[0]);
                                //будем передавать два параметра
                                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
                                //передаем параметры из наших текстбоксов
                                //лоигн
                                nameValuePairs.add(new BasicNameValuePair("login", login.getText().toString()));
                                //пароль
                                nameValuePairs.add(new BasicNameValuePair("pass", pass.getText().toString()));
                                //собераем их вместе и посылаем на сервер
                                postMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                                //получаем ответ от сервера
                                String response = hc.execute(postMethod, res);
                                //посылаем на вторую активность полученные параметры
                                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                                //то что куда мы будем передавать и что, putExtra(куда, что);
                                intent.putExtra(SecondActivity.JsonURL, response.toString());
                                startActivity(intent);
                        } catch (Exception e) {
                                System.out.println("Exp=" + e);
                        }
                        return null;
                }

                @Override
                protected void onPostExecute(String result) {

                        dialog.dismiss();
                        super.onPostExecute(result);
                }

                @Override
                protected void onPreExecute() {

                        dialog = new ProgressDialog(MainActivity.this);
                        dialog.setMessage("Загружаюсь...");
                        dialog.setIndeterminate(true);
                        dialog.setCancelable(true);
                        dialog.show();
                        super.onPreExecute();
                }
        }
}


Комментарии описывают весь функционал, остальное впринципе нам не сильно нужно, его я добавил чисто для карсоты.

Запрос мы выполняем в AsyncTask для меньшей загружености телефона, и что бы он не зависал при обработке запроса.

Главное окно


Ах да, как я забыл про разметочку нашей активити, вот она родимая ниже:

main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:text="Залогиниться" />

    <EditText
        android:id="@+id/editText2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/button1"
        android:layout_alignParentLeft="true"
        android:text="pass"
        android:ems="10" >

        <requestFocus />
    </EditText>

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/editText2"
        android:layout_alignParentLeft="true"
        android:text="Пароль" />

    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/textView2"
        android:layout_alignParentLeft="true"
        android:text="user"
        android:ems="10" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/editText1"
        android:layout_alignParentLeft="true"
        android:text="Логин" />
</RelativeLayout>


Воот, теперь нам нужно создать вторую активность которая будет принимать наш json и парсить его, для вывода в листвью. Там так же не сильно много кода, он простой и понятный, конечно же присутствуют комментарии.

SecondActivity
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
public class SecondActivity extends Activity {

        public static String JsonURL;
        private static ArrayList<HashMap<String, Object>> myBooks;
        private static final String FIRST = "firstname";
        private static final String LAST = "lastname";
        public ListView listView;

        /** @param result */
        public void JSONURL(String result) {

                try {
                        //создали читателя json объектов и отдали ему строку - result
                        JSONObject json = new JSONObject(result);
                        //дальше находим вход в наш json им является ключевое слово data
                        JSONArray urls = json.getJSONArray("data");
                        //проходим циклом по всем нашим параметрам
                        for (int i = 0; i < urls.length(); i++) {
                                HashMap<String, Object> hm;
                                hm = new HashMap<String, Object>();
                                //читаем что в себе хранит параметр firstname
                                hm.put(FIRST, urls.getJSONObject(i).getString("firstName").toString());
                                //читаем что в себе хранит параметр lastname
                                hm.put(LAST, urls.getJSONObject(i).getString("lastName").toString());
                                myBooks.add(hm);
                                //дальше добавляем полученные параметры в наш адаптер
                                SimpleAdapter adapter = new SimpleAdapter(SecondActivity.this, myBooks, R.layout.list,
                                                new String[] { FIRST, LAST, }, new int[] { R.id.text1, R.id.text2 });
                                //выводим в листвбю
                                listView.setAdapter(adapter);
                                listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
                        }
                } catch (JSONException e) {
                        Log.e("log_tag", "Error parsing data " + e.toString());
                }
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {

                super.onCreate(savedInstanceState);
                setContentView(R.layout.url);
                listView = (ListView) findViewById(R.id.list);
                myBooks = new ArrayList<HashMap<String, Object>>();
                //принимаем параметр который мы послылали в manActivity
                Bundle extras = getIntent().getExtras();
                //превращаем в тип стринг для парсинга
                String json = extras.getString(JsonURL);
                //передаем в метод парсинга
                JSONURL(json);
        }
}


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

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

url.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<ListView 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/list"
    />
</LinearLayout>


и сама разметка listview

list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:orientation="horizontal"
  android:layout_height="wrap_content">

  <LinearLayout
  android:layout_width="265dip"
  android:orientation="vertical"
  android:layout_height="wrap_content">
  
  <TextView android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:id="@+id/text1"
  android:textSize="25dip"
  android:text="This is text1"/>
  
  <TextView android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:id="@+id/text2"
  android:text="This is text2"/>
  
  </LinearLayout>
</LinearLayout>




Не забываем так же прописать в AndroidManifest доступ в интернет:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>


И доступ к второй активности:
<activity android:name="my.home.page.SecondActivity"></activity>


Вот теперь запускаем и проверяем как оно работает. Исходники я закинул на гит так что у тех у кого не получилось что либо смотрите их.

Скачать исходники с GitHub & Скачать исходники с Dropbox