Retrofit and Laravel Restful API

Okay so a I’m writing this for two reasons, one: someone asked me to and secondly I wanted some sort of analytics view on my phone and making a blog post out of my efforts seemed like a good idea.

Laravel

I already store the page and the type of device that visited my site so getting a count of all the human visits to my site is easy. I mentioned human visits because other computers can visit my site as well to try and do something with the information that I publish. Google is a good example of this, they know what search result to return because they use computers to collect the information on websites all across the internet including my website. I don’t want google’s visits to count to the total visits for my articles so I filter that out.

Firstly in Laravel we need to create a controller for collecting the data and serialising it to something an Android client can consume(in this case JSON).

class ArticleController extends Controller
{
    public function index()
    {
        $articles = CmsArticle::all();

        /** @var CmsArticle $article */
        foreach($articles as &$article) {
            $article->total_visits = $article->totalVisits();
            $article->daily_visits = $article->dailyVisits();
        }

        return response()->json($articles);
    }
}

Then we add a route to the controller so we can expose it on a URL.

Route::group(array('namespace' => 'Api', 'prefix' => 'api'), function () {
    Route::resource('articles', 'ArticleController');
});

Android

For the android application we are going to use the RecyclerView and CardView support libraries to render the data on the screen. RecyclerView is much like ListView but much more memory and processor efficient. For the Android developers reading this, it standardises the view holder pattern. The CardView library is and attempt(a successful one) to help bring modern android design to older phones.

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

        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        mRecyclerView.setHasFixedSize(true);

        // use a linear layout manager
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        // specify an adapter (see also next example)
        mAdapter = new MyAdapter(myDataSet);
        mRecyclerView.setAdapter(mAdapter);

        this.fetchArticles();
    }

Gradle

On to the Android part. To import the libraries to build the android application we need to add the following to the dependencies list in Gradle.

    compile 'com.android.support:appcompat-v7:22.2.1'
    compile 'com.squareup.retrofit:retrofit:1.9.0'
    compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'
    compile 'com.squareup.okhttp:okhttp:2.0.0'
    compile 'com.android.support:cardview-v7:22.2.1'
    compile 'com.android.support:recyclerview-v7:22.2.1'

Retrofit

The first thing we need here is an object that we can use across our application to hold the API data after we receive it.

public class Article {
    private String title;
    private Integer total_visits;

    public Article(String title, Integer total_visits) {
        this.title = title;
        this.total_visits = total_visits;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Integer getTotal_visits() {
        return total_visits;
    }

    public void setTotal_visits(Integer totalViews) {
        this.total_visits = totalViews;
    }
}

Retrofit requires an API definition defined by a java interface, here is ours:

import java.util.List;

import retrofit.Callback;
import retrofit.http.GET;
import retrofit.http.Headers;

public interface WebsiteService {

    @Headers("User-Agent: android-api-client")
    @GET("/articles")
    void list(Callback<list
> cb); }

And lastly we need to call the API from Android, Android doesn’t allow web requests on the main thread so we have to use a callback.

    private void fetchArticles() {
        RestAdapter restAdapter = new RestAdapter.Builder()
                .setEndpoint("http://www.fritsstegmann.co.za/api")
                .build();

        WebsiteService service = restAdapter.create(WebsiteService.class);

        service.list(new Callback<list
>() { @Override public void success(List

articles, Response response) { myDataSet = articles; Log.i(“MA”, “Successful API Call”); for(Article article: articles) { Log.i(“MA”, article.getTitle()); } mRecyclerView.setAdapter(new MyAdapter(myDataSet)); mAdapter.notifyDataSetChanged(); } @Override public void failure(RetrofitError error) { Log.e(“MA”, error.getMessage()); } }); }

The final product is an Android application that shows the amount of page views for each blog post using material design guidelines.

Leave a Reply

Your email address will not be published. Required fields are marked *