Showing posts with label android. Show all posts
Showing posts with label android. Show all posts

Friday, 2 December 2011

Error: The RequestFactory ValidationTool must be run for GWT 2.4

When loading up the CloudTasks tutorial as downloaded from the Google website, I encountered the following Runtime error:

SEVERE: Unexpected error
java.lang.RuntimeException: The RequestFactory ValidationTool must be run for the com.cloudtasks.shared.CloudTasksRequestFactory RequestFactory type

I found this article:

http://code.google.com/p/google-web-toolkit/wiki/RequestFactoryInterfaceValidation

Here's an excerpt:
The RequestFactory annotation processor will validate the RequestFactory interface declarations and ensure that the mapping of proxy properties and context methods to their domain types is valid. The manner in which the errors are reported depends on the method by which the annotation processor is invoked.
In addition to validating the interfaces, the annotation processor also generates additional Java types which embed pre-computed metadata that is required by the RequestFactory server components. Users of RequestFactorySource must also run the annotation processor in order to provide the client code with obfuscated type token mappings. In the client-only case, the server domain types are not required.
If the validation process is not completed, a runtime error message will be generated:
The RequestFactory ValidationTool must be run for the com.example.shared.MyRequestFactory RequestFactory type
In GWT 2.4, RequestFactory interfaces must be validated before they can be used by the RequestFactory server code or JVM-based clients. I followed the instructions for Eclipse as follows:
  • Right-click on Project and select Properties > Java Compiler > Annotation Processing
  • Tick "Enable project specific settings"
  • Then make sure that both "Enable annotation processing" and "Enable processing in editor" are ticked.
  • Go to Factory Path underneath Annotation Processing in the left-hand menu
  • Click the button "Add External Jar"
  • Add the requestfactory-apt.jar file from your Eclipse distribution
  • Press Apply and the project will re-build.
The images on the above link ask you to add this file from GWT_TOOLS, but the text says to use your distribution. I found my file under:

C:\dev\eclipse-3.5.2\plugins\com.google.gwt.eclipse.sdkbundle_2.4.0.relr35v201110112027\gwt-2.4.0

Thursday, 1 December 2011

Eclipse Android Library Error: Unable to get system library for the project

