Så här använder du Azure Mobile Apps SDK för Android

Den här guiden visar hur du använder Android-klient-SDK för Mobile Apps för att implementera vanliga scenarier, till exempel:

  • Fråga efter data (infoga, uppdatera och ta bort).
  • Autentisering.
  • Hantera fel.
  • Anpassa klienten.

Den här guiden fokuserar på Android SDK på klientsidan. Mer information om SDK:er på serversidan för Mobile Apps finns i Work with .NET backend SDK (Arbeta med .NET-serversidans SDK) eller How to use the Node.js backend SDK (Så här använder du SDK för Node.js serversidan).

Referensdokumentation

Du hittar Javadocs API-referensen för Android-klientbiblioteket på GitHub.

Plattformar som stöds

Azure Mobile Apps SDK för Android stöder API-nivåerna 19 till 24 (KitKat via Nojekt) för formfaktorer för telefoner och surfplattor. Autentisering använder i synnerhet en gemensam metod för webbramverk för att samla in autentiseringsuppgifter. Serverflödesautentisering fungerar inte med små formfaktorenheter, till exempel klockor.

Installation och krav

Slutför Mobile Apps självstudien . Den här uppgiften säkerställer att alla krav för att utveckla Azure Mobile Apps har uppfyllts. Snabbstarten hjälper dig också att konfigurera ditt konto och skapa din första mobilapps-backend.

Om du inte vill slutföra snabbstartskursen utför du följande uppgifter:

Uppdatera Gradle-byggfilen

Ändra båda build.gradle-filerna :

  1. Lägg till den här koden Projectbuild.gradle-filen på Project nivå:

    buildscript {
        repositories {
            jcenter()
            google()
        }
    }
    
    allprojects {
        repositories {
            jcenter()
            google()
        }
    }
    
  2. Lägg till den här koden i filenbuild.gradle på modulappnivå inuti beroendetaggen :

    implementation 'com.microsoft.azure:azure-mobile-android:3.4.0@aar'
    

    För närvarande är den senaste versionen 3.4.0. De versioner som stöds visas på bintray.

Aktivera Internet-behörighet

För att få åtkomst till Azure måste din app ha INTERNET-behörighet aktiverad. Om den inte redan är aktiverad lägger du till följande kodrad i din AndroidManifest.xml fil:

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

Skapa en klientanslutning

Azure Mobile Apps tillhandahåller fyra funktioner för ditt mobilprogram:

  • Dataåtkomst och offlinesynkronisering med en Azure Mobile Apps-tjänst.
  • Anropa anpassade API:er som skrivits med Azure Mobile Apps Server SDK.
  • Autentisering med Azure App Service autentisering och auktorisering.
  • Push-meddelanderegistrering med Notification Hubs.

Var och en av dessa funktioner kräver först att du skapar ett MobileServiceClient -objekt. Endast ett MobileServiceClient objekt ska skapas i din mobila klient (det vill säga det bör vara ett Singleton-mönster). Så här skapar du ett MobileServiceClient -objekt:

MobileServiceClient mClient = new MobileServiceClient(
    "<MobileAppUrl>",       // Replace with the Site URL
    this);                  // Your application Context

är <MobileAppUrl> antingen en sträng eller ett URL-objekt som pekar på din mobila backend. Om du använder Azure App Service värd för din mobila backend ska du kontrollera att du använder den säkra https:// versionen av URL:en.

Klienten kräver också åtkomst till aktiviteten eller kontexten – this parametern i exemplet. MobileServiceClient-konstruktionen ska ske inom metoden onCreate() för aktiviteten som refereras i AndroidManifest.xml filen.

Som bästa praxis bör du abstrahera serverkommunikationen till en egen klass (singleton-pattern). I det här fallet bör du skicka aktiviteten i konstruktorn för att konfigurera tjänsten på rätt sätt. Till exempel:

package com.example.appname.services;

import android.content.Context;
import com.microsoft.windowsazure.mobileservices.*;

public class AzureServiceAdapter {
    private String mMobileBackendUrl = "https://myappname.azurewebsites.net";
    private Context mContext;
    private MobileServiceClient mClient;
    private static AzureServiceAdapter mInstance = null;

    private AzureServiceAdapter(Context context) {
        mContext = context;
        mClient = new MobileServiceClient(mMobileBackendUrl, mContext);
    }

    public static void Initialize(Context context) {
        if (mInstance == null) {
            mInstance = new AzureServiceAdapter(context);
        } else {
            throw new IllegalStateException("AzureServiceAdapter is already initialized");
        }
    }

    public static AzureServiceAdapter getInstance() {
        if (mInstance == null) {
            throw new IllegalStateException("AzureServiceAdapter is not initialized");
        }
        return mInstance;
    }

    public MobileServiceClient getClient() {
        return mClient;
    }

    // Place any public methods that operate on mClient here.
}

Nu kan du anropa AzureServiceAdapter.Initialize(this); i metoden onCreate() för din huvudaktivitet. Alla andra metoder som behöver åtkomst till klienten använder för AzureServiceAdapter.getInstance(); att hämta en referens till tjänstkortet.

Dataåtgärder

Kärnan i Azure Mobile Apps SDK är att ge åtkomst till data som lagras SQL Azure i mobilappens backend. Du kan komma åt dessa data med hjälp av starkt typade klasser (rekommenderas) eller otypade frågor (rekommenderas inte). Merparten av det här avsnittet handlar om att använda starkt typindelade klasser.

Definiera klientdataklasser

För att komma åt data SQL Azure-tabeller definierar du klientdataklasser som motsvarar tabellerna i mobilappens backend. I exemplen i det här avsnittet förutsätts en tabell med namnet MyDataTable, som har följande kolumner:

  • id
  • text
  • slutföra

Motsvarande typade objekt på klientsidan finns i en fil med namnet MyDataTable.java:

public class ToDoItem {
    private String id;
    private String text;
    private Boolean complete;
}

Lägg till get- och set-metoder för varje fält som du lägger till. Om din SQL Azure innehåller fler kolumner lägger du till motsvarande fält i den här klassen. Om DTO -objektet (dataöverföringsobjektet) till exempel har en kolumn med heltalsprioritet kan du lägga till det här fältet tillsammans med dess get- och set-metoder:

private Integer priority;

/**
* Returns the item priority
*/
public Integer getPriority() {
    return mPriority;
}

/**
* Sets the item priority
*
* @param priority
*            priority to set
*/
public final void setPriority(Integer priority) {
    mPriority = priority;
}

