Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Reply
Highlighted
Contributor
Posts: 31
Registered: ‎11-14-2012
My Device: Blackberry 9780
My Carrier: Digicel

Connection Factory and general network optimizations

Hi, I have some questions I hope you all can shed some light on.. I've been testing an app we're developing and I've seen very weird behaviours on EDGE...

  • Is it bad practice to only have ONE connection factory? I have a class that makes all my http connections and so on. For the life of the app I only have one connection factory, should I only have one factory per request?
  • Is the connection factory fine with managing multiple, simultaneous connections?
  • Is there any limit to the number of http connections we can do simultaneously in app?
  • I notice sometimes the connection factory will just not return a connection even when I exit the app and come back in. I opened another app and the network worked then I re-open my app and the net works? Is there any explanation why this would happen?
  • What exactly is connectionTimeout and timeLimit and are setting these necessary to optimize network connetions?
Developer
Posts: 19,636
Registered: ‎07-14-2008
My Device: Not Specified

Re: Connection Factory and general network optimizations

Hard Questions.

 

I don't use ConnectionFactory, so this is just my opinion based on my understanding of what it does.

 

As it is not Thread safe and is blocking, you should only have 1 Thread using an instance at a time.  If you have multiple Threads potentially attempting connections at the same time, then you really need multiple ConnectionFactory instances.

 

While there is no real limit to the number of connections, I would suggest that a large number is likely to just cause contention.  There have been a number of discussions regarding what is the optimal number of active connections, and I think the consensus is around 3.  But I also think you can tune this based on the connection method in use (e.g. more for WiFi) and the OS level (I think networking code improved significantly in OS 6.0).  And it will also depend on what you are doing.  For example, I wouldn't attempt more than 1 large image download at once, but I suspect multiple small file downloads are ok run together. 

 

connectionTimeout and timelimit are important, but their implementation is not complete.  I would try to use them, but as I understand it, whether they work (specifically connectionTimeout) depends on the connection method. 

 

Have a look at this Thread for more:

http://supportforums.blackberry.com/t5/Java-Development/Consistent-HTTP-Timeout-setting/m-p/1973759

 

Regarding your point about ConnectionFactory not giving you a connection at times, that is very difficult to resolve using this information.  I suspect there is a timing issue here. 

 

Try improving your code based on these thoughts and see if this problem can be reproduced. 

Contributor
Posts: 31
Registered: ‎11-14-2012
My Device: Blackberry 9780
My Carrier: Digicel

Re: Connection Factory and general network optimizations

[ Edited ]

Thanks for the suggestions... I've tried to put in some optimizations.. I really need to get rid of this bug... because the app just stops getting descriptors from the Factory after some time... I'll try to describe what I'm doing below...

 

I have two arrays that I maintain... available and order... the ordering I toy with based what was last used and initial preference. Every 20s I check what's available and cleanse and refill the available array. 

See below..

private int[] transportOrder = { TransportInfo.TRANSPORT_TCP_WIFI, TransportInfo.TRANSPORT_BIS_B, TransportInfo.TRANSPORT_TCP_CELLULAR, TransportInfo.TRANSPORT_WAP2, TransportInfo.TRANSPORT_MDS };

// Holds all available connection methods
private int[] transportsAvailable = {};

 

private void configureAvailableTransports(){
Utils.log("Network: Configuring transports");
String transportList = "";
synchronized (transportsAvailable) {
transportsAvailable = new int [0];
for (int a = 0; a < transportOrder.length; a++) {
int transport = transportOrder[a];
if (DeviceInfo.isSimulator() || (TransportInfo.isTransportTypeAvailable(transport) || TransportInfo.hasSufficientCoverage(transport))) {
String msg = "";
switch (transport) {
case TransportInfo.TRANSPORT_TCP_WIFI:
msg = "WIFI";
transportList += " " + msg;
break;

case TransportInfo.TRANSPORT_BIS_B:
msg = "BIS";
transportList += " " + msg;
break;

case TransportInfo.TRANSPORT_WAP2:
msg = "WAP2";
transportList += " " + msg;
break;

case TransportInfo.TRANSPORT_TCP_CELLULAR:
msg = "TCP";
transportList += " " + msg;
break;

case TransportInfo.TRANSPORT_MDS:
msg = "MDS";
transportList += " " + msg;
break;
}
Arrays.add(transportsAvailable, transport);
}
}
}
Utils.log("Network: Transports available with coverage: " + transportList);
}

 