I downloaded some code via subclipse from the SVN server of Google to follow a tutorial. However, eclipse didn't know that it was an Android project and wouldn't let me build it as one no matter how many different ways I tried to add the android jar file. I found this great discussion on StackOverflow but this is what was wrong for me:
  • Right click on project > Properties > Android
  • Set Project build target (mine was ICS Android 4
  • Press Apply (I had to press apply 3 times for it to listen to me!)
  • Then go to Build Configuration and set the "Unable to get system library for the project" libraries Native folder to your Android jar (something like  C:/dev/AndroidSDK/platforms/android-14)
  • Right click on project > Android Tools > Fix Project Properties
  • Clean & Build
  • If nothing, try opening and closing the project
  • Also try pressing Apply on the build target some more
Sounds silly, but eclipse can be silly sometimes too!
Obviously check to make sure that you've set the Android SDK location in Window > Preferences > Android. My SDK location is C:\dev\AndroidSDK (not sure why eclipse holds the backslashes here and forward slashes above)

Tuesday, 29 November 2011

AppEngine Datastore implementation with Objectify - put()

Now I have set up the RequestFactory way of client-server communication, I now need to actually implement some logic to CRUD Gifts.

I am going to use the AppEngine Datastore, see:


Particulary note the comment: "In addition to the standard frameworks and low-level datastore API, the Java SDK supports other frameworks designed to simplify datastore usage for Java developers. A large number of Java developers use these frameworks. The Google App Engine team highly recommends them and encourages you to check them out."

This is because JDO and JPA are massive and have a steep learning curve They suggest Objectify, TWiG and Slim3. With my first Google I found this cool article by Andreas Borglin, and then lots of links to his article.


It seems to me that Objectify is the better option to get going, and this part of the pet-project is not that interesting to me (I AM suppose to be learning Android!). I first had a look at Concepts:


Then I downloaded the Objectify jar and added it to my project (as I'm using AppEngine SDK 1.5.5, I need to use Objectify version 3.1 beta (not the newer 3.1 version) released 13th October 2011)

Now for some implementation.

First I have to manually register the entities with ObjectifyService. The Best Practices guide advised me to use a DAO object with a static initialiser. so I created a new class in package com.yrdomain.yrproject.server;

import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.util.DAOBase;

/**
 * By accessing Objectify through your own DAO class, you can register your
 * entities in a static initializer and also add domain-specific helper methods.
 *
 */
public class DAO extends DAOBase {

    static {
        ObjectifyService.register(Gift.class);
    }

    /* Your DAO can have your own useful methods
    public MyThing getOrCreateMyThing(long id)
    {
        MyThing found = ofy().find(clazz, id);
        if (found == null)
            return new MyThing(id);
        else
            return found;
    }*/
}
 
I then didn't realise what I was doing and tried to get a reference to the Objectify twice with:

Objectify ofy = ObjectifyService.begin();
 
in my YrprojectService.java class. However, by extending DAOBase, it already gets this and is accessible by just typing:

dao.ofy().some_method()
 
If you do it twice it comes up with a NoClassDefFoundError for DAOBase - well it did the first time, when trying to re-create the error to put in the stack-trace for you guys, it worked fine!

This is a first go at the implementation:

public class YrprojectService {

    DAO dao = new DAO();

    @ServiceMethod
    public Gift createGift() {

        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();
        String message;
        if (user == null) {
          message = "No one is logged in!\nSent from App Engine at " + new Date();
        } else {
          message = "Howdie, " + user.getEmail() + 
"!\nSent from createGift on the App Engine at " + 
new Date();
        }

        // Simple create
        Gift porsche = new Gift();
        porsche.setGiftName("sports car");
        porsche.setGiftLocation(message);
        dao.ofy().put(porsche);
        assert porsche.getId() != null;    // id was autogenerated
        return porsche;

    }
    //...other CRUD methods...
}
 
It all works fine, as in there are no errors... but can I get my porche back?

Another Error

Objectify FAQs suggest that we turn off the datanucleus byte-code enhancer in Eclipse (go to the Project Properties -> Builders and disable the Enhancer) If you are using the default AppEngine Connected Android Project that is created when you use the Wizard in Eclipse, it uses JDO in the registration of the device. If you subsequently decide to use Objectify, turning off the datanucleus byte-code enhancer will give you the following error:

Failure: Got exception javax.jdo.JDOUserException: Persistent class "Class com.yrdomain.yrproject.server.DeviceInfo does not seem to have been enhanced. You may want to rerun the enhancer and check for errors in the output." has no table in the database, but the operation requires it. Please check the specification of the MetaData for this class. NestedThrowables: org.datanucleus.store.exceptions.NoTableManagedException: Persistent class "Class comyrdomain.yrproject.server.DeviceInfo does not seem to have been enhanced. You may want to rerun the enhancer and check for errors in the output." has no table in the database, but the operation requires it. Please check the specification of the MetaData for this class.

Just turn on the enhancer again, Clean and re-build, the error will go away. You have to remove all the default behaviour and use the Objectify ways. People like to turn off the enhancer because it can take too much time, its easier to just be a bit more specific in what files you want enhanced, remember it's looking for files that will be persisted. Change these options in:

Project Settings > Google > App Engine > ORM

Change the src/ and shared/ folders

Monday, 28 November 2011

Calling your own AppEngine Service methods

To test the operation of this I'm going to take a leaf out of the Task example and implement a Create button on the GWT front-end of the server, to make sure everything is wired up and working.

Add a new button to the web-page com.yrdomain.yrproject.client.YrprojectWidget.ui.xml

 <g:Button ui:field="createButton">Create</g:Button>
 
Open file com.yrdomain.yrproject.client.YrprojectWidget.java

Add the UI element:

@UiField
Button createButton;
 
And in the constructor, fire off a createGift() request.

createButton.addClickHandler(new ClickHandler() {
        public void onClick(ClickEvent event) {
            createButton.setEnabled(false);
            MygiftwishlistRequest mygwlRequest = requestFactory.mygiftwishlistRequest();
            mygwlRequest.createGift().fire(new Receiver<GiftProxy>() {
                @Override
                public void onFailure(ServerFailure error) {
                    createButton.setEnabled(true);
                    setStatus(error.getMessage(), true);
                }
                @Override
                public void onSuccess(GiftProxy response) {
                    createButton.setEnabled(true);
                    setStatus(response.getGiftLocation(), false);
                  }
                
            });
        }
    });
 
The RPC wizard automatically took the Gift.java Entity and created a GiftProxy, which it used in YrprojectRequest.java and added an entry for it in the MyRequestFactory.java (both in the shared folder).
Update the createGift() method to make it return something interesting - ok, just a variation on the HelloWorldService:

@ServiceMethod
    public Gift createGift() {
        
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();
        String message;
        if (user == null) {
          message = "No one is logged in!\nSent from App Engine at " + new Date();
        } else {
          message = "Howdie, " + user.getEmail() + 
"!\nSent from createGift on the App Engine at " + 
new Date();
        }
       
        Gift porsche = new Gift();
        porsche.setGiftName("sports car");
        porsche.setGiftLocation(message);
        
        return porsche;
    }
 
When we run the project, we see that when we press the Create button on the web-page, it calls the createGift() function on YrprojectService.java as expected.

Now we need to properly create Gifts and store them against the name of the user in the database.

RequestFactory implementation

This is a record of my implementation of the information contained in the following tutorial:

http://code.google.com/webtoolkit/doc/latest/DevGuideRequestFactory.html

I started with the default implementation of a new AppEngine Connected Android Project and I have been following the tutorial on the Google website:

http://www.youtube.com/watch?v=M7SxNNC429U&feature=player_embedded#!

Sometimes I cut and paste text from the Google website, or change it around slightly, so credit to and acknowledgement to Google where I have done this. It just makes it easier as their terminology is correct.
I wanted to add some gifts (as its Christmas!) to my default AppEngine Connected Android Project. They chose Tasks, I thought Gifts would be more fun :)

First I created my Gift.java class - a simple class with three variables: giftName, giftLocation, giftPrice (all Strings for now) and the getters and setters.

Now the thing that makes this POJO interesting is that I added the annotation @Entity. This describes my class being able to be 'persisted to a data store such as a relational database or the Google App Engine Datastore'.

Gift.java

package com.yrdomain.yrproject.server;

import javax.persistence.*;
import javax.validation.constraints.*;

@Entity
public class Gift {

      private String giftName;
      private String giftLocation;
      private String giftPrice;

      @Id
      @Column(name = "id")
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long id;

      @Version
      @Column(name = "version")
      private Integer version;

    public String getGiftName() {
        return giftName;
    }
    public void setGiftName(String giftName) {
        this.giftName = giftName;
    }

    public String getGiftLocation() {
        return giftLocation;
    }
    public void setGiftLocation(String giftLocation) {
        this.giftLocation = giftLocation;
    }

    public String getGiftPrice() {
        return giftPrice;
    }
    public void setGiftPrice(String giftPrice) {
        this.giftPrice = giftPrice;
    }

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public Integer getVersion() {
        return version;
    }
    public void setVersion(Integer version) {
        this.version = version;
    }
}
 
I was then able to use File > New > Google > RPC Service to generate me the necessary classes for the RPC service. Its an easy way to create the client-side code that does the basic CRUD operations. The wizard looks for all classes with persistence annotations (and finds Gift.java defined above) and uses this to create the following files in the same package:
  • GiftLocator.java
  • YrprojectService.java
  • YrprojectServiceLocator.java
and the proxy in the shared package:
  • GiftProxy.java
  • YrprojectRequest.java
and a new annotations package:
  • ServiceMethod.java
Lets have a look at some of these...

GiftProxy.java

The GiftProxy is the client-side representation (EntityProxy) of the server-side Gift (Entity). We associate it with the entity in the @ProxyFor annotation and link the persistence implementation with the GiftLocator class.
package com.yrdomain.yrproject.shared;

import com.google.web.bindery.requestfactory.shared.EntityProxy;
import com.google.web.bindery.requestfactory.shared.ProxyForName;

@ProxyForName(value   = "com.yrdomain.yrproject.server.Gift",
              locator = "com.yrdomain.yrproject.server.GiftLocator")
public interface GiftProxy extends EntityProxy {

    String getGiftName();
    void setGiftName(String giftName);

    String getGiftLocation();
    void setGiftLocation(String giftLocation);
    String getGiftPrice();
    void setGiftPrice(String giftPrice);

    Long getId();

    Integer getVersion();
    void setVersion(Integer version);
}
 
GiftLocator.java

The generated file is for when you don't want to implement persistence code in an entity itself. However there are two small problems with the generated file, maybe because the API is so new?
Change Void id to Long id (Eclipse will suggest that you implement all unimplemented methods, which will in effect re-define this method)
@Override
    public Gift find(Class<? extends Gift> clazz, Long id) {
        // TODO Auto-generated method stub
        return null;
    }
Add the missing semi-colon :)
@Override
    public Long getId(Gift domainObject) {
    return domainObject.getId();
    }
 