Information om hur du skapar ytterligare tabeller i Mobile Apps-backend finns i Så här definierar du en tabellkontrollant (.NET-backend) eller Definiera tabeller med ett dynamiskt schema (Node.js-backend).

En Azure Mobile Apps-tabell definierar fem särskilda fält, varav fyra är tillgängliga för klienter:

  • String id: Det globalt unika ID:t för posten. Bästa praxis är att göra ID:t till strängrepresentationen för ett UUID-objekt .
  • DateTimeOffset updatedAt: Datum/tid för den senaste uppdateringen. Fältet updatedAt anges av servern och bör aldrig anges av klientkoden.
  • DateTimeOffset createdAt: Datum/tid då objektet skapades. Fältet createdAt anges av servern och bör aldrig anges av klientkoden.
  • byte[] version: Versionen representeras vanligtvis som en sträng och anges också av servern.
  • boolean deleted: Anger att posten har tagits bort men inte rensats ännu. Använd inte som deleted en egenskap i klassen .

Fältet id är obligatoriskt. Fältet updatedAt och fältet version används för offlinesynkronisering (för inkrementell synkronisering respektive konfliktlösning). Fältet createdAt är ett referensfält och används inte av klienten. Namnen är "över kabel"-namnen på egenskaperna och är inte justerbara. Du kan dock skapa en mappning mellan ditt -objekt och "över kabel"-namnen med hjälp av gson-biblioteket . Till exempel:

package com.example.zumoappname;

import com.microsoft.windowsazure.mobileservices.table.DateTimeOffset;

public class ToDoItem
{
    @com.google.gson.annotations.SerializedName("id")
    private String mId;
    public String getId() { return mId; }
    public final void setId(String id) { mId = id; }

    @com.google.gson.annotations.SerializedName("complete")
    private boolean mComplete;
    public boolean isComplete() { return mComplete; }
    public void setComplete(boolean complete) { mComplete = complete; }

    @com.google.gson.annotations.SerializedName("text")
    private String mText;
    public String getText() { return mText; }
    public final void setText(String text) { mText = text; }

    @com.google.gson.annotations.SerializedName("createdAt")
    private DateTimeOffset mCreatedAt;
    public DateTimeOffset getCreatedAt() { return mCreatedAt; }
    protected void setCreatedAt(DateTimeOffset createdAt) { mCreatedAt = createdAt; }

    @com.google.gson.annotations.SerializedName("updatedAt")
    private DateTimeOffset mUpdatedAt;
    public DateTimeOffset getUpdatedAt() { return mUpdatedAt; }
    protected void setUpdatedAt(DateTimeOffset updatedAt) { mUpdatedAt = updatedAt; }

    @com.google.gson.annotations.SerializedName("version")
    private String mVersion;
    public String getVersion() { return mVersion; }
    public final void setVersion(String version) { mVersion = version; }

    public ToDoItem() { }

    public ToDoItem(String id, String text) {
        this.setId(id);
        this.setText(text);
    }

    @Override
    public boolean equals(Object o) {
        return o instanceof ToDoItem && ((ToDoItem) o).mId == mId;
    }

    @Override
    public String toString() {
        return getText();
    }
}

Skapa en tabellreferens

Om du vill komma åt en tabell skapar du först ett MobileServiceTable-objekt genom att anropa metoden getTableMobileServiceClient. Den här metoden har två överlagringar:

public class MobileServiceClient {
    public <E> MobileServiceTable<E> getTable(Class<E> clazz);
    public <E> MobileServiceTable<E> getTable(String name, Class<E> clazz);
}

I följande kod är mClient en referens till ditt MobileServiceClient-objekt. Den första överlagringen används där klassnamnet och tabellnamnet är desamma och är det som används i snabbstarten:

MobileServiceTable<ToDoItem> mToDoTable = mClient.getTable(ToDoItem.class);

Den andra överlagringen används när tabellnamnet skiljer sig från klassnamnet: den första parametern är tabellnamnet.

MobileServiceTable<ToDoItem> mToDoTable = mClient.getTable("ToDoItemBackup", ToDoItem.class);

Fråga en backend-tabell

Hämta först en tabellreferens. Kör sedan en fråga i tabellreferensen. En fråga är valfri kombination av:

Satserna måste presenteras i föregående ordning.

Filtrera resultat

Den allmänna formen av en fråga är:

List<MyDataTable> results = mDataTable
    // More filters here
    .execute()          // Returns a ListenableFuture<E>
    .get()              // Converts the async into a sync result

Föregående exempel returnerar alla resultat (upp till den maximala sidstorlek som angetts av servern). Metoden .execute() kör frågan på backend- Frågan konverteras till en OData v3-fråga innan den överförs Mobile Apps backend. Vid mottagning konverterar Mobile Apps-backend frågan till en SQL-instruktion innan den körs på SQL Azure instansen. Eftersom nätverksaktiviteten tar lite tid returnerar .execute() metoden en ListenableFuture<E>.

Filtrera returnerade data

Följande frågekörning returnerar alla objekt från ToDoItem-tabellen där complete är lika med false.

List<ToDoItem> result = mToDoTable
    .where()
    .field("complete").eq(false)
    .execute()
    .get();

mToDoTable är referensen till mobiltjänsttabellen som vi skapade tidigare.

Definiera ett filter med hjälp av where-metod-anropet i tabellreferensen. Metoden where följs av en fältmetod följt av en metod som anger det logiska predikatet. Möjliga predikatmetoder är eq (lika med), ne (inte lika med), gt (större än), ge (större än eller lika med), lt (mindre än), le (mindre än eller lika med). Med dessa metoder kan du jämföra tal- och strängfält med specifika värden.

Du kan filtrera efter datum. Med följande metoder kan du jämföra hela datumfältet eller delar av datumet: år, månad, dag, timme, minut och sekund. I följande exempel läggs ett filter till för objekt vars förfallodatum är lika med 2013.

List<ToDoItem> results = MToDoTable
    .where()
    .year("due").eq(2013)
    .execute()
    .get();

Följande metoder stöder komplexa filter på strängfält: startsWith, endsWith, concat, subString, indexOf, replace, toLower, toUpper, trim och length. I följande exempel filtreras tabellrader där textkolumnen börjar med "PRI0".

List<ToDoItem> results = mToDoTable
    .where()
    .startsWith("text", "PRI0")
    .execute()
    .get();

