Random musings on mobile software development...
Sorcery-ltd | 24 March, 2008 15:20
I spend quite a bit of time helping out people on the discussion boards. When I'm answering questions these days I try to keep this old proverb in mind:
"Give a man a fish; you have fed him for today. Teach a man to fish; and you have fed him for a lifetime."
I believe the key to success in the ever changing technology industry is not about learning an enormous amount of information but more about learning how to find the information you need. If I give someone a few lines of code that fixes their problem they paste it in and what have they learned - "if you get stuck, just ask and someone will fix it". If I can explain why something is happening or point someone to the resources they need to find out (fellow champion _wizard_hu is excellent at this) then hopefully they'll have more of an idea what to do themselves the next time.
I was one of those annoying kids who was always asking "why?", "how?", "what does that mean?". My grandmother set me on the right path by never answering my questions but showing me how to use the dictionary, encyclopedia or whatever other source I could use to find out for myself. These days we have the internet and search engines so surely there's no excuse.
However, when I looked this proverb up to check the wording I found this site with some "improvements": http://www.amatecon.com/fish.html
Here are some of my favourites (converted into some tips for getting the most out of the discussion boards):
"Give a man a fish; you have fed him for today. Teach a man to use the Net and he won't bother you for weeks."
So, before you post a question on the discussion boards - search! Search the wiki and use your favourite search engine. Double check the same question hasn't already been asked on the board you're posting on (they often have).
"Give a man a fish; you have fed him for today. Teach a man to fish, and he will sit in the boat and drink beer all day."
Just because you've learnt how to search don't spend too long surfing the amazing amount of information this has revealed to you - there's some coding to do!
"Teach a man to fish and you have fed him for a lifetime. Unless he doesn't like sushi - then you also have to teach him how to cook."
Don't be afraid to post questions though. Just because the information's out there and you can find it doesn't mean you will know how to use it. Be specific with your questions, provide as much detail as you can (even if you think it's irrelevant), what device (or emulator) and SDK are you using, what's your application trying to do and why - someone might solve your problem by pointing out a better way to acheive the result. Also, show you've made some effort - provide a link to the example or wiki page that you're using for reference - that way you're much more likely to get a fast, high quality response.
I'd like to finish by pointing out what I think is a great initiative, code snippets, that I hope Nokia expands further - making the fishing easier for everyone.
Mark
ltomuta | 24/03/2008, 19:21
One more thing to remember about the Dibo is that the fishing lessons are public and recorded. You spend the time teaching one developer but hopefully many other will read an learn from the same posts.
Sorcery-ltd | 24/03/2008, 19:43
Thanks Bogdan, glad you enjoyed it. I'd like to be able to educate and amuse at the same time... after all, learning should be fun!
I've also written this because I think it will massively improve the signal to noise ratio on the discussion boards if we have fewer fishing lessons and more cooking lessons - less about where to look ("Have you looked at this example?... Have you tried searching the Wiki, this article looks as if it might help?... Have you searched the discussion board, this post (that I've linked to 10 times before) has the answer in it... etc etc. Hopefully then what's left will be more of the "no, that won't work because..." and "you could try doing x or y, please report back and let everyone know what works". That starts a virtuous circle because people are more likely to spend time searching the DiBo if there's less noise on there!
stichbury | 24/03/2008, 20:03
Hi Mark
Thanks for posting this, and for the link to the code snippets, which are very useful. These are, to my mind, very much like the recipes you see in the traditional "cookbooks" from O'Reilly, which have always been useful once a certain level of knowledge about the basics of cookery (how to work with an active object, how to create a UI project) have been acquired.
Symbian Press has a cookbook coming soon (http://www.amazon.co.uk/Quick-Recipes-Symbian-Mastering-Development/dp/0470997834/ref=sr_1_5?ie=UTF8&s=books&qid=1206381430&sr=1-5) which again uses code snippets and a traditional formula to teach Symbian skills. I hope you don't mind me promoting it here!
Jo (Symbian Press)
Sorcery-ltd | 24/03/2008, 20:49
Now you've gone and made it look like a setup :-)
Fishing and cooking metaphors, then a cookbook...
Promote away! You should probably get yourself an amazon affiliate code too! :-)
Seriously I'm looking forward to this book coming out. More examples of how to do things the right way is exactly what we need more of for Symbian.
prats123 | 31/03/2008, 22:59
Hello sir,
I am the student of Information Technology Engg. Branch presently in
8th semester and doing my Major project "Compression and Decompression
in Mobile Phones". I have implemented LZW algorithm on mobile phone
.Problem what I am facing is to select the File to be compressed by
our project ie im building a file explorer , code is building and
running in emulators but not working in mobile .
It is just listing the roots but not listing the file and directories .
Please help me out and give me the right direction so that i can give
the path of the file implicitly. I am also sending u the code which i
had implemented
Regards,
Prateek
import java.util.*;
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.file.*;
import javax.microedition.midlet.*;
public class MobileXplorer3 extends MIDlet implements CommandListener
{
// For our file system, this will be our root
private final static String ROOT = "/";
private String str1;
private String str;
// Definitions for directories
private final static String DIRECTORY_INDICATOR = "/";
private final static String UP_DIRECTORY_INDICATOR = "..";
// Holds the full path to the current directory. Point to the root at
// app startup
private String fullPath = ROOT;
// Our main display object.
// List of files/directories in the current directory
List lstDirectory = null;
// Icons for directory, file, and move-up-one directory
Image imgDirectory = null, imgFile = null, imgUpDirectory = null;
private Command cmExit; // Exit app
private Command cmSelect; // View file properties
private Command cmRead; // View file contents
private Command cmWrite; //Writing of viewed file
private Command cmBack; // Exit textbox showing file contents
/*--------------------------------------------------
* It all starts here. Check for FileConnection API
* get images, create commands and allocate List
*-------------------------------------------------*/
public MobileXplorer3()
{
if (System.getProperty("microedition.io.file.FileConnection.version")
== null)
{
System.out.println("FileConnection API not available");
destroyApp(false);
notifyDestroyed();
}
else
{
// Store references to our images for files and directories
try
{
imgFile = Image.createImage("/file.png");
imgDirectory = Image.createImage("/directory.png");
imgUpDirectory = Image.createImage("/up_directory.png");
System.out.println("Images is Readed");
}
catch(IOException e)
{ }
}
// Allocate the List that will hold directory contents
lstDirectory = new List(fullPath, List.IMPLICIT);
// Add commands and listen for events
cmExit = new Command("Exit", Command.EXIT, 1);
cmSelect = new Command("Select", Command.ITEM, 1);
cmRead = new Command("Read", Command.ITEM, 2);
cmBack = new Command("Back", Command.BACK, 1);
cmWrite = new Command("Write", Command.ITEM, 3);
lstDirectory.addCommand(cmExit);
lstDirectory.addCommand(cmSelect);
lstDirectory.addCommand(cmRead);
lstDirectory.setCommandListener(this);
// Default command when selecting an entry in the List
lstDirectory.setSelectCommand(cmSelect);
}
/*--------------------------------------------------
* Get list of roots and display the List object
*-------------------------------------------------*/
public void startApp()
{
getRootDirectories();
Display d= Display.getDisplay(this);
//SplashScreenTest st = new SplashScreenTest(this,d);
}
public void startMain()
{
// Create a list of root directories
getRootDirectories();
System.out.println("startApp is started");
// The List is our main displayable
Display.getDisplay(this).setCurrent(lstDirectory);
}
public void pauseApp()
{
}
public void destroyApp(boolean cond)
{
notifyDestroyed();
}
/*--------------------------------------------------
* Create a list of the valid root directories
*-------------------------------------------------*/
private void getRootDirectories()
{
// Get roots
Enumeration enum = FileSystemRegistry.listRoots();
System.out.println("Root directories ");
// Clear out the existing List contents
lstDirectory.deleteAll();
// Store entries in vector
while(enum.hasMoreElements())
{
String root = (String) enum.nextElement();
System.out.println(root);
lstDirectory.append(root, imgDirectory);
}
}
/*--------------------------------------------------
* Build list of files in the specified directory
*-------------------------------------------------*/
private void buildFileList(String dir)
{
String fname;
Enumeration enum;
FileConnection fc = null;
try
{
// Open connection to the specified directory
fc = (FileConnection) Connector.open("file://" + dir);
// Enumerate the list of returned files/directories
enum = fc.list("*", true);
// Clear out the existing List contents
lstDirectory.deleteAll();
// Show image that represents going up one directory level
lstDirectory.append("..", imgUpDirectory);
// Loop through all entries, building a List
while(enum.hasMoreElements())
{
fname = (String) enum.nextElement();
// Open connection
fc = (FileConnection) Connector.open("file://" + dir + "/" + fname);
// Append the name, along with an indicator to the List,
// specifying if the entry is a file or directory
lstDirectory.append(fname, fc.isDirectory() ? imgDirectory : imgFile);
}
fc.close();
}
catch (Exception e)
{ }
}
/*--------------------------------------------------
* Directory selected, change to the directory
*-------------------------------------------------*/
void changeToDirectory(String dirname)
{
// Selected ".." directory, move up the tree
if (dirname.equals(UP_DIRECTORY_INDICATOR))
{
// Locate the next to last separator so we can remove the path
char separator = fullPath.charAt(0);
int x = fullPath.lastIndexOf(separator, (fullPath.length() - 2));
// Remove the last path entry, as we are moving up the tree
fullPath = fullPath.substring(0, x + 1);
}
else // Drilling down the directory tree
{
// Update variable that holds the full directory path
fullPath += dirname;
}
// We worked our way up the tree back to the root,
// build list of roots
if (fullPath.length() == 1)
getRootDirectories();
else
// Build a list of files/dir given the new path
buildFileList(fullPath);
// Show the new List
Display.getDisplay(this).setCurrent(lstDirectory);
}
/*--------------------------------------------------
* File selected, show its properties
*-------------------------------------------------*/
void displayFileProperties(String fullPath, String filename)
{
try
{
FileConnection fc = (FileConnection) Connector.open(fullPath);
// Build an alert to show file properties
Alert fileinfo = new Alert(filename,
"Last Modified " + new Date(fc.lastModified()) + "\n" +
"Write access: " + (fc.canWrite() ? "yes" : "no") + "\n" +
"Read access: " + (fc.canRead() ? "yes" : "no") + "\n" +
"File size: " + fc.fileSize(),
null, AlertType.INFO);
// Wait for user acknowledgement
fileinfo.setTimeout(Alert.FOREVER);
// Show the alert
Display.getDisplay(this).setCurrent(fileinfo);
fc.close();
}
catch (IOException ioe)
{ }
}
/*--------------------------------------------------
* File selected, show its contents
* We assume the selected file contains pure text
*-------------------------------------------------*/
String displayFileContents(String fullPath, String filename)
{
// Textbox to hold the file contents, set it to read-only
TextBox tbx = new TextBox(filename, null, 2048,
TextField.UNEDITABLE | TextField.ANY);
// Create a byte array to hold file contents
byte[] b = new byte[2048];
// Connection and input stream
FileConnection fc = null;
InputStream is = null;
try
{
// Open file and stream
fc = (FileConnection) Connector.open(fullPath);
is = fc.openInputStream();
System.out.println(fullPath);
// Read no more than 2048 bytes
int len = is.read(b, 0, 2048);
// Here's how we get back from the file viewer textbox
tbx.addCommand(cmBack);
tbx.addCommand(cmWrite);
tbx.setCommandListener(this);
// Set textbox contents based on file read results...
if (len > 0)
{
// Place contents into the textbox
tbx.setString(new String(b, 0, len));
}
else
tbx.setString("Unable to read file!");
// Display the textbox and the file contents
Display.getDisplay(this).setCurrent(tbx);
str1 = tbx.getString();
is.close();
fc.close();
}
catch(Exception e)
{ }
return(str1);
}
/*--------------------------------------------------
* File selected for writing
* We assume the selected file contains pure text
*-------------------------------------------------*/
public void writing(String str1, String str)
{
System.out.println("Writing of data to be done");
System.out.println("Name of the File-"+" "+str1);
System.out.println("DATA TO BE WRITTEN-"+" "+str);
// Create a byte array to hold file contents
byte[] b = new byte[2048];
FileConnection fc = null;
OutputStream is = null;
System.out.println("Connection to be Establish");
try
{
// Open file and stream
fc = (FileConnection)
Connector.open("file:///root1/Compress/sample.txt",Connector.READ_WRITE);
System.out.println("Full path is - "+fullPath);
if (!fc.exists())
{
fc.create();
}
System.out.println("Connection is established");
OutputStream out = fc.openOutputStream();
String s="Dar ke aagaye JEEt hai ";
byte [] buf=s.getBytes();
byte [] buf1=str.getBytes();
out.write(buf);
out.write(buf1);
PrintStream output = new PrintStream(out);
output.println("this is a test");
System.out.println("WRITING has been Completed");
out.close();
fc.close();
}
catch(Exception e)
{ }
}
/*--------------------------------------------------
* Manage commands
*-------------------------------------------------*/
public void commandAction(Command c, Displayable s)
{
if (c == cmExit)
{
destroyApp(false);
notifyDestroyed();
}
else if (c == cmBack)
{
// Selected from the textbox showing a files contents,
// go back to our main list of files/directories
Display.getDisplay(this).setCurrent(lstDirectory);
}
else
{
// Get a reference to the selected List entry
String str = lstDirectory.getString(lstDirectory.getSelectedIndex());
// Select command...
if (c == cmSelect)
{
// Depending on whether a file or directory was selected...
// Valid directories are "/" or ".."
if(str.endsWith(DIRECTORY_INDICATOR) ||
str.equals(UP_DIRECTORY_INDICATOR))
changeToDirectory(str);
else
{
// Pass in the full path (including the selected file name)
// as well as the filename itself
displayFileProperties("file://" + fullPath + str, str);
}
}
else // Read file contents...
{
System.out.println("read file...");
displayFileContents("file://" + fullPath + str, str);
}
}
}
}
Sorcery-ltd | 01/04/2008, 00:54
Hi,
This isn't the right place for this question. Personally I've never used JSR-75. Please use the appropriate Java discussion board.
Mark
nigel.brown | 11/04/2008, 16:20
Give a man a match, and he'll be warm for a minute, but set him on fire, and he'll be warm for the rest of his life.
Mobile and embedded software developer. Loves technology and loves to help people.
RDF Facets:
qfnZtopicQUqfnBlogTopicZgeneralQ
qfnZtypeQUqfnTypeZBlogContentQ
qfnZtypeQUqfnTypeZBlogE45ntryQ
qfnZtypeQUqfnTypeZCommunityContentQ
qfnZtypeQUqfnTypeZWebpageQ
qmarsZlanguageQUxhttpE3aE2fE2fswE2enokiaE2ecomE2flanguageE2d1E2fenX
Re: Fishing for information
bogdan.galiceanu | 24/03/2008, 18:38
That was one of the funniest and definitely one of the most educational posts on FN Blogs.
All those fishing tips apply to our Discussion Boards. I'd like to add one of my own -not as good as those you've mentioned, but still-:
"Give a man a fish; you have fed him for today. Teach a man to fish and he might bleed the lake dry."
If you only answer small questions, you're basically doing someone else's work for them, a little bit at a time. If you teach them how to solve their problems on their own, they will grow beyond expectations (in most cases).
So, in DiBo terms, if you answer small questions for someone they'll keep asking for help again and again, but if you teach them the art of problem solving, they, in turn, will help others and become motivated to learn more.