YrprojectRequest.java

This is found with the GiftProxy.java class in the shared package. This is a RequestFactory service stub, and it must extend RequestContext and uses the @Service or @ServiceName annotations to name the associated service implementation class on the server. The methods in a service stub do not return entities directly, but rather return subclasses of com.google.web.bindery.requestfactory.shared.Request.
This allows the methods on the interface to be invoked asynchronously with Request.fire()from the client.
package com.yrdomain.yrproject.shared;

import java.util.List;
import com.google.web.bindery.requestfactory.shared.Request;
import com.google.web.bindery.requestfactory.shared.RequestContext;
import com.google.web.bindery.requestfactory.shared.ServiceName;

@ServiceName(value = "com.yrdomain.yrproject.server.YrprojectService", locator = "com.yrdomain.yrproject.server.YrprojectServiceLocator")
public interface YrprojectRequest extends RequestContext {

    Request<GiftProxy> createGift();
    Request<GiftProxy> readGift(Long id);
    Request<GiftProxy> updateGift(GiftProxy gift);
    Request<Void> deleteGift(GiftProxy gift);
    Request<List<GiftProxy>> queryGifts();
}
 
YrprojectService.java

package com.yrdomain.yrproject.server;

import java.util.List;
import com.yrdomain.yrproject.annotation.ServiceMethod;