Följande operatormetoder stöds för nummerfält: add, sub, mul, div, mod, floor, ceiling och round. I följande exempel filtreras tabellrader där varaktigheten är ett jämnt tal.

List<ToDoItem> results = mToDoTable
    .where()
    .field("duration").mod(2).eq(0)
    .execute()
    .get();

Du kan kombinera predikat med följande logiska metoder: och, eller och inte. I följande exempel kombineras två av de föregående exemplen.

List<ToDoItem> results = mToDoTable
    .where()
    .year("due").eq(2013).and().startsWith("text", "PRI0")
    .execute()
    .get();

Gruppera och kapsla logiska operatorer:

List<ToDoItem> results = mToDoTable
    .where()
    .year("due").eq(2013)
    .and(
        startsWith("text", "PRI0")
        .or()
        .field("duration").gt(10)
    )
    .execute().get();

Mer detaljerad diskussion och exempel på filtrering finns i Utforska hur omfattande Android-klientfrågemodellen är.

Sortera returnerade data

Följande kod returnerar alla objekt från en tabell med ToDoItems sorterade stigande efter textfältet . mToDoTable är referensen till den backend-tabell som du skapade tidigare:

List<ToDoItem> results = mToDoTable
    .orderBy("text", QueryOrder.Ascending)
    .execute()
    .get();

Den första parametern i metoden orderBy är en sträng som är lika med namnet på det fält som ska sorteras. Den andra parametern använder QueryOrder-uppräkningen för att ange om stigande eller fallande ska sorteras. Om du filtrerar med hjälp av metoden where måste metoden where anropas före metoden orderBy .

Välj specifika kolumner

Följande kod visar hur du returnerar alla objekt från en tabell med ToDoItems, men endast visar de fullständiga fältenoch textfälten . mToDoTable är referensen till den backend-tabell som vi skapade tidigare.

List<ToDoItemNarrow> result = mToDoTable
    .select("complete", "text")
    .execute()
    .get();

Parametrarna för select-funktionen är strängnamnen för tabellens kolumner som du vill returnera. Select-metoden måste följa metoder som where och orderBy. Den kan följas av växlingsmetoder som skip och top.

Returnera data på sidor

Data returneras ALLTID på sidor. Det maximala antalet poster som returneras anges av servern. Om klienten begär fler poster returnerar servern det maximala antalet poster. Som standard är den maximala sidstorleken på servern 50 poster.

Det första exemplet visar hur du väljer de fem översta objekten från en tabell. Frågan returnerar objekten från en tabell med ToDoItems. mToDoTable är referensen till den backend-tabell som du skapade tidigare:

List<ToDoItem> result = mToDoTable
    .top(5)
    .execute()
    .get();

Här är en fråga som hoppar över de första fem objekten och sedan returnerar nästa fem:

List<ToDoItem> result = mToDoTable
    .skip(5).top(5)
    .execute()
    .get();

Om du vill hämta alla poster i en tabell implementerar du kod för att iterera över alla sidor:

List<MyDataModel> results = new ArrayList<>();
int nResults;
do {
    int currentCount = results.size();
    List<MyDataModel> pagedResults = mDataTable
        .skip(currentCount).top(500)
        .execute().get();
    nResults = pagedResults.size();
    if (nResults > 0) {
        results.addAll(pagedResults);
    }
} while (nResults > 0);

En begäran för alla poster med den här metoden skapar minst två begäranden till Mobile Apps backend.

Tips

Att välja rätt sidstorlek är en balans mellan minnesanvändning medan begäran sker, bandbreddsanvändning och fördröjning i att ta emot data helt. Standardvärdet (50 poster) är lämpligt för alla enheter. Om du uteslutande använder större minnesenheter kan du öka upp till 500. Vi har upptäckt att en ökning av sidstorleken över 500 poster resulterar i oacceptabla fördröjningar och stora minnesproblem.

Gör så här: Sammanfoga frågemetoder

De metoder som används för att köra frågor mot backend-tabeller kan sammanfogas. Med länkning av frågemetoder kan du välja specifika kolumner med filtrerade rader som är sorterade och sidindelade. Du kan skapa komplexa logiska filter. Varje frågemetod returnerar ett Query-objekt. Om du vill avsluta serien med metoder och faktiskt köra frågan anropar du metoden execute . Till exempel:

List<ToDoItem> results = mToDoTable
        .where()
        .year("due").eq(2013)
        .and(
            startsWith("text", "PRI0").or().field("duration").gt(10)
        )
        .orderBy(duration, QueryOrder.Ascending)
        .select("id", "complete", "text", "duration")
        .skip(200).top(100)
        .execute()
        .get();

De länkade frågemetoderna måste ordnas på följande sätt:

  1. Filtreringsmetoder (var).
  2. Sorteringsmetoder (orderBy).
  3. Urvalsmetoder (select).
  4. metoder för växling (hoppaöver och över).

Binda data till användargränssnittet

Databindningen omfattar tre komponenter:

  • Datakällan
  • Skärmlayouten
  • Adaptern som kopplar ihop de två.

I vår exempelkod returnerar vi data från Mobile Apps SQL Azure ToDoItem till en matris. Den här aktiviteten är ett vanligt mönster för dataprogram. Databasfrågor returnerar ofta en samling rader som klienten hämtar i en lista eller matris. I det här exemplet är matrisen datakällan. Koden anger en skärmlayout som definierar vyn av de data som visas på enheten. De två binds samman med ett kort, som i den här koden är ett tillägg till klassen ArrayAdapterToDoItem<>.

Definiera layouten

Layouten definieras av flera kodfragment med XML-kod. I en befintlig layout representerar följande kod den ListView som vi vill fylla med våra serverdata.

    <ListView
        android:id="@+id/listViewToDo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:listitem="@layout/row_list_to_do" >
    </ListView>

I föregående kod anger listitem-attributet id för layouten för en enskild rad i listan. Den här koden anger en kryssruta och dess associerade text och instansieras en gång för varje objekt i listan. Den här layouten visar inte ID-fältet och en mer komplex layout skulle ange ytterligare fält i visningen. Den här koden finnsrow_list_to_do.xmlfilen .

<?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="horizontal">
    <CheckBox
        android:id="@+id/checkToDoItem"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/checkbox_text" />
</LinearLayout>

Definiera kortet

