2016年1月2日土曜日

android:Googleトレンドから急上昇ワードを取得する

androidアプリ内でGoogleトレンドの急上昇ワードを扱う。
  • Googleトレンドへのアクセスは、AsyncTaskLoaderを使用して非同期で通信する。
  • Googleトレンドから取得したXMLのパースはXmlPullParserで解析する。
  • 取得したワードはリストビュー(ListView)で表示する。

MainActivity


package net.kuttya.googletrendaccesssample;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.util.Xml;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import org.xmlpull.v1.XmlPullParser;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<String> {
    private final String GOOGLETREND_URL = "http://www.google.co.jp/trends/hottrends/atom/hourly";
    private final String ENCODING = "UTF-8";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Googleトレンドからワードを取得(非同期)
        getSupportLoaderManager().initLoader(0, null, this);

    }

    @Override
    public Loader<String> onCreateLoader(int id, Bundle args) {
        // GoogleトレンドにアクセスするAsyncTaskLoaderを返す
        return new HttpAccessingTaskLoader(this, GOOGLETREND_URL);
    }

    @Override
    public void onLoadFinished(Loader<String> loader, String data) {
        // Googleトレンドから取得したXMLから、CDATAの部分を抽出
        String htmlData = getHtmlData(data);

        // CDATAからワードを抽出
        List<String> words = getListData(htmlData);

        // リストビューのアダプタを作成、Googleトレンドのワードを設定
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, words);

        // リストビューにアダプタを設定
        ListView view = (ListView)findViewById(R.id.listView);
        view.setAdapter(adapter);
    }

    @Override
    public void onLoaderReset(Loader<String> loader) {
    }

    /**
     * Googleトレンドから取得したXMLデータから、CDATAの部分を抽出する
     * @param data 解析するXMLデータ
     * @return CDATA内のHTMLデータ
     */
    private String getHtmlData(String data) {
        String htmlData = "";
        try {
            // Xmlパーサで解析
            XmlPullParser xmlPullParser = Xml.newPullParser();
            xmlPullParser.setInput(new ByteArrayInputStream(data.getBytes(ENCODING)), ENCODING);
            int eventType;
            String tagName;
            while((eventType = xmlPullParser.next()) != XmlPullParser.END_DOCUMENT) {
                if(eventType == XmlPullParser.START_TAG) {
                    tagName = xmlPullParser.getName();

                    // contentタグの中身を抽出する
                    if(tagName.equals("content")) {
                        htmlData = xmlPullParser.nextText();
                        break;
                    }
                }
            }
        }
        catch(Exception e) {
            e.printStackTrace();
        }

        return htmlData;
    }

    /**
     * CDATA内のHTMLからワードを抽出する
     * @param htmlData 解析するHTMLデータ
     * @return 抽出したワードのリスト
     */
    private List<String> getListData(String htmlData) {
        List<String> listData = new ArrayList<String>();

        try {
            // HTMLでもXmlパーサで解析可能
            XmlPullParser xmlPullParser = Xml.newPullParser();
            xmlPullParser.setInput(new ByteArrayInputStream(htmlData.getBytes(ENCODING)), ENCODING);

            // content内の構造は下記
            // <li><span><a>データ</a></span></li>
            int eventType;
            String tagName;
            String word;
            boolean inLi = false;
            boolean inSpan = false;
            while((eventType = xmlPullParser.next()) != XmlPullParser.END_DOCUMENT) {
                switch(eventType) {
                    case XmlPullParser.START_TAG:
                        tagName = xmlPullParser.getName();
                        if(tagName.equals("li")) {
                            inLi = true;
                            break;
                        }
                        if(inLi != true) {
                            break;
                        }

                        // <Li>タグ内部のみ以下を実施

                        if(tagName.equals("span")) {
                            inSpan = true;
                            break;
                        }
                        if(inSpan != true) {
                            break;
                        }

                        // <span>タグ内部のみ以下を実施

                        if(tagName.equals("a")) {
                            // ワードを抽出
                            word = xmlPullParser.nextText();
                            listData.add(word);
                        }
                        break;
                    case XmlPullParser.END_TAG:
                        tagName = xmlPullParser.getName();
                        if(tagName.equals("li")) {
                            inLi = false;
                        }
                        else if(tagName.equals("span")) {
                            inSpan = false;
                        }
                        break;
                }
            }
        }
        catch(Exception e) {
            e.printStackTrace();
        }

        return listData;
    }
}



AsyncTaskLoader


package net.kuttya.googletrendaccesssample;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

/**
 * Created by junichi on 2016/01/02.
 */
public class HttpAccessingTaskLoader extends AsyncTaskLoader<String> {
    private String mUrl;

    public HttpAccessingTaskLoader(Context context, String url) {
        super(context);
        mUrl = url;
    }

    @Override
    public String loadInBackground() {
        String result = "";

        try {
            // URL
            URL url = new URL(mUrl);

            // 接続
            URLConnection connection = url.openConnection();

            // 結果を文字列で返す
            BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String line;
            while((line = br.readLine()) != null) {
                sb.append(line);
            }
            result = sb.toString();
        }
        catch(Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    @Override
    protected void onStartLoading() {
        forceLoad();
    }
}




レイアウト


リストビューだけ。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="net.kuttya.googletrendaccesssample.MainActivity">

    <ListView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/listView"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"/>
</RelativeLayout>



AndroidManifest.xml


パーミッションの追加を忘れずに。
<?xml version="1.0" encoding="utf-8"?>
<manifest package="net.kuttya.googletrendaccesssample"
          xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

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

</manifest>


実行結果