public class YrprojectService {

    @ServiceMethod
    public Gift createGift() {
        // TODO Auto-generated method stub
        return null;
    }
    @ServiceMethod
    public Gift readGift(Long id) {
        // TODO Auto-generated method stub
        return null;
    }
    @ServiceMethod
    public Gift updateGift(Gift gift) {
        // TODO Auto-generated method stub
        return null;
    }
    @ServiceMethod
    public void deleteGift(Gift gift) {
        // TODO Auto-generated method stub
    }
    @ServiceMethod
    public List<Gift> queryGifts() {
        // TODO Auto-generated method stub
        return null;
    }
}
 
You'll notice that the Service class above imports a generated annotation class too:


package com.yrdomain.yrproject.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Annotation on method specifying that the method is a service method
 * and needs to have the corresponding request factory code
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface ServiceMethod {
}
 
YrprojectServiceLocator.java

package com.yrdomain.yrproject.server;

import com.google.web.bindery.requestfactory.shared.ServiceLocator;

public class YrprojectServiceLocator implements ServiceLocator {

    @Override
    public Object getInstance(Class<?> clazz) {
        try {
            return clazz.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}
 
That's enough for one post... next, making it do stuff!

Thursday, 24 November 2011

FATAL EXCEPTION: IntentService due to NullPointerException on PendingIntent.getActivity()

When sending a message to your Android device you use the default GWT template provided:

C2DM web service

You must have used a registered email address (see previous post) otherwise you'll get a Failure. If all is fine you'll get a Success: message sent message.
However, just because all things are rosy this side, doesn't mean that your phone has picked up the message:

11-24 17:37:35.586: E/AndroidRuntime(1339): FATAL EXCEPTION: IntentService[role@yrdomain.com]
11-24 17:37:35.586: E/AndroidRuntime(1339): java.lang.NullPointerException
11-24 17:37:35.586: E/AndroidRuntime(1339):   
at android.app.PendingIntent.getActivity(PendingIntent.java:195)
11-24 17:37:35.586: E/AndroidRuntime(1339):   
at com.example.yourname.Util.generateNotification(Util.java:120)
11-24 17:37:35.586: E/AndroidRuntime(1339):   
at com.example.yourname.MessageDisplay.displayMessage(MessageDisplay.java:44)
11-24 17:37:35.586: E/AndroidRuntime(1339):   
at com.example.yourname.C2DMReceiver.onMessage(C2DMReceiver.java:82)
11-24 17:37:35.586: E/AndroidRuntime(1339):   
at com.google.android.c2dm.C2DMBaseReceiver.onHandleIntent(C2DMBaseReceiver.java:112)
11-24 17:37:35.586: E/AndroidRuntime(1339):   
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
11-24 17:37:35.586: E/AndroidRuntime(1339):   
at android.os.Handler.dispatchMessage(Handler.java:99)
11-24 17:37:35.586: E/AndroidRuntime(1339):     at android.os.Looper.loop(Looper.java:137)
11-24 17:37:35.586: E/AndroidRuntime(1339):   
at android.os.HandlerThread.run(HandlerThread.java:60)

This is due to the default code that comes with the standard New install of the Android Cloud to Device Messaging (C2DM):

    /**
     * Display a notification containing the given string.
     */
    public static void generateNotification(Context context, String message) {
        int icon = R.drawable.status_icon;
        long when = System.currentTimeMillis();

        Notification notification = new Notification(icon, message, when);
        notification.setLatestEventInfo(context, "C2DM Example", message,
                PendingIntent.getActivity(context, 0, null, PendingIntent.FLAG_CANCEL_CURRENT));
        notification.flags |= Notification.FLAG_AUTO_CANCEL;

        SharedPreferences settings = Util.getSharedPreferences(context);
        int notificatonID = settings.getInt("notificationID", 0);

        NotificationManager nm = (NotificationManager) context
                .getSystemService(Context.NOTIFICATION_SERVICE);
        nm.notify(notificatonID, notification);

        SharedPreferences.Editor editor = settings.edit();
        editor.putInt("notificationID", ++notificatonID % 32);
        editor.commit();    

    }
 
Besides the fact that they really should be using the new Notification.Builder (introduced in Honeycomb API 11), this piece of code gives a NullPointerException because of the null value given where an Intent is expected.

PendingIntent.getActivity(context, 0, null, PendingIntent.FLAG_CANCEL_CURRENT));
 
All you have to do is add an Intent:

PendingIntent.getActivity(context, 0, new Intent(Util.DUMMY_PENDING_INTENT)
PendingIntent.FLAG_CANCEL_CURRENT));