Eftersom datakällan i vyn är en matris med ToDoItem underklassar vi vårt kort från klassen ArrayAdapterToDoItem<>. Den här underklassen skapar en vy för varje ToDoItem med hjälp row_list_to_do layouten. I vår kod definierar vi följande klass som är ett tillägg till klassen ArrayAdapterE<>:

public class ToDoItemAdapter extends ArrayAdapter<ToDoItem> {
}

Åsidosätt adaptern getView-metoden . Till exempel:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;

        final ToDoItem currentItem = getItem(position);

        if (row == null) {
            LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
            row = inflater.inflate(R.layout.row_list_to_do, parent, false);
        }
        row.setTag(currentItem);

        final CheckBox checkBox = (CheckBox) row.findViewById(R.id.checkToDoItem);
        checkBox.setText(currentItem.getText());
        checkBox.setChecked(false);
        checkBox.setEnabled(true);

        checkBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (checkBox.isChecked()) {
                    checkBox.setEnabled(false);
                    if (mContext instanceof ToDoActivity) {
                        ToDoActivity activity = (ToDoActivity) mContext;
                        activity.checkItem(currentItem);
                    }
                }
            }
        });
        return row;
    }

Vi skapar en instans av den här klassen i vår aktivitet enligt följande:

    ToDoItemAdapter mAdapter;
    mAdapter = new ToDoItemAdapter(this, R.layout.row_list_to_do);

Den andra parametern i ToDoItemAdapter-konstruktorn är en referens till layouten. Nu kan vi instansiera ListView och tilldela kortet till ListView.

    ListView listViewToDo = (ListView) findViewById(R.id.listViewToDo);
    listViewToDo.setAdapter(mAdapter);

Använd adaptern för att binda till användargränssnittet

Nu är du redo att använda databindning. Följande kod visar hur du hämtar objekt i tabellen och fyller det lokala kortet med de returnerade objekten.

    public void showAll(View view) {
        AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>(){
            @Override
            protected Void doInBackground(Void... params) {
                try {
                    final List<ToDoItem> results = mToDoTable.execute().get();
                    runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            mAdapter.clear();
                            for (ToDoItem item : results) {
                                mAdapter.add(item);
                            }
                        }
                    });
                } catch (Exception exception) {
                    createAndShowDialog(exception, "Error");
                }
                return null;
            }
        };
        runAsyncTask(task);
    }

Anropa kortet varje gång du ändrar ToDoItem-tabellen . Eftersom ändringar görs post för post hanterar du en enskild rad i stället för en samling. När du infogar ett objekt anropar du metoden add på kortet. när du tar bort anropar du metoden remove .

Du hittar ett komplett exempel i Snabbstartsguide för Android Project.

Infoga data i backend

Instansiera en instans av klassen ToDoItem och ange dess egenskaper.

ToDoItem item = new ToDoItem();
item.text = "Test Program";
item.complete = false;

Använd sedan insert() för att infoga ett objekt:

ToDoItem entity = mToDoTable
    .insert(item)       // Returns a ListenableFuture<ToDoItem>
    .get();

Den returnerade entiteten matchar de data som infogas i backend-tabellen, inklusive ID:t och eventuella andra värden (createdAttill exempel fälten , updatedAtversion och ) som angetts på backend-enheten.

Mobile Apps-tabeller kräver en primärnyckelkolumn med namnet id. Den här kolumnen måste vara en sträng. Standardvärdet för KOLUMNEN ID är ett GUID. Du kan ange andra unika värden, till exempel e-postadresser eller användarnamn. När ett sträng-ID-värde inte anges för en infogad post genererar backend ett nytt GUID.

Sträng-ID-värden ger följande fördelar:

  • DU kan generera ETT -NUMMER utan att göra en tur och retur-resa till databasen.
  • Poster är enklare att sammanfoga från olika tabeller eller databaser.
  • ID-värden integreras bättre med ett programs logik.

Sträng-ID-värden krävs för offlinesynkroniseringsstöd. Du kan inte ändra ett ID när det har lagrats i serverdatabasen.

Uppdatera data i en mobilapp

Om du vill uppdatera data i en tabell skickar du det nya objektet till metoden update( ).

mToDoTable
    .update(item)   // Returns a ListenableFuture<ToDoItem>
    .get();

I det här exemplet är objektet en referens till en rad i toDoItem-tabellen som har gjort några ändringar i den. Raden med samma ID uppdateras.

Ta bort data i en mobilapp

Följande kod visar hur du tar bort data från en tabell genom att ange dataobjektet.

mToDoTable
    .delete(item);

Du kan också ta bort ett objekt genom att ange ID-fältet för raden som ska tas bort.

String myRowId = "2FA404AB-E458-44CD-BC1B-3BC847EF0902";
mToDoTable
    .delete(myRowId);

Leta upp ett specifikt objekt efter ID

Leta upp ett objekt med ett specifikt ID-fält med metoden lookUp( ):

ToDoItem result = mToDoTable
    .lookUp("0380BAFB-BCFF-443C-B7D5-30199F730335")
    .get();

Gör så här: Arbeta med otypade data

Den otypade programmeringsmodellen ger dig exakt kontroll över JSON-serialisering. Det finns några vanliga scenarier där du kanske vill använda en otypad programmeringsmodell. Om din backend-tabell till exempel innehåller många kolumner och du bara behöver referera till en delmängd av kolumnerna. Den typbestämda modellen kräver att du definierar alla kolumner som definieras Mobile Apps i din dataklass. De flesta API-anrop för åtkomst till data liknar de typade programmerings-anropen. Den största skillnaden är att i den otypade modellen anropar du metoder på MobileServiceJsonTable-objektet i stället för MobileServiceTable-objektet .

Skapa en instans av en otypad tabell

Precis som med den typade modellen börjar du med att hämta en tabellreferens, men i det här fallet är det ett MobileServicesJsonTable-objekt . Hämta referensen genom att anropa metoden getTable på en instans av klienten:

private MobileServiceJsonTable mJsonToDoTable;
//...
mJsonToDoTable = mClient.getTable("ToDoItem");

När du har skapat en instans av MobileServiceJsonTable har den praktiskt taget samma API som med den typade programmeringsmodellen. I vissa fall tar metoderna en otypad parameter i stället för en typad parameter.

Infoga i en otypad tabell

Följande kod visar hur du gör en infogning. Det första steget är att skapa ett JsonObject, som är en del av gson-biblioteket .

JsonObject jsonItem = new JsonObject();
jsonItem.addProperty("text", "Wake up");
jsonItem.addProperty("complete", false);

