RoboSpice — библиотека для асинхронных запросов

| 07.02.2015

Библиотека RoboSpice позволяет выполнять асинхронные запросы к внешнему серверу, например, для получения текстовых данных или изображений. При этом RoboSpice решает многие проблемы, которые могут возникнуть при выполнении подобных запросов. В частности, одна из распространенных — AsyncTask и поворот экрана в процессе ее выполнения. Задача вернет результат для старого Активити, а не для нового. С RoboSpice «мы можем спать спокойно» — все нюансы учтены и возможные проблемы решены.

Есть немалое количество примеров с использованием RoboSpice. Вы можете ознакомиться с ними здесь. В этой статье мы разберем, как с помощью RoboSpice получить json-строку с внешнего сайта. Один из способов мы разбирали ранее. Сейчас мы не будем парсить полученный json, а просто разберем пример, в котором получим эти данные с внешнего URL и выведем результат в TextView.

Итак, для начала добавим несколько строковых ресурсов.

res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">RoboSpice Example</string>
    <string name="action_settings">Settings</string>
    <string name="title_activity_sample_spice">SampleSpiceActivity</string>
    <string name="textview_text">textview_text</string>

</resources>

Создадим верстку основного экрана — res/layout/activity_main.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" >

    <TextView
        android:id="@+id/txtV"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:ellipsize="marquee"
        android:singleLine="true"
        android:text="textview_text" />

</LinearLayout>

Добавим нужные зависимости в gradle для библиотеки RoboSpice:

compile 'com.octo.android.robospice:robospice:1.4.14'

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

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.+'
    compile 'com.octo.android.robospice:robospice:1.4.14'
}

Создадим файл сервиса, наследующего SpiceService.

SampleSpiceService.java

package ru.androiddocs.robospiceexample;

import android.app.Application;

import com.octo.android.robospice.SpiceService;
import com.octo.android.robospice.persistence.CacheManager;
import com.octo.android.robospice.persistence.exception.CacheCreationException;
import com.octo.android.robospice.persistence.string.InFileStringObjectPersister;

public class SampleSpiceService extends SpiceService {

    @Override
    public CacheManager createCacheManager(Application application) throws CacheCreationException {
        CacheManager cacheManager = new CacheManager();

        InFileStringObjectPersister inFileStringObjectPersister =
                new InFileStringObjectPersister(application);

        cacheManager.addPersister(inFileStringObjectPersister);

        return cacheManager;
    }

    @Override
    public int getThreadCount() {
        return 3;
    }
}

Здесь, как мы видим, имеется два метода. В первом создается CacheManager для работы со строковыми данными, а во втором возвращается количество возможных потоков. В нашем случае — 3.

Создадим «базовый» класс Активити, который переопределяет несколько методов жизненного цикла приложения и содержит метод, возвращающий объект SpiceManager. В конструктор менеджера передается созданный ранее SampleSpiceService. Информацию об этом Активити в файл манифеста можно не добавлять (мы его не будем использовать по «прямому» назначению).

BaseSpiceActivity.java

package ru.androiddocs.robospiceexample;

import android.app.Activity;

import com.octo.android.robospice.SpiceManager;


public abstract class BaseSpiceActivity extends Activity {
    private SpiceManager spiceManager = new SpiceManager(SampleSpiceService.class);

    @Override
    protected void onStart() {
        spiceManager.start(this);
        super.onStart();
    }

    @Override
    protected void onStop() {
        spiceManager.shouldStop();
        super.onStop();
    }

    protected SpiceManager getSpiceManager() {
        return spiceManager;
    }

}

Теперь создадим наше основное Активити и унаследуем его от BaseSpiceActivity.

package ru.androiddocs.robospiceexample;

import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;

import com.octo.android.robospice.persistence.DurationInMillis;
import com.octo.android.robospice.persistence.exception.SpiceException;
import com.octo.android.robospice.request.listener.RequestListener;
import com.octo.android.robospice.request.simple.SimpleTextRequest;


public class SampleSpiceActivity extends BaseSpiceActivity {

    private TextView mTxtView;
    private SimpleTextRequest txtRequest;

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

        mTxtView = (TextView) findViewById(R.id.txtV);

        txtRequest = new SimpleTextRequest("http://androiddocs.ru/api/friends.json");
    }

    @Override
    protected void onStart() {
        super.onStart();

        getSpiceManager().execute(txtRequest, "txt", DurationInMillis.ONE_MINUTE,
                new TextRequestListener());
    }

    public final class TextRequestListener implements RequestListener<String> {

        @Override
        public void onRequestFailure(SpiceException spiceException) {
            Toast.makeText(SampleSpiceActivity.this, "failure", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onRequestSuccess(final String result) {

            Toast.makeText(SampleSpiceActivity.this, "success", Toast.LENGTH_SHORT).show();

            mTxtView.setText(result);
        }
    }
}

В методе onCreate() мы создаем объект SimpleTextRequest, передавая в конструктор урл-адрес, с которого будем тянуть json-строку. В общем-то, название SimpleTextRequest говорит само за себя.

В методе onStart() мы получаем SpiceManager методом getSpiceManager() и запускаем асинхронную задачу, передавая в качестве параметров объект запроса txtRequest, ключ для кэша «txt», продолжительность жизни кэша DurationInMillis.ONE_MINUTE и слушателя TextRequestListener, которому будет возвращен результат.

Внутренний класс слушателя TextRequestListener достаточно прост. Тут два метода обработки успешного и неуспешного запроса. В случае успеха, строка данных будет добавлена в TextView.

Не забудем добавить нужные permissions в файл манифеста. У меня это выглядит так:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="ru.androiddocs.robospiceexample" >

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >

        </activity>

        <service
            android:name=".SampleSpiceService"
            android:enabled="true"
            android:exported="true" >
        </service>

        <activity
            android:name=".SampleSpiceActivity"
            android:label="@string/title_activity_sample_spice" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

Запускаем приложение и получаем:

RoboSpice - библиотека для асинхронных запросов

Как я уже пояснял, сам json не разбираем, а помещаем его на экран как есть.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*