You could use an existing one declared in Util.java, or you can create a new one like I did here called DUMMY_PENDING_INTENT. It doesn't matter because we are not going to use the Intent to start an activity, it's just an example to display a message on the notification bar. In a real program you would launch your app, just as an email notification launches your email app, etc.

Wednesday, 23 November 2011

Your First Connect to the Cloud Error: PHONE_REGISTRATION_ERROR

When you set up your new project you added in your role email address as in this image. This is the same role email address that you used to sign up for Android Cloud to Device Messaging. If you haven't done this yet then go to http://code.google.com/android/c2dm/signup.html and fill in the form and wait for the confirmation email before proceeding.

Configure C2DM

You build the projects and launch in Debug for the first time. All Android devices have the concept of a Google email address and password that is usually set up on the first day you have the phone. Thereafter you don't have to supply your email address and password every time you connect to a Google service. However, if you try to connect to the cloud using the role email address that you used to register with C2DM then you'll get the following error:

C2DM Connect to the Cloud Screen

11-23 15:39:11.444: E/C2DM(629): Registration error PHONE_REGISTRATION_ERROR
11-23 15:39:31.584: I/dalvikvm(629): threadid=3: reacting to signal 3
11-23 15:39:31.623: D/dalvikvm(629): threadid=1: still suspended after undo (sc=1 dc=1)
11-23 15:39:31.623: I/dalvikvm(629): Wrote stack traces to '/data/anr/traces.txt'
11-23 15:39:41.677: D/AndroidRuntime(629): Shutting down VM
11-23 15:39:41.677: W/dalvikvm(629): threadid=1: thread exiting with uncaught exception (group=0x409951f8)
11-23 15:39:41.854: E/AndroidRuntime(629): FATAL EXCEPTION: main
11-23 15:39:41.854: E/AndroidRuntime(629): java.lang.RuntimeException: Error receiving broadcast Intent { act=comexample.yourname.UPDATE_UI flg=0x10 } in com.example.yournameActivity$1@41058dd8
11-23 15:39:41.854: E/AndroidRuntime(629):     at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:737)
11-23 15:39:41.854: E/AndroidRuntime(629):     at android.os.Handler.handleCallback(Handler.java:605)
11-23 15:39:41.854: E/AndroidRuntime(629):     at android.os.Handler.dispatchMessage(Handler.java:92)
11-23 15:39:41.854: E/AndroidRuntime(629):     at android.os.Looper.loop(Looper.java:137)
11-23 15:39:41.854: E/AndroidRuntime(629):     at android.app.ActivityThread.main(ActivityThread.java:4340)
11-23 15:39:41.854: E/AndroidRuntime(629):     at java.lang.reflect.Method.invokeNative(Native Method)
11-23 15:39:41.854: E/AndroidRuntime(629):     at java.lang.reflect.Method.invoke(Method.java:511)
11-23 15:39:41.854: E/AndroidRuntime(629):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
11-23 15:39:41.854: E/AndroidRuntime(629):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
11-23 15:39:41.854: E/AndroidRuntime(629):     at dalvik.system.NativeStart.main(Native Method)
11-23 15:39:41.854: E/AndroidRuntime(629): Caused by: java.lang.NullPointerException
11-23 15:39:41.854: E/AndroidRuntime(629):     at android.app.PendingIntent.getActivity(PendingIntent.java:195)
11-23 15:39:41.854: E/AndroidRuntime(629):     at com.example.yourname.Util.generateNotification(Util.java:120)
11-23 15:39:41.854: E/AndroidRuntime(629):     at com.example.yournameActivity$1.onReceive(yournameActivity.java:81)
11-23 15:39:41.854: E/AndroidRuntime(629):     at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:728)
11-23 15:39:41.854: E/AndroidRuntime(629):     ... 9 more

