3

What is the easiest way to use XML-RPC in android? I tried http://code.google.com/p/android-xmlrpc/ , but it dooesn't compile and looks abandoned.

Ivan Gromov
  • 4,195
  • 9
  • 41
  • 57

4 Answers4

6

You can take a look at how the WordPress client for Android is doing it. The code is public under the GNU General Public Licence and can be inspected via SVN here: http://android.wordpress.org/development/

The client itself is implemented in the package org.xmlrpc.android essentially using Android provided libs, like e.g. the XmlPullParser: http://developer.android.com/reference/org/xmlpull/v1/XmlPullParser.html

It's not as simple as sticking a jar into your project, but it seems to be a lightweight path to explore. And it certainly works as the WordPress client is under ongoing development and use.

kongo09
  • 1,281
  • 10
  • 23
2

https://github.com/timroes/aXMLRPC

This project could be a better choice for XMLRPC client.

1

Is there a reason Apache's XML-RPC client (at http://ws.apache.org/xmlrpc/client.html) doesn't work?

Femi
  • 64,273
  • 8
  • 118
  • 148
  • Is this still activeley developed? The site shows the last update to be from February 2010 - which is more than 1.5 years ago. Other questions on stackoverflow (http://stackoverflow.com/questions/6946858/using-apache-xmlrpc-client-with-apache-httpclient-4-x) indicate that the client is not up-to-date. – kongo09 Aug 08 '11 at 14:47
  • Well, no, there really hasn't been any further development, but that may be because the XML RPC spec hasn't evolved since then. Why would it need to be be changed if it already does everything it needs to do to comply with the underlying spec? – Femi Aug 08 '11 at 18:49
  • With the risk of going off-topic here: I've been struggeling quite a bit with that client and found while it might be academically perfect according to the spec it is not perfect at all in the real world of the web - as many servers are just not 100% according to spec. E.g., try to use it with WordPress... It might not be a design goal to make it practically more usable, but if it is, then an ongoing development would be needed. – kongo09 Aug 10 '11 at 11:26
0

Current library for XMLRPC is working, but the example is too small. You definitely need another few threads to handle the communication. For me, a connection to Linux-Python is easy to make.

Here an example on top of the library, which is used in a restaurant (partially written myself):

package hha.zhongcan.communication;

import java.net.URI;

import android.os.Handler;

import android.util.Log;
import hha.zhongcan.framework.Citem;
import hha.zhongcan.framework.Configuration;
import hha.zhongcan.framework.CtimeFrame;
import hha.zhongcan.framework.Ctransaction;
import hha.zhongcan.microfood.AskTableDialog;
import hha.zhongcan.resources.Global;
import org.apache.http.conn.HttpHostConnectException;

interface XMLRPCMethodCallback 
{
    void callFinished(Object result);
}

/** Messages to send to the PC at high level. Receive the menu items, pages, transactions.
 *  Create fake data for the demo.
 *  
 * @author mensfort
 *
 */
public class Cmessage
{
    static private Cmessage     m_message =null;
    private static URI          m_uri;
    public static XMLRPCClient  m_client;
    private final static String TAG="message";
    private boolean             m_connected =false;
    private int m_pingId =0;
    private int m_lost =0;
    private int m_wait =0;
    private boolean m_sendTransactions =true;
    private Handler m_updateHandler = new Handler(); 
    boolean m_getItems = false;
    boolean m_getPages = false;
    private static Global m_global =null;
    private int m_countTransactions =10;
    private int transactionMessageCount =0;
    private long getValue( String s)
    {
        try
        {
            if ( s.startsWith("0x") || s.startsWith("0X"))
            {
                s =s.substring(2);
                while (s.startsWith("0"))
                {
                    s=s.substring(1);
                }
                if ( s.length() ==0)
                {
                    return 0;
                }
                return Long.parseLong(s, 16);  
            }
            if ( s=="")
            {
                return 0;
            }
            return Long.parseLong(s);
        }
        catch(Exception e)
        {
            e.printStackTrace();
            return 0;
        }
    }

    /// @brief New thread for running ask-table.
    private Runnable messageTask = new Runnable() 
    {
        //@override
        public void run() 
        {
            if ( m_getItems)
            {
                m_getItems =false;
                getMenuItems();
            }
            else if ( m_getPages)
            {
                m_getPages =false;
                getMenuPages();
            }
            else if ( m_sendTransactions)
            {
                // If I have sth to send and I'm not in page mode, then start sending items.
                sendTransactions();
                m_wait =2;
            }
            else if ( Configuration.getInstance().isDemo())
            {
                m_connected =true;
                next();
            }
            else if ( m_wait>0)
            {
                m_wait--;
                next();
            }
            else if ( --m_countTransactions<=0)
            {
                 sendMessage_getTransactions();
                 m_countTransactions =5;
            }
            else
            {
                 // Update this screen every 10 seconds.
                 sendConnected();
            }           
        }
    };  

    /** @brief At startup start the first message after a second.
     */
    private Cmessage()
    {
        m_updateHandler.postDelayed( messageTask, 1000);
    }

    /** @brief Set the address and port.
     * 
     * @param address [in] Address to use.
     * @param port [in] Port to use.
     */
    public void setPath( String address, Integer port)
    {
        m_uri = URI.create("http://192.168.0.105:9876");
        m_client  =new XMLRPCClient( m_uri); 
    }

    /** @brief Singleton implementation, only this instance can send messages.
     * 
     * @return Pointer to the singleton.
     */
    public static Cmessage getInstance()
    {
        if ( m_message ==null)
        {
            m_message =new Cmessage();
            m_global  =Global.getInstance();
        }
        return m_message;
    }

    /** @brief In a second, the next command can be send to the PC.
     */
    public void next()
    {
        m_updateHandler.postDelayed( messageTask, 1000);
    }

    /** @brief Check if we are connected to the PC. 
     * 
     * @return true when connected.
     */
    public boolean isConnected()
    {
        return m_connected;
    }

    /** @brief Send Ping message, just to check the connection status. 
     */
    public void sendConnected()
    {
        {
            XMLRPCMethod method =new XMLRPCMethod( "ping", new XMLRPCMethodCallback() {
                public void callFinished(Object result) 
                {
                    try 
                    {
                        String s = (String) (result);
                        if ( s.equals("bart"))
                        {
                            m_lost =0;
                            m_connected =true;
                        }
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        m_connected =false;
                        m_lost++;
                    }
                }
            });
            Object[] params ={ m_pingId++ }; // {};
            method.call(params);
        }
        if ( ++m_lost>2)
        {
            m_connected =false;
        }
    }

    public void sendMessage_getConfiguration() 
    {
        // TODO Auto-generated method stub      
    }

    private void createMenuFrom( Object [] arrY)
    {
        if ( arrY.length >0)
        {
            m_global.itemDB.clean();
        }
        int v=(int)(arrY.length/9);
        int lvl=1;
        for (int y=0; y<arrY.length; y++)  
        {
            if ( y==lvl*v)
            {
                setSlider(lvl++);
            }
            Log.i(TAG, "item " + y);
            Object[] arrX = (Object[]) arrY[y];
            int id =(Integer) arrX[0];
            String alias =(String) arrX[1];
            String local =(String) arrX[2];                         
            String chinese =(String) arrX[3];
            int restaurant_price =(Integer) arrX[4];
            int takeaway_price =(Integer) arrX[5];
            int level =(Integer) arrX[6];
            int page =(Integer) arrX[7];
            int sequence =(Integer) arrX[8];
            int colour_text = (int)(getValue( (String) arrX[9])&0xffffffff);
            int colour_background = (int)(getValue( (String) arrX[10])&0xffffffff);
            int colour_selected_text = (int)(getValue( (String) arrX[11])&0xffffffff);
            int colour_selected_background = (int)(getValue( (String) arrX[12])&0xffffffff);
            int colour_background2 = (int)(getValue( (String) arrX[13])&0xffffffff);
            int colour_selected_background2 = (int)(getValue( (String) arrX[14])&0xffffffff);
            if ( m_global.mainMenuHandler !=null)
            {
    //                  m_global.mainMenuHandler.obtainMessage( y, "UPDATE_MENU_SLIDEBAR "+y).sendToTarget();

            }
            m_global.itemDB.insert( id, alias, local, chinese, restaurant_price, 
                                  takeaway_price, (byte)level, (byte)page, (short)sequence, 
                                  colour_text, colour_background, colour_selected_text, 
                                  colour_selected_background, colour_background2, 
                                  colour_selected_background2);
        }
        m_global.itemDB.complete();
        Log.i(TAG, "Items received correct.");
    }

    /** Indicate that we want to get the menu card.
     */
    public void sendMessage_getMenuItems() 
    {
        m_getItems = true;
        m_getPages = true;
    }

    /** @brief Get the menu items. */
    public void getMenuItems() 
    {
        boolean demo =Configuration.getInstance().isDemo();
        if (demo ==true)
        {
            createMenuFrom( demoMenu.items);        
            next();
        }
        else
        {
            XMLRPCMethod method =new XMLRPCMethod( "items", new XMLRPCMethodCallback() {
                public void callFinished(Object result) 
                {
                    try 
                    {
                        m_global.itemDB.deleteAll();
                        m_global.itemDB.clean();
                        Object[] arrY = (Object[]) result;
                        createMenuFrom( arrY);
                        m_connected =true;
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        m_connected =false;
                    }
                }
            });
            Object[] params = {};
            if ( m_global.mainMenuHandler !=null)
            {
                m_global.mainMenuHandler.obtainMessage( 1, "UPDATE_MENU_SLIDEBAR 1").sendToTarget();
            }
            method.call(params);
            if ( m_global.mainMenuHandler !=null)
            {
                m_global.mainMenuHandler.obtainMessage( 1, "UPDATE_MENU_SLIDEBAR 5").sendToTarget();
            }
        }
    }

    /** Call to get all transactions from the server, including payments, items and time-frames. */
    public void sendMessage_sendTransactions() 
    {
        m_sendTransactions =true;
    }

    /** Set slider to a value 1..10 
     * 
     * @param n [in] 0..10
     */
    private void setSlider( int n)
    {
        if ( m_global.mainMenuHandler !=null)
        {
            m_global.mainMenuHandler.obtainMessage( 0, "UPDATE_MENU_SLIDEBAR "+n).sendToTarget();
        }
    }

    /** After sending the orders, the database can be cleaned...
     */
    private void cleanDatabase()
    {
        try 
        {
            m_global.transactionDB.clean();
            m_global.timeFrameDB.clean();
            m_global.transactionItemDB.clean();
            m_connected =true;
        } 
        catch (Exception e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
            m_connected =false;
        }
    }

    /** Send all transaction */
    private void sendTransactions()
    {
        if ( m_global.transactionDB.size() ==0)
        {
            m_sendTransactions =false;
            cleanDatabase();
            next();
            return;
        }
        if ( Configuration.getInstance().isDemo())
        {
            cleanDatabase();
            try
            {
                m_global.askTableHandler.obtainMessage( AskTableDialog.MESSAGE_DATA_SENT,-1,-1, -1).sendToTarget();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            m_sendTransactions =false;
        }
        XMLRPCMethod method =new XMLRPCMethod( "orders", new XMLRPCMethodCallback() 
        {
            public void callFinished(Object result) 
            {
                cleanDatabase();
                m_global.askTableHandler.obtainMessage( AskTableDialog.MESSAGE_DATA_SENT,-1,-1, -1).sendToTarget();
                m_sendTransactions =false;
            }
        });
        Object[][] transaction =m_global.transactionDB.get();
        Object[][] timeFrame   =m_global.timeFrameDB.get();
        Object[][] item        =m_global.transactionItemDB.get();

        Object[] params ={ transaction,timeFrame,item };

        //{
        //  transaction, timeFrame, item
        //}/;
        if ( transaction ==null || timeFrame ==null || item ==null)
        {
            cleanDatabase();
            Log.e( TAG,"Database problem!!");
        }
        method.call( params);
    }

    /// Call to get all transactions from the server, including payments, items and time-frames.
    public void sendMessage_getTransactions() 
    {
        if ( m_global.transactionDB.size() >0)
        {
            return;
        }
        if ( m_global.timeFrameDB.size() >0)
        {
            return;
        }
        if ( m_global.transactionItemDB.size() >0)
        {
            return;
        }
        XMLRPCMethod method =new XMLRPCMethod( "get_transactions", new XMLRPCMethodCallback() 
        {
            public void callFinished(Object result) 
            {
                m_countTransactions =10;
                m_connected =true;
                if ( m_global.transactionDB.size() >0)
                {
                    Log.i(TAG, "Transaction DB not empty.");
                    return;
                }
                if ( m_global.timeFrameDB.size() >0)
                {
                    Log.i(TAG, "Time Frame DB not empty.");
                    return;
                }
                if ( m_global.transactionItemDB.size() >0)
                {
                    Log.i(TAG, "Transaction Item DB not empty.");
                    return;
                }
                try 
                {
                    m_global.transactionList.clean();               
                    Object[] arrY = (Object[]) result;
                    Object[] transactions =(Object[]) arrY[0];
                    Object[] timeFrames   =(Object[]) arrY[1];
                    Object[] items        =(Object[]) arrY[2];
                    //Object[] payments     =(Object[]) arrY[3];

                    for (int y=0; y<transactions.length; y++) 
                    {
                        Object[] trx = (Object[]) transactions[y];
                        int id = Integer.valueOf(trx[0].toString());
                        String tme =trx[1].toString();
                        String name =trx[2].toString();
                        int customer_id =Integer.valueOf( trx[3].toString());
                        int status =Integer.valueOf( trx[4].toString());
                        int total =Integer.valueOf( trx[5].toString());
                        Ctransaction t=new Ctransaction( id, name, tme, status, customer_id, total);
                        m_global.transactionList.insert( t);
                    }
                    for (int y=0; y<timeFrames.length; y++) 
                    {
                        Object[] trx = (Object[]) timeFrames[y];
                        int id = Integer.valueOf( trx[0].toString());
                        int tfi =Integer.valueOf( trx[1].toString());
                        int waiter =Integer.valueOf( trx[2].toString());
                        String start_time =trx[3].toString();
                        String end_time =trx[4].toString();
                        int transaction_id =Integer.valueOf( trx[5].toString());
                        int device_id =Integer.valueOf( trx[6].toString());
                        CtimeFrame c =new CtimeFrame( id, (short)tfi, waiter, 
                                                      start_time, end_time, 
                                                      transaction_id, device_id);
                        m_global.transactionList.insert( c);
                    }
                    for (int y=0; y<items.length; y++) 
                    {
                        Object[] trx = (Object[]) items[y];
                        //int id = (Integer) trx[0];
                        long menu_item_id =Long.valueOf( trx[1].toString());
                        int sequence =Integer.valueOf( trx[2].toString());
                        int time_frame_index =Integer.valueOf( trx[3].toString());
                        int deleted_time_frame_index =Integer.valueOf( trx[4].toString());
                        long transaction_id =Long.valueOf( trx[5].toString());
                        int quantity =Integer.valueOf( trx[6].toString());
                        int level =Integer.valueOf( trx[7].toString());
                        int deleted =Integer.valueOf( trx[8].toString());
                        int portion =Integer.valueOf( trx[9].toString());
                        int orig_price =Integer.valueOf( trx[10].toString());
                        int unit_price =Integer.valueOf( trx[11].toString());
                        String time =trx[12].toString();                    
                        Citem i=new Citem( menu_item_id, y, (short)sequence, 
                                           (short)time_frame_index, 
                                           (short)deleted_time_frame_index,
                                           transaction_id, quantity, 
                                           (byte)level, deleted, (byte)portion, unit_price, orig_price, time);
                        m_global.transactionList.insert( i);
                    }
                    //for (int y=0; y<payments.length; y++) 
                    //{
                        //Object[] pay = (Object[]) payments[y];
                        //int id = (Integer) pay[0];
                        //String time =(String) pay[1];
                        //int money_received =(Integer) pay[2];
                        //int customer_id =(Integer) pay[3];
                        //int pay_method =(Integer) pay[4];
                        //int partial_index =(Integer) pay[5];
                        //global.paymentsDB.insert( id, time, money_received, customer_id, pay_method, partial_index);
                    //}
                } 
                catch (Exception e) 
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    m_connected =false;
                }
            }
        });
        Object[] params = { transactionMessageCount++ };
        method.call(params);
    }

    /// Call, but not in main thread, answer comes in a thread.
    private void getMenuPages() 
    {
        if ( Configuration.getInstance().isDemo())
        {
            decodePages( demoMenu.pages);
            next();
            return;
        }
        XMLRPCMethod method =new XMLRPCMethod( "pages", new XMLRPCMethodCallback() 
        {
            public void callFinished(Object result) 
            {
                decodePages( result);
            }
        });
        setSlider(7);
        Object[] params = {};
        method.call(params);
        setSlider(8);
    }

    /**  
     * @brief Convert an array to page data. 
     * @param result [in] array with local, chinese names.
     */
    private void decodePages( Object result)
    {
        try 
        {
            m_global.pageDB.clean();
            Object[] arrY = (Object[]) result;
            setSlider(9);
            for (int y=0; y<arrY.length; y++) 
            {
                Object[] arrX = (Object[]) arrY[y];
                int id = (Integer) arrX[0];
                String local =(String) arrX[1];
                String chinese =(String) arrX[2];
                String lc =local.replace( "'", "''");
                String ch =chinese.replace( "'", "''");
                m_global.pageDB.insert( id, lc, ch);
            }
            m_connected =true;
            if ( m_global.mainMenuHandler !=null)
            {
                m_global.mainMenuHandler.obtainMessage( 0, "UPDATE_MENU_READY").sendToTarget();
            }
        } 
        catch (Exception e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
            m_connected =false;
        }
    }

    class XMLRPCMethod extends Thread 
    {
        private String method;
        private Object[] params;
        private Handler handler;
        private XMLRPCMethodCallback callBack;
        public XMLRPCMethod(String method, XMLRPCMethodCallback callBack) 
        {
            this.method = method;
            this.callBack = callBack;
            handler = new Handler();
        }
        public void call() 
        {
            call(null);
        }
        public void call(Object[] params) 
        {
            this.params = params;
            start();
        }
        //@Override
        public void run() 
        {
             synchronized(this) 
             {
                try 
                {
                    final long t0 = System.currentTimeMillis();
                    final Object result = m_client.callEx(method, params);
                    final long t1 = System.currentTimeMillis();
                    handler.post(new Runnable() 
                    {
                        public void run() 
                        {
                            Log.i(TAG, "XML-RPC call took " + (t1-t0) + "ms");
                            callBack.callFinished(result);
                            next();
                        }
                    });
                } 
                catch (final XMLRPCFault e) 
                {
                    handler.post(new Runnable() 
                    {
                        public void run() 
                        {
                            Log.e(TAG, "Fault message: " + e.getFaultString() + "\nFault code: " + e.getFaultCode());
                            Log.d("Test", "error", e);
                            next();
                        }
                    });
                } 
                catch (final XMLRPCException e) 
                {
                    next();
                    handler.post(new Runnable() 
                    {
                        public void run() 
                        {
                            Throwable couse = e.getCause();
                            if (couse instanceof HttpHostConnectException) 
                            {
                                Log.e(TAG, "Cannot connect to " + m_uri.getHost() + "\nMake sure server.py on your development host is running !!!");
                            } 
                            else 
                            {
                                Log.e(TAG, "Error " + e.getMessage());
                            }
                            Log.d(TAG, "error", e);
                        }
                    });
                }
                catch (Exception e)
                {
                    next();
                    e.printStackTrace();
                }
             }
         }
    }
}
Bart Mensfort
  • 995
  • 11
  • 21