So then in order to get the connection factory, I just set the preferred conn types to the available list..

public ConnectionFactory getConnectionFactory() {
ConnectionFactory factory = new ConnectionFactory();
factory.setPreferredTransportTypes(transportsAvailable);
return factory;
}

 

After every successful load given the response time is below 5s (just toying with that for now.. I call preferTransport..

// Prefer the transport given certain metrics...
if(status == 200 && getResponseTime < 5000){
// prefer this transport...
preferTransport(transportType);
}

 

The prefer transport, moves the currently transport to the top of the list...

protected void preferTransport(int transportType){

synchronized (transportOrder) {
int numTransports = transportOrder.length;
if(numTransports > 0){
int firstTransport = transportOrder[0];
if(firstTransport == transportType){
// nothing to do
Utils.log("Network: No reordering necessary. " + TransportInfo.getTransportTypeName(transportType) + " is first");
return;
} else {
int [] newTransports = new int [numTransports];
int index = 1;
Utils.log("Network: Reordering transports: #1 " + TransportInfo.getTransportTypeName(transportType));
newTransports[0] = transportType;
for(int i = 0; i < numTransports; i++){
int oldTransportType = transportOrder[i];
if(oldTransportType != transportType){
Utils.log("Network: Reordering transports: #" + (index+1) + " " + TransportInfo.getTransportTypeName(oldTransportType));
newTransports[index] = oldTransportType;
index++;
}
}
// Replace the transport order array..
this.transportOrder = newTransports;
}
}
}
}

 

I always check canConnect before attempting connections... that code below

public boolean canConnect() {
// Set ConnectionFactory options
if (transportsAvailable.length > 0) {
for (int i = 0; i < transportOrder.length; i++) {
int transportType = transportOrder[i];
if (TransportInfo.isTransportTypeAvailable(transportType) && TransportInfo.hasSufficientCoverage(transportType)) {
return true;
}
}
}
return false;
}

 

The fetch code basically starts like this...

ConnectionDescriptor connectionDescriptor = getConnectionDescriptor(url);

HttpConnection httpConnection = (HttpConnection) connectionDescriptor.getConnection();

if (usePost) { // set POST if we're using it
httpConnection.setRequestMethod(HttpProtocolConstants.HTTP_METHOD_POST);
}

// Configure the headers
httpConnection.setRequestProperty(HttpProtocolConstants.HEADER_USER_AGENT, "Blackberry Device");
httpConnection.setRequestProperty("x-rim-transcode-content", "none");

// Set headers if GZIP is enabled...
if (useCompression) {
httpConnection.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_TYPE, HttpProtocolConstants.CONTENT_TYPE_APPLICATION_X_WWW_FORM_URLENCODED);
httpConnection.setRequestProperty(HttpProtocolConstants.HEADER_ACCEPT_ENCODING, "gzip");
}

int status = httpConnection.getResponseCode();

 

For reference.. my getConnectionDescriptor method is here...

private ConnectionDescriptor getConnectionDescriptor(String url) {
if(connectionDescriptors.get(url)!= null){
ConnectionDescriptor descriptor = (ConnectionDescriptor) connectionDescriptors.get(url);
// remove it...
connectionDescriptors.remove(url);
// check if descriptor is still available
int transportType = descriptor.getTransportDescriptor().getTransportType();
if(TransportInfo.hasSufficientCoverage(transportType)){
return descriptor;
}
}
ConnectionFactory factory = getConnectionFactory();
return factory.getConnection(url);
}