This is because you are trying to connect without a proper gmail address. If you have connected up your live device, choose another email address such as your personal one to test. If you are using the simulator, you need to go into the Settings and add another google account - again add your personal one. You'll then have success :)

C2DM Contacting server

C2DM Successful response from App Engine

New App Engine Connected Android Project Won't Build

It's really irritating when watching a really cool video showing how easy it is to create a new project and right out of the box (so to speak) it doesn't compile :(

This happened to me whilst checking out the cool new App Engine Connected Android Project tutorial from Google IO 2011.

You have to download the Google plug-in for eclipse first of course, but then select New > Other > App Engine Connected Android Project.

It doesn't build - lots of errors - specifically can't find:

com.example.yourname.client.MyRequestFactory;
import com.example.yourname.client.MyRequestFactory.RegistrationInfoRequest;
import com.example.yourname.shared.RegistrationInfoProxy;

All we need to do is to build the two projects properly:
  1. Right-click on yourname-Android >Build Path > Configure Build Path... and go to the Projects Tab.
  2. Add the yourname-AppEngine project to the Android project by pressing the Add button and choosing it.
  3. Right-click on yourname-Android > Debug As >Local App Engine Connected Android Application.
No more red :)

If you do get errors then first try Clean and then Build. Other than that it's the standard turn it off and then on again, sometimes delete project (not files!!!!!) from workspace and re-import them (hence do NOT delete contents of project on disk!!!) otherwise Google it - maybe there's a problem release?

Monday, 14 November 2011

Couldn't get connection factory client

Sometimes when setting up your Android development environment for the first time you'll get an error like: Couldn't get connection factory client

For example: Trying out the HelloGoogleMaps tutorial from http://developer.android.com/resources/tutorials/views/hello-mapview.html

Sometimes it may be due to an invalid Maps API key so check that you have done this correctly.

If you have followed all the instructions and haven't cut corners then the next thing to try is your DDMS settings.

In Eclipse go to Window > Preferences > Android > DDMS and set your ADB connection time out (ms) from the default 5000 to 10000.

This gives the notoriously slow AVD a chance to get going with the request before it times out.