Använd sedan insert() för att infoga det otypade objektet i tabellen.

JsonObject insertedItem = mJsonToDoTable
    .insert(jsonItem)
    .get();

Om du behöver hämta ID:t för det infogade objektet använder du metoden getAsJsonPrimitive( ).

String id = insertedItem.getAsJsonPrimitive("id").getAsString();

Ta bort från en otypad tabell

Följande kod visar hur du tar bort en instans, i det här fallet samma instans av ett JsonObject som skapades i föregående infogningsexempel . Koden är samma som för det typifierade fallet, men metoden har en annan signatur eftersom den refererar till ett JsonObject.

mToDoTable
    .delete(insertedItem);

Du kan också ta bort en instans direkt med hjälp av dess ID:

mToDoTable.delete(ID);

Returnera alla rader från en otypad tabell

Följande kod visar hur du hämtar en hel tabell. Eftersom du använder en JSON-tabell kan du selektivt hämta endast vissa av tabellens kolumner.

public void showAllUntyped(View view) {
    new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... params) {
            try {
                final JsonElement result = mJsonToDoTable.execute().get();
                final JsonArray results = result.getAsJsonArray();
                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        mAdapter.clear();
                        for (JsonElement item : results) {
                            String ID = item.getAsJsonObject().getAsJsonPrimitive("id").getAsString();
                            String mText = item.getAsJsonObject().getAsJsonPrimitive("text").getAsString();
                            Boolean mComplete = item.getAsJsonObject().getAsJsonPrimitive("complete").getAsBoolean();
                            ToDoItem mToDoItem = new ToDoItem();
                            mToDoItem.setId(ID);
                            mToDoItem.setText(mText);
                            mToDoItem.setComplete(mComplete);
                            mAdapter.add(mToDoItem);
                        }
                    }
                });
            } catch (Exception exception) {
                createAndShowDialog(exception, "Error");
            }
            return null;
        }
    }.execute();
}

Samma uppsättning filtrerings-, filtrerings- och växlingsmetoder som är tillgängliga för den typerade modellen är tillgängliga för den otypade modellen.

Implementera offlinesynkronisering

Azure Mobile Apps Client SDK implementerar även offlinesynkronisering av data med hjälp av en SQLite-databas för att lagra en kopia av serverdata lokalt. Åtgärder som utförs på en offlinetabell kräver inte mobil anslutning för att fungera. Offlinesynkronisering underlättar återhämtning och prestanda på bekostnad av mer komplex logik för konfliktlösning. Azure Mobile Apps Client SDK implementerar följande funktioner:

  • Inkrementell synkronisering: Endast uppdaterade och nya poster laddas ned, vilket sparar bandbredd och minnesförbrukning.
  • Optimistisk samtidighet: Åtgärder antas lyckas. Konfliktlösningen skjuts upp tills uppdateringar utförs på servern.
  • Konfliktlösning: SDK:n identifierar när en ändring i konflikt har gjorts på servern och tillhandahåller hookar för att varna användaren.
  • Mjuk borttagning: Borttagna poster markeras som borttagna så att andra enheter kan uppdatera sin offline-cache.

Initiera offlinesynkronisering

Varje offlinetabell måste definieras i offlinecachen innan den används. Normalt görs tabelldefinitionen omedelbart efter att klienten har skapats:

AsyncTask<Void, Void, Void> initializeStore(MobileServiceClient mClient)
    throws MobileServiceLocalStoreException, ExecutionException, InterruptedException
{
    AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
        @Override
        protected void doInBackground(Void... params) {
            try {
                MobileServiceSyncContext syncContext = mClient.getSyncContext();
                if (syncContext.isInitialized()) {
                    return null;
                }
                SQLiteLocalStore localStore = new SQLiteLocalStore(mClient.getContext(), "offlineStore", null, 1);

                // Create a table definition.  As a best practice, store this with the model definition and return it via
                // a static method
                Map<String, ColumnDataType> toDoItemDefinition = new HashMap<String, ColumnDataType>();
                toDoItemDefinition.put("id", ColumnDataType.String);
                toDoItemDefinition.put("complete", ColumnDataType.Boolean);
                toDoItemDefinition.put("text", ColumnDataType.String);
                toDoItemDefinition.put("version", ColumnDataType.String);
                toDoItemDefinition.put("updatedAt", ColumnDataType.DateTimeOffset);

                // Now define the table in the local store
                localStore.defineTable("ToDoItem", toDoItemDefinition);

                // Specify a sync handler for conflict resolution
                SimpleSyncHandler handler = new SimpleSyncHandler();

                // Initialize the local store
                syncContext.initialize(localStore, handler).get();
            } catch (final Exception e) {
                createAndShowDialogFromTask(e, "Error");
            }
            return null;
        }
    };
    return runAsyncTask(task);
}

Hämta en referens till offline-cachetabellen

För en onlinetabell använder du .getTable(). För en offlinetabell använder du .getSyncTable():

MobileServiceSyncTable<ToDoItem> mToDoTable = mClient.getSyncTable("ToDoItem", ToDoItem.class);

Alla metoder som är tillgängliga för onlinetabeller (inklusive filtrering, sortering, växling, infogning av data, uppdatering av data och borttagning av data) fungerar lika bra på online- och offlinetabeller.

Synkronisera den lokala offlinecachen

Synkroniseringen ligger i din appkontroll. Här är ett exempel på en synkroniseringsmetod:

private AsyncTask<Void, Void, Void> sync(MobileServiceClient mClient) {
    AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>(){
        @Override
        protected Void doInBackground(Void... params) {
            try {
                MobileServiceSyncContext syncContext = mClient.getSyncContext();
                syncContext.push().get();
                mToDoTable.pull(null, "todoitem").get();
            } catch (final Exception e) {
                createAndShowDialogFromTask(e, "Error");
            }
            return null;
        }
    };
    return runAsyncTask(task);
}

Om ett frågenamn anges för .pull(query, queryname) metoden används inkrementell synkronisering för att endast returnera poster som har skapats eller ändrats sedan den senaste slutförda pullen.

Hantera konflikter vid offlinesynkronisering

Om en konflikt inträffar under .push() en åtgärd, MobileServiceConflictException uppstår en . Det server utfärdade objektet är inbäddat i undantaget och kan hämtas av .getItem() vid undantaget. Justera push-objektet genom att anropa följande objekt i objektet MobileServiceSyncContext:

  • .cancelAndDiscardItem()
  • .cancelAndUpdateItem()
  • .updateOperationAndItem()

När alla konflikter har markerats som du vill kan du anropa .push() igen för att lösa alla konflikter.

Anropa ett anpassat API

Med ett anpassat API kan du definiera anpassade slutpunkter som exponerar serverfunktioner som inte mappar till en infognings-, uppdaterings-, borttagnings- eller läsåtgärd. Genom att använda ett anpassat API kan du få mer kontroll över meddelanden, inklusive läsning och inställning av HTTP-meddelandehuvuden och definiera ett annat meddelandetextformat än JSON.

Från en Android-klient anropar du metoden invokeApi för att anropa den anpassade API-slutpunkten. I följande exempel visas hur du anropar en API-slutpunkt med namnet completeAll, som returnerar en samlingsklass med namnet MarkAllResult.

public void completeItem(View view) {
    ListenableFuture<MarkAllResult> result = mClient.invokeApi("completeAll", MarkAllResult.class);
    Futures.addCallback(result, new FutureCallback<MarkAllResult>() {
        @Override
        public void onFailure(Throwable exc) {
            createAndShowDialog((Exception) exc, "Error");
        }

        @Override
        public void onSuccess(MarkAllResult result) {
            createAndShowDialog(result.getCount() + " item(s) marked as complete.", "Completed Items");
            refreshItemsFromTable();
        }
    });
}

Metoden invokeApi anropas på klienten, som skickar en POST-begäran till det nya anpassade API:et. Resultatet som returneras av det anpassade API:et visas i en meddelandedialogruta, liksom eventuella fel. I andra versioner av invokeApi kan du välja att skicka ett objekt i begärandetexten, ange HTTP-metoden och skicka frågeparametrar med begäran. Otypade versioner av invokeApi tillhandahålls också.

Lägg till autentisering i appen

Självstudier beskriver redan i detalj hur du lägger till dessa funktioner.

App Service har stöd för autentisering av appanvändare med hjälp av olika externa identitetsproviders: Facebook, Google, Microsoft Account, Twitter och Azure Active Directory. Du kan ange behörigheter för tabeller för att begränsa åtkomsten för specifika åtgärder till endast autentiserade användare. Du kan också använda identiteten för autentiserade användare för att implementera auktoriseringsregler i din backend.

Två autentiseringsflöden stöds: ett serverflöde och ett klientflöde . Serverflödet ger den enklaste autentiseringsupplevelsen eftersom det förlitar sig på identitetsproviders webbgränssnitt. Inga ytterligare SDK:er krävs för att implementera serverflödesautentisering. Serverflödesautentisering ger ingen djupgående integrering med den mobila enheten och rekommenderas endast för konceptbevisscenarier.

Klientflödet möjliggör djupare integrering med enhetsspecifika funktioner, till exempel enkel inloggning, eftersom det förlitar sig på DEDK:er som tillhandahålls av identitetsprovidern. Du kan till exempel integrera Facebook SDK i ditt mobilprogram. Mobilklienten växlar till Facebook-appen och bekräftar din inloggning innan du växlar tillbaka till mobilappen.

Fyra steg krävs för att aktivera autentisering i din app:

  • Registrera din app för autentisering med en identitetsprovider.
  • Konfigurera App Service backend.
  • Begränsa tabellbehörigheter till autentiserade användare endast på App Service backend.
  • Lägg till autentiseringskod i din app.

Du kan ange behörigheter för tabeller för att begränsa åtkomsten för specifika åtgärder till endast autentiserade användare. Du kan också använda SID för en autentiserad användare för att ändra begäranden. Mer information finns i Kom igång med autentisering och i dokumentationen om Server SDK HOWTO.

Autentisering: Server Flow

Följande kod startar en inloggningsprocess för serverflöden med hjälp av Google-providern. Ytterligare konfiguration krävs på grund av säkerhetskraven för Google-providern:

MobileServiceUser user = mClient.login(MobileServiceAuthenticationProvider.Google, "{url_scheme_of_your_app}", GOOGLE_LOGIN_REQUEST_CODE);

Lägg dessutom till följande metod i huvudaktivitetsklassen:

// You can choose any unique number here to differentiate auth providers from each other. Note this is the same code at login() and onActivityResult().
public static final int GOOGLE_LOGIN_REQUEST_CODE = 1;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // When request completes
    if (resultCode == RESULT_OK) {
        // Check the request code matches the one we send in the login request
        if (requestCode == GOOGLE_LOGIN_REQUEST_CODE) {
            MobileServiceActivityResult result = mClient.onActivityResult(data);
            if (result.isLoggedIn()) {
                // login succeeded
                createAndShowDialog(String.format("You are now logged in - %1$2s", mClient.getCurrentUser().getUserId()), "Success");
                createTable();
            } else {
                // login failed, check the error message
                String errorMessage = result.getErrorMessage();
                createAndShowDialog(errorMessage, "Error");
            }
        }
    }
}

Definieras GOOGLE_LOGIN_REQUEST_CODE i din huvudaktivitet som används för login() metoden och i onActivityResult() metoden . Du kan välja ett unikt tal så länge samma tal används i metoden login() och onActivityResult() metoden . Om du abstraherar klientkoden till ett tjänstkort (som du visade tidigare) bör du anropa lämpliga metoder på tjänstkortet.

Du måste också konfigurera projektet för anpassadeflikar. Ange först en omdirigerings-URL. Lägg till följande kodfragment i AndroidManifest.xml:

<activity android:name="com.microsoft.windowsazure.mobileservices.authentication.RedirectUrlActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="{url_scheme_of_your_app}" android:host="easyauth.callback"/>
    </intent-filter>
</activity>

Lägg till redirectUriScheme i build.gradle filen för ditt program:

android {
    buildTypes {
        release {
            // … …
            manifestPlaceholders = ['redirectUriScheme': '{url_scheme_of_your_app}://easyauth.callback']
        }
        debug {
            // … …
            manifestPlaceholders = ['redirectUriScheme': '{url_scheme_of_your_app}://easyauth.callback']
        }
    }
}

Slutligen lägger du com.android.support:customtabs:28.0.0 till i listan över beroenden i build.gradle filen:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.google.code.gson:gson:2.3'
    implementation 'com.google.guava:guava:18.0'
    implementation 'com.android.support:customtabs:28.0.0'
    implementation 'com.squareup.okhttp:okhttp:2.5.0'
    implementation 'com.microsoft.azure:azure-mobile-android:3.4.0@aar'
    implementation 'com.microsoft.azure:azure-notifications-handler:1.0.1@jar'
}

Hämta ID:t för den inloggade användaren från en MobileServiceUser med hjälp av metoden getUserId . Ett exempel på hur du använder Futures för att anropa API:er för asynkron inloggning finns i Kom igång med autentisering.

Varning

Det URL-schema som nämns är case-sensitive. Se till att alla förekomster av {url_scheme_of_you_app} matchningsfallet.

Cacheautentiseringstoken

Cachelagring kräver att du lagrar användar-ID och autentiseringstoken lokalt på enheten. Nästa gång appen startar kontrollerar du cachen och om dessa värden finns kan du hoppa över inloggningsproceduren och återupplagra klienten med dessa data. Dessa data är dock känsliga och bör lagras krypterade av säkerhetsskäl om telefonen blir stulen. Du kan se ett komplett exempel på hur du cachelagrar autentiseringstoken i avsnittet Cacheautentiseringstoken.

När du försöker använda en token som har upphört att gälla får du ett 401-obehörigt svar. Du kan hantera autentiseringsfel med hjälp av filter. Filtrerar skärningspunktsbegäranden till App Service-backend. Filterkoden testar svaret för ett 401-fel, utlöser inloggningsprocessen och återupptar sedan begäran som genererade 401.

Använda uppdateringstoken

Den token som returneras Azure App Service autentisering och auktorisering har en definierad livslängd på en timme. Efter den här perioden måste du återauktorera användaren. Om du använder en långlivad token som du har tagit emot via klientflödesautentisering kan du autentisera på nytt med Azure App Service autentisering och auktorisering med samma token. En Azure App Service token genereras med en ny livslängd.

Du kan också registrera providern för att använda uppdateringstoken. En uppdateringstoken är inte alltid tillgänglig. Ytterligare konfiguration krävs:

  • Konfigurera Azure Active Directory klienthemlighet för Azure Active Directory appen. Ange klienthemligheten i Azure App Service när du konfigurerar Azure Active Directory autentisering. När du anropar .login()skickar du response_type=code id_token som en parameter:

    HashMap<String, String> parameters = new HashMap<String, String>();
    parameters.put("response_type", "code id_token");
    MobileServiceUser user = mClient.login
        MobileServiceAuthenticationProvider.AzureActiveDirectory,
        "{url_scheme_of_your_app}",
        AAD_LOGIN_REQUEST_CODE,
        parameters);
    
  • För Google skickar du som access_type=offline en parameter:

    HashMap<String, String> parameters = new HashMap<String, String>();
    parameters.put("access_type", "offline");
    MobileServiceUser user = mClient.login
        MobileServiceAuthenticationProvider.Google,
        "{url_scheme_of_your_app}",
        GOOGLE_LOGIN_REQUEST_CODE,
        parameters);
    
  • För Microsoft-konto väljer du omfånget wl.offline_access .

Om du vill uppdatera en token anropar du .refreshUser():

MobileServiceUser user = mClient
    .refreshUser()  // async - returns a ListenableFuture<MobileServiceUser>
    .get();

Du bör skapa ett filter som identifierar ett 401-svar från servern och försöker uppdatera användartoken.

Logga in med klientflödesautentisering

Den allmänna processen för att logga in med klientflödesautentisering är följande:

  • Konfigurera Azure App Service autentisering och auktorisering på samma sätt som med serverflödesautentisering.

  • Integrera SDK för autentiseringsprovider för autentisering för att skapa en åtkomsttoken.

  • Anropa metoden .login() på följande sätt (result ska vara en AuthenticationResult):

    JSONObject payload = new JSONObject();
    payload.put("access_token", result.getAccessToken());
    ListenableFuture<MobileServiceUser> mLogin = mClient.login("{provider}", payload.toString());
    Futures.addCallback(mLogin, new FutureCallback<MobileServiceUser>() {
        @Override
        public void onFailure(Throwable exc) {
            exc.printStackTrace();
        }
        @Override
        public void onSuccess(MobileServiceUser user) {
            Log.d(TAG, "Login Complete");
        }
    });
    

Se det fullständiga kodexe exemplet i nästa avsnitt.

Ersätt metoden onSuccess() med den kod som du vill använda vid en lyckad inloggning. Strängen {provider} är en giltig provider: aad (Azure Active Directory), facebook, google, microsoftaccount eller twitter. Om du har implementerat anpassad autentisering kan du även använda taggen för anpassad autentiseringsprovider.

Autentisera användare med Active Directory-autentiseringsbibliotek (ADAL)

Du kan använda Active Directory-autentiseringsbibliotek (ADAL) för att logga in användare i ditt program med Azure Active Directory. Att använda en klientflödesinloggning loginAsync() är ofta bättre än att använda metoderna eftersom det ger en mer inbyggd UX-känsla och möjliggör ytterligare anpassning.

  1. Konfigurera mobilappens backend för inloggning AAD genom att följa självstudien Så här konfigurerar du App Service Active Directory-inloggning. Se till att slutföra det valfria steget för att registrera ett inbyggt klientprogram.

  2. Installera ADAL genom att ändra filen build.gradle så att den innehåller följande definitioner:

    repositories {
        mavenCentral()
        flatDir {
            dirs 'libs'
        }
        maven {
            url "YourLocalMavenRepoPath\\.m2\\repository"
        }
    }
    packagingOptions {
        exclude 'META-INF/MSFTSIG.RSA'
        exclude 'META-INF/MSFTSIG.SF'
    }
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation('com.microsoft.aad:adal:1.16.1') {
            exclude group: 'com.android.support'
        } // Recent version is 1.16.1
        implementation 'com.android.support:support-v4:28.0.0'
    }
    
  3. Lägg till följande kod i programmet, vilket gör följande ersättningar:

    • Ersätt INSERT-AUTHORITY-HERE med namnet på den klientorganisation där du etablerade programmet. Formatet ska vara https://login.microsoftonline.com/contoso.onmicrosoft.com.
    • Ersätt INSERT-RESOURCE-ID-HERE med klient-ID:t för din mobilapps backend. Du kan hämta klient-ID:t fliken Avancerat under Azure Active Directory Inställningar på portalen.
    • Ersätt INSERT-CLIENT-ID-HERE med det klient-ID som du kopierade från det interna klientprogrammet.
    • Ersätt INSERT-REDIRECT-URI-HERE med webbplatsens /.auth/login/done-slutpunkt med hjälp av HTTPS-schemat. Det här värdet bör likna https://contoso.azurewebsites.net/.auth/login/done.
private AuthenticationContext mContext;

private void authenticate() {
    String authority = "INSERT-AUTHORITY-HERE";
    String resourceId = "INSERT-RESOURCE-ID-HERE";
    String clientId = "INSERT-CLIENT-ID-HERE";
    String redirectUri = "INSERT-REDIRECT-URI-HERE";
    try {
        mContext = new AuthenticationContext(this, authority, true);
        mContext.acquireToken(this, resourceId, clientId, redirectUri, PromptBehavior.Auto, "", callback);
    } catch (Exception exc) {
        exc.printStackTrace();
    }
}

private AuthenticationCallback<AuthenticationResult> callback = new AuthenticationCallback<AuthenticationResult>() {
    @Override
    public void onError(Exception exc) {
        if (exc instanceof AuthenticationException) {
            Log.d(TAG, "Cancelled");
        } else {
            Log.d(TAG, "Authentication error:" + exc.getMessage());
        }
    }

    @Override
    public void onSuccess(AuthenticationResult result) {
        if (result == null || result.getAccessToken() == null
                || result.getAccessToken().isEmpty()) {
            Log.d(TAG, "Token is empty");
        } else {
            try {
                JSONObject payload = new JSONObject();
                payload.put("access_token", result.getAccessToken());
                ListenableFuture<MobileServiceUser> mLogin = mClient.login("aad", payload.toString());
                Futures.addCallback(mLogin, new FutureCallback<MobileServiceUser>() {
                    @Override
                    public void onFailure(Throwable exc) {
                        exc.printStackTrace();
                    }
                    @Override
                    public void onSuccess(MobileServiceUser user) {
                        Log.d(TAG, "Login Complete");
                    }
                });
            }
            catch (Exception exc){
                Log.d(TAG, "Authentication error:" + exc.getMessage());
            }
        }
    }
};

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (mContext != null) {
        mContext.onActivityResult(requestCode, resultCode, data);
    }
}

Justera Client-Server kommunikation

Klientanslutningen är vanligtvis en grundläggande HTTP-anslutning med hjälp av det underliggande HTTP-biblioteket som medföljer Android SDK. Det finns flera orsaker till varför du vill ändra detta:

  • Du vill använda ett alternativt HTTP-bibliotek för att justera tidsgränser.
  • Du vill ange en förloppsstapel.
  • Du vill lägga till ett anpassat huvud som stöder API Management-funktioner.
  • Du vill fånga upp ett misslyckat svar så att du kan implementera omauthenticering.
  • Du vill logga begäranden från en backend till en analystjänst.

Använda ett alternativt HTTP-bibliotek

Anropa metoden .setAndroidHttpClientFactory() omedelbart efter att du har skapat din klientreferens. Om du till exempel vill ange anslutningens tidsgräns till 60 sekunder (i stället för standardvärdet 10 sekunder):

mClient = new MobileServiceClient("https://myappname.azurewebsites.net");
mClient.setAndroidHttpClientFactory(new OkHttpClientFactory() {
    @Override
    public OkHttpClient createOkHttpClient() {
        OkHttpClient client = new OkHttpClient();
        client.setReadTimeout(60, TimeUnit.SECONDS);
        client.setWriteTimeout(60, TimeUnit.SECONDS);
        return client;
    }
});

Implementera ett förloppsfilter

Du kan implementera en skärningspunkt för varje begäran genom att implementera en ServiceFilter. Följande uppdaterar till exempel en förloppsstapel som skapats i förväg:

private class ProgressFilter implements ServiceFilter {
    @Override
    public ListenableFuture<ServiceFilterResponse> handleRequest(ServiceFilterRequest request, NextServiceFilterCallback next) {
        final SettableFuture<ServiceFilterResponse> resultFuture = SettableFuture.create();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (mProgressBar != null) mProgressBar.setVisibility(ProgressBar.VISIBLE);
            }
        });

        ListenableFuture<ServiceFilterResponse> future = next.onNext(request);
        Futures.addCallback(future, new FutureCallback<ServiceFilterResponse>() {
            @Override
            public void onFailure(Throwable e) {
                resultFuture.setException(e);
            }
            @Override
            public void onSuccess(ServiceFilterResponse response) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (mProgressBar != null)
                            mProgressBar.setVisibility(ProgressBar.GONE);
                    }
                });
                resultFuture.set(response);
            }
        });
        return resultFuture;
    }
}

Du kan koppla det här filtret till klienten på följande sätt:

mClient = new MobileServiceClient(applicationUrl).withFilter(new ProgressFilter());

Anpassa begärandehuvuden

Använd följande ServiceFilter och bifoga filtret på samma sätt som :ProgressFilter

private class CustomHeaderFilter implements ServiceFilter {
    @Override
    public ListenableFuture<ServiceFilterResponse> handleRequest(ServiceFilterRequest request, NextServiceFilterCallback next) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                request.addHeader("X-APIM-Router", "mobileBackend");
            }
        });
        SettableFuture<ServiceFilterResponse> result = SettableFuture.create();
        try {
            ServiceFilterResponse response = next.onNext(request).get();
            result.set(response);
        } catch (Exception exc) {
            result.setException(exc);
        }
    }
}

Konfigurera automatisk serialisering

Du kan ange en konverteringsstrategi som gäller för varje kolumn med hjälp av gson-API: et. Android-klientbiblioteket använder gson i bakgrunden för att serialisera Java-objekt till JSON-data innan data skickas till Azure App Service. I följande kod används metoden setFieldNamingStrategy() för att ange strategin. Det här exemplet tar bort det inledande tecknet (ett "m") och gör sedan nästa tecken till gemener för varje fältnamn. Till exempel skulle "mId" omvandlas till "id". Implementera en konverteringsstrategi för att minska behovet av SerializedName() anteckningar i de flesta fält.

FieldNamingStrategy namingStrategy = new FieldNamingStrategy() {
    public String translateName(File field) {
        String name = field.getName();
        return Character.toLowerCase(name.charAt(1)) + name.substring(2);
    }
}

client.setGsonBuilder(
    MobileServiceClient
        .createMobileServiceGsonBuilder()
        .setFieldNamingStrategy(namingStrategy)
);

Den här koden måste köras innan du skapar en referens för mobila klienter med hjälp av MobileServiceClient.