[GUIDE] Debugging apps - Java for Android App Development

Debugging apps
This is my multi-post guide on debugging apps.
Android provides its own ways of debugging:
Logcat
The most important aspect when we talk about debugging. Whenever your app crashes, you can find the reason for that in the logs (as long as you install it from your IDE).
However, we can also use it for other ways of debugging. It can help to understand how the app acts and why it does so.
Toasts
Toasts are these small pop-ups you can see in many apps. You can use them for debugging as well.
Debugger in Eclipse or Android Studio
Eclipse and Android Studio have their own debuggers. You can execute the source code step by step and see all variable values during that.
AVDs
If a user reports that the layout does not look great on his device, you can check it using an AVD, often refered to as an emulator. It can help to understand how the app will look on other devices.
Using Google and posting on XDA
Google can help you very much with your problem. If you still cannot figure out what the reasons for your problem are, you can profit by the XDA community power. However, we need some information in order to help you.
This was featured on the XDA portal on June 29, 2013.

Logcat
As I have already stated, logcats are the most important aspect of debugging on Android.
You can use them to get error messages when your app crashed or to print your own debugging information.
Understand error messages
This is one example of an error message you can get:
Code:
06-15 12:45:02.205 805-805/? E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{de.nikwen.myapplication/de.nikwen.myapplication.MainActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
at android.app.ActivityThread.access$600(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5041)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at de.nikwen.myapplication.MainActivity.doSomething(MainActivity.java:21)
at de.nikwen.myapplication.MainActivity.onCreate(MainActivity.java:17)
at android.app.Activity.performCreate(Activity.java:5104)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
... 11 more
The code producing the error:
Code:
package de.nikwen.myapplication;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Button;
public class MainActivity extends Activity {
Button myButton;
@[B][/B]Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
doSomething();
}
private void doSomething() {
myButton.setText("Crashing here");
}
}
Now we are going to analyse the error.
The second line is the most important one. It tells you which kind of error ocurred. In this case it is a NullPointerException (NPE).
Code:
java.lang.RuntimeException: Unable to start activity ComponentInfo{de.nikwen.myapplication/de.nikwen.myapplication.MainActivity}: java.lang.[COLOR="Red"]NullPointerException[/COLOR]
The first thing to do now is searching for this type of error. When does it occur?
You come up with something like this:
Thrown when an application attempts to use null in a case where an object is required. These include:
Calling the instance method of a null object.
Click to expand...
Click to collapse
(Source: http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/NullPointerException.html)
Now you know what kind of Exception was thrown. You can get a lot of other useful information from the logcat:
Usually, you get some more information about the error. There should be an explanation why the Exception was thrown:
Code:
java.lang.RuntimeException: [COLOR="Red"]Unable to start activity[/COLOR] ComponentInfo{de.nikwen.myapplication/de.nikwen.myapplication.MainActivity}: java.lang.NullPointerException
It also prints the stacktrace. The stacktrace contains all methods which have been invoked, the last one on the top.
In this case one exception caused another one. In most cases, the one which caused the other one is the one which is interesting for you.
Code:
Caused by: java.lang.NullPointerException
In this case the one which was thrown first is a NPE as well.
Let us have a closer look at the stacktrace:
Code:
[COLOR="Red"]at de.nikwen.myapplication.MainActivity.doSomething(MainActivity.java:21)
at de.nikwen.myapplication.MainActivity.onCreate(MainActivity.java:17)[/COLOR]
at android.app.Activity.performCreate(Activity.java:5104)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
The ones which are important for you usually are the ones with your package name (the red ones).
At the end of the line it tells you in which file and in which line the error occured.
Code:
at de.nikwen.myapplication.MainActivity.onCreate[COLOR="Red"](MainActivity.java:17)[/COLOR]
Here it is just the part of the code where the other method is called. So we look at the other one. (This most often happens when there are two of your methods. For that reason have a look at the upper one first.)
Code:
at de.nikwen.myapplication.MainActivity.doSomething[COLOR="Red"](MainActivity.java:21)[/COLOR]
It tells us MainActivity.java, line 21.
That is the line:
Code:
myButton.setText("Crashing here");
Remember, we got a NullPointerException. The only variable that can get null in that line is myButton. In fact we initialise it nowhere.
So this is our new onCreate method:
Code:
@[B][/B]Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myButton = (Button) findViewById(R.id.my_button);
doSomething();
}
We solved the error. :victory:

Logcat - part II
Your own debug messages
We can also output our own debugging information that way:
Code:
Log.d("myTag", "myMessage");
or
Code:
Log.e("myTag", "myErrorMessage");
Error messages (produced with Log.e) are shown in red.
The tag can be used for filtering.
It can help us to check specific values when it does not return the right output:
Code:
Log.d("start", "hey");
String[] myStringArray = new String[] {"Hello world", "Debugging is fun (normally not ;))", "XDA is great!!!"};
String all = "Words: ";
for (String s: myStringArray) {
Log.d("String s", s);
all = all + s + ", ";
Log.d("new all", all);
}
Log.d("status", "done");
The output:
Code:
06-15 13:15:03.014 1347-1347/de.nikwen.myapplication D/start: hey
06-15 13:15:03.014 1347-1347/de.nikwen.myapplication D/String s: Hello world
06-15 13:15:03.014 1347-1347/de.nikwen.myapplication D/new all: Words: Hello world,
06-15 13:15:03.014 1347-1347/de.nikwen.myapplication D/String s: Debugging is fun (normally not ;))
06-15 13:15:03.014 1347-1347/de.nikwen.myapplication D/new all: Words: Hello world, Debugging is fun (normally not ;)),
06-15 13:15:03.014 1347-1347/de.nikwen.myapplication D/String s: XDA is great!!!
06-15 13:15:03.014 1347-1347/de.nikwen.myapplication D/new all: Words: Hello world, Debugging is fun (normally not ;)), XDA is great!!!,
06-15 13:15:03.014 1347-1347/de.nikwen.myapplication D/status: done
You can also use the log if one of your methods does not finish:
Code:
for (int i = 0; i < 20; i--) {
//do something
Log.d("i", String.valueOf(i));
}
Log.d("status", "1");
myButton.setText("New text");
Log.d("status", "2");
Log.d("status", "done");
You can figure out the reason for logical errors by printing the required information to the logs.
If there are Exceptions you want to handle but you still want the error standard Java error message discussed in the previous post, use the printStackTrace() method of the class Exception:
Code:
try {
Thread.sleep(5000);
} catch(Exception e) {
e.printStackTrace();
//do something here
}

Toasts
Toasts are these little windows you can see in many apps.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
(Source: http://developer.android.com/images/toast.png)
You can also use them for debugging. You can output your values using Toasts instead of logcat messages.
Using Toasts for debugging is a great option, if you want to actually see the values when you test on a real device with no computer around, e.g. on the train.
It is also helpful if you want a customer to test your app. Using toasts, you can show him that something went wrong.
Do it that way:
Code:
Toast.makeText(getApplicationContext(), "My message", Toast.LENGTH_LONG).show();
(Do not forget the .show()!)
If you invoke this in an Activity, you can also do this:
Code:
Toast.makeText(this, "My message", Toast.LENGTH_LONG).show();
The disadvantage is that they are just shown for a short period of time.

Debugger in Eclipse
The debugger of Eclipse is a very productive tool. It allows you to see the values of the variables in real time. Additionally, you will be able to see and control exactly what your app is doing while it is running.
If we want to start our app in debug mode, we have to run it using the debug button.
To set or delete breakpoints we can right-click on the space left to the source code and select "Toggle Breakpoint". You will notice a blue dot next to the line. When the app is running, it will stop executing the code at the position of the breakpoint. The line with the breakpoint will not be executed.
When you run the app now, it will show a dialog which says that it is waiting for the debugger to attach.
You will also see a pop-up asking you to launch the debug perspective. Hit "Yes".
The code of your app will be executed, but it will stop before executing the line with your breakpoint. The current line which is not executed yet will be marked green.
Now you can decide what should be done next. The proper controls can be found in the debug perspective we opened before.
The one on the left will run the code until the next breakpoint will be reached. This will be the next thing we see if we define another breakpoint and press the "Resume" button:
The red button will disconnect the debugger. If you do this, your app will go on running as if no debugger had ever been attached.
Let us talk about the other buttons. The left one will make your program execute the current line and if it is a method, it will step into this method and you will be able to debug the other method step by step, too. It is called "Step into". The debugger will not be able to step into methods which are not defined by you or any library you added to your project.
If you want the debugger to execute the next line but (if the line is a method) not to step into the method, use the second button called "Step over". It will directly go to the next line.
If you are in a method and want to step out of it, use the third button. That means that it will leave the current method. Note that it will still run all code of the current method. Its name is "Step return".
In the picture above the buttons would cause this:
The "Step into" button will continue with the first line of the doSomething() method.
The "Step over" button will run the doSomething() and pause afterwards.
The "Step return" method will run the onCreate() method until its end and will pause then.
Now let us see how we can get the value of variables.
All variables used in the current method will be shown in the debugger view.
If there is an array, you can view its childs by clicking on the arrow next to it.
You can also view the fields of an object by clicking on the arrow.
If you hover of a variable in the code view, you will see its value, too.
I think that now you see why I call the debugger a productive tool.
And if I had shown you everything you can do with it, it would have been to long to post it on XDA. The ones I showed you are just the basic functions of the debugger.

Debugger in Android Studio
The debugger of Android Studio is a very powerful tool which allows you to see the values of the variables while your app is running on the emulator or a real device. Additionally, you will be able to see and control exactly what it is doing in real time.
In order to debug an app we need to start it using the debug button.
Then we can define or delete breakpoints by clicking on the space left to the source code. A red dot will appear there. When running the app, it will stop executing the code at the position of the breakpoint. The line with the breakpoint will not be executed.
When you run the app now, it will show a dialog which says that it is waiting for the debugger to attach.
The debug view will be opened automatically.
The code of your app will be executed, but it will stop before executing the line with your breakpoint. The current line which is not executed yet will be marked blue.
Now you can control how your app should continue. The proper controls can be found in the debug view.
The one on the left will run the code until the next brekpoint will be reached. It is called "Resume program execution". The other four buttons are for smaller steps. This will be the next thing we see if we define another breakpoint and press the "Resume program execution" button:
Let us talk about the other four buttons. The left one will make your program execute the current line and go to the next line. It is called "Step over". If you do this, it will not step into other methods and debug them.
If you want the debugger to step into the method, use the second button called "Step into". The debugger will not be able to step into methods which are not defined by you or any library you added to your project.
If you are in a method and want to step out of it, use the fourth button. That means that it will leave the current method. Note that it will still run all code of the current method. Its name is "Step out" (Surprise :laugh.
In the picture above the buttons would cause this:
The "Step over" button will run the doSomething() and pause afterwards.
The "Step into" button will continue with the first line of the doSomething() method.
The "Step out" method will run the onCreate() method until its end and will pause then.
Now we talk about getting variable values.
All variables available in the current method will be shown in the debugger view.
If there is an array, you can view its childs by clicking on the plus next to it.
You can also view the fields of an object by clicking on the plus.
To see a certain value you can also hover above the variable in your code.
After that you see that the debugger is a very powerful tool.
And this is just the beginning. You can do even more complex actions with it.

AVDs
I guess that nearly every developer for Android knows them and uses them: AVDs or emulators
They are great for testing your apps on other screen sizes or platform versions.
Before releasing your app, test them on different screen sizes and (most important) on different versions of Android. Some methods are just available on new API versions and crash on old versions. Another thing to mention: If your layout is designed for large screens, it might look bad on small ones. In the same manner phone layout often look ugly on a tablet.
Creating AVDs: Official documentation
ROOTING an AVD: Guide by Androguide.fr

Using Google
Google or any other search engine is great help when you debug your app. Nearly every error which occurs for you has already been experienced by others.
If you want to find out why your app crashes, search for this:
Android <the name of the Exception> <the method which causes the Exception>
Click to expand...
Click to collapse
If it is no Android specific Exception (e.g. a NumberFormatException when using Integer.parseInt("27")), replace "Android" by "Java".
If no method which is written by you is causing the crash, use keywords like these:
Android <the name of the Exception> <the name of the superclass> <when the crash occurs>
Click to expand...
Click to collapse
Example for these could be:
Android TextView setText CalledFromWrongThreadException
Android IllegalStateException Fragment orientation change
Java NumberFormatException Integer.parseInt
Click to expand...
Click to collapse
Often it is the best way to search for the message you find in the logs, e.g.
java.lang.RuntimeException: Unable to start activity ComponentInfo{}:
android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment:
make sure class name exists, is public, and has an empty constructor that is public
Click to expand...
Click to collapse

Posting on XDA
This should be your last option. Try everything you can before posting here. Though posting your problem on XDA is nothing you should be ashamed of.
However, please follow these steps to ensure that we are able to help you properly:
Give us your code.
Do not worry. You do not have to publish all of your code but the relevant parts. That means the class which causes the Exception. If you can exclude some methods to be the reason for the Exception, you do not need to post them. But do this only if you are sure that they are not important for us.
Post a logcat.
As you can see in post #2, logcats are the most important information on the bug and the reasons why it crashes.
Describe the problem.
Tell us when the code crashes. That might be that it crashes when you change the screen orientation, press the menu or back key or when a particular method is invoked. Many of us do not execute your code but just look at it in the browser. Hence we need to know when the code crashes.
Liked this tutorial?
Check out my interactive tutorial on how to use the command line.

very very useful thanks

matt95 said:
very very useful thanks
Click to expand...
Click to collapse
You are welcome.
I am glad that you like it.
Btw, I will update it soon.

Updated the guide:
Post #8
Post #9

This is very helpful! When I was reading this in my book it was a little confusing but now I get it.

FlyLikeAGS3 said:
This is very helpful! When I was reading this in my book it was a little confusing but now I get it.
Click to expand...
Click to collapse
Great. :good:

Posted the guide for the debugger of Android Studio.
Post #6

Added the Eclipse debugging tutorial.
Now I am done.
Post #5

I vote for another sticky by Nikwen!

Zatta said:
I vote for another sticky by Nikwen!
Click to expand...
Click to collapse
Thanks.
If it is a sticky, people will see it. If not, nobody will see it due to the number of new posts every day.
(@mark manning)

I'll look at it later on when I get a sec

Great guide!

Related

MessageBox.Show() fails to show !?!?

Hello,
I write a WindowsMobile C# application (details below).
I added a try...catch statement, wrapping the Main Form, trying to show a message to my users to report of any issues. something like...
Code:
try {
Application.Run(new MainViewForm());
}
catch (Exception e) {
String msg = "Failed to execute properly :(\n" +
"Please report error to [email protected]\n" +
"I'll do my best to fix this!";
MessageBox.Show(msg, "Application Error");
}
Sadly, The exception is being called, but the dialog is not showed (a quick flickering appears and disappears.
I even tried to show another Form with my error but same thing happens.
I was wondering
1. how can I handle an error message that would succeed?
2. is there a BKM to handle app crash reporting?
I'd really appreciate help on this.
Thanks
My ReliRescue app for free at http://www.logelog.com/utils
- I'm using HTC Blackstone reflashed with Miri_WM65_21885_V33.0_Premium

Getting serious about root: FIOASYNC bug

Presently we're running a little short on kernel exploits, with the following being the only one that looks remotely plausible:
http://xorl.wordpress.com/2010/01/14/cve-2009-4141-linux-kernel-fasync-locked-file-use-after-free/
Big hold-up? For all that we have a trigger, we don't have an exploit. I believe it's up to us at this point to make that happen.
If I'm reading it right, it looks like the bug initially rears its head right here:
Code:
void __kill_fasync(struct fasync_struct *fa, int sig, int band)
{
while (fa) {
struct fown_struct * fown;
if (fa->magic != FASYNC_MAGIC) {
printk(KERN_ERR "kill_fasync: bad magic number in "
"fasync_struct!\n");
return;
}
[B]fown = &fa->fa_file->f_owner;[/B]
/* Don't send SIGURG to processes which have not set a
queued signum: SIGURG has its own default signalling
mechanism. */
if (!(sig == SIGURG && fown->signum == 0))
send_sigio(fown, fa->fa_fd, band);
fa = fa->fa_next;
}
}
... as fa_file now points to invalid memory (having been free'd earlier). The f_owner member gets shot out to send_sigio, which look like this:
Code:
void send_sigio(struct fown_struct *fown, int fd, int band)
{
struct task_struct *p;
enum pid_type type;
struct pid *pid;
int group = 1;
read_lock(&fown->lock);
type = fown->pid_type;
if (type == PIDTYPE_MAX) {
group = 0;
type = PIDTYPE_PID;
}
[B]pid = fown->pid;[/B]
if (!pid)
goto out_unlock_fown;
read_lock(&tasklist_lock);
do_each_pid_task(pid, type, p) {
send_sigio_to_task(p, fown, fd, band, group);
} while_each_pid_task(pid, type, p);
read_unlock(&tasklist_lock);
out_unlock_fown:
read_unlock(&fown->lock);
}
... in which we see the f_owner member being dereferenced. Also it gets pushed through several other functions which may be exploitable.
There are several questions to be answered before we can start attacking this:
Can we resolve the address of the fa_file data structure so we can overwrite the f_owner value?
Can we do anything with it once we've done that? (Presumably we can set it to zero to cause a null-pointer dereference, but we're mmap_min_addr = 32768 on the most recent versions, so unless we can flag the mmap region to grow down and apply memory pressure to reach page 0 this will do us no good.)
Failing the plan above: are any of the functions that f_owner gets pushed into vulnerable? I evaluated this over the weekend, but without the help of a trained kernel dev I'm not going to get very far.
While I studied a lot of this in uni, I'll admit I'm green when it comes to actually writing these exploits. I'm hoping that this will get the creative juices flowing, and perhaps provide a more comprehensive resource in case any hard-core kernel hackers want to take a look at what we're doing or give us pointers (harhar) in the right direction.
Thanks, guys. Great work up to this point.
In the original POC if you change /bin/true to /system/bin/sh you can get a new shell to open just not as root. So I'm guessing that their needs to be more added to the POC to make it a full exploit.
Right, the fork()'s in the PoC exist only to cause the file descriptor's fasync_struct to be erroneously killed, not start a root session. The root session would need to be started (presumably) by the kernel doing something to our maliciously crafted fown_struct.
The tough part is figuring out exactly where and what that fown_struct needs to be.
Well I definetly agree with you that this seems to be our best best bet I am some what of a newbie when it comes to linux allthough i am learning as i go. Do you know of any good sites to read up on kernel hacking?
Sorry Guys just got the word that this one is dead for us.....
Here is the explantion i got.
some_person said:
Nope, the bug didn't exist in 2.6.27. That's why they say >= 2.6.28 are vulnerable.
As far as how the bug works, there are 2 other issues. 1) our kernel probably wasn't compiled with AT_RANDOM 2) we don't have an elf executable.
The exploit you found does not give us root access, it crashes the system. Basically, you open the "random number generator" file, lock it, and close it... but the lock release when you close it. Then you have to call an elf executable because that generates a random number (running an elf executable) provided the kernel was compiled AT_RANDOM. you continue to call that executable (and generating random numbers) until the the lock is released on the "random number generator" file... then it's your program's turn... the kernel tries to send your program notification that the file is available, but your program has moved on. BLAM the kernel stops (or "oops").
Click to expand...
Click to collapse
Sorry to dredge up an old thread:
This exploit *will* work. According to Zanfur, the hole is in our kernel. We need to use it without AT_RANDOM (which I dont know how to do).
http://sourceware.org/ml/libc-alpha/2008-10/msg00016.html
I am pretty sure we do have elf executables, here is proof:
% file m6
m6: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
If our kernel is susceptible to this bug then it should work, as long as there is a way to do it without at random.
Though I do not in any way represent my self as a hacker or developer I was wondering if I could throw in my 2 cents. I notice that this bug/exploit won't work because it requires AT RANDOM. I was wondering if it s possible to write code that does what the function does and insert it in. Is root required to do this (i.e. insert code into the kernel that wasn't there before) or is this a matter of know-how? Just some brainstorming I thought that I would throw in.
jballz0682 said:
Though I do not in any way represent my self as a hacker or developer I was wondering if I could throw in my 2 cents. I notice that this bug/exploit won't work because it requires AT RANDOM. I was wondering if it s possible to write code that does what the function does and insert it in. Is root required to do this (i.e. insert code into the kernel that wasn't there before) or is this a matter of know-how? Just some brainstorming I thought that I would throw in.
Click to expand...
Click to collapse
This won't get us root. Even zanfur said it. Moving on....
Framework43 said:
This won't get us root. Even zanfur said it. Moving on....
Click to expand...
Click to collapse
To clarify, even if we get AT_RANDOM functionality working, we can't use this to exploit our kernel. All we can do with this is get data from a file that was recently closed. The point of this exploit is to send a signal to a process, but there are no processes we could send a signal to that would give us root.
Our kernel seems practically invulnerable, it appears that almost all exploits are patched

[GUIDE] Android Client-Server Communication (PHP-MYSQL REST API)

Hey XDA, this is my first guide and first proper contribution to the community!
I’m writing this because I've seen many people ask a variation of the question: “How can my app get information from a database?”
This guide is intended for those who have created their first app – it is assumed you have a working development environment and are reasonable comfortable with the Android SDK and Java. I'm also assuming little to no knowledge of PHP and MYSQL
This guide walks you through:
Setting up a database and a PHP script
Testing the server
Accessing it from Android.
To make it relevant, we're going to use data that we might see in an actual app: First & Last Name, Age and Points.
Requirements:
Android Device*
Computer*
Apache/PHP/MySQL Server – I use WAMP (for Windows) (PHP v 5.4)
Postman Rest Client for Google Chrome
(*Both must be connected to the same network!)
This guide will help you setup a local server. If you want to host your script and database online, you will have to purchase paid hosting.
Let's get started!
First off, what is a RESTful service?
According to Wikipedia: A RESTful web API (also called a RESTful web service) is a web API implemented using HTTP and REST principles.
How it works:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
A breakdown of the steps:
The client makes a request using a HTTP POST to a server
The PHP script queries the MYSQL server
The PHP script gets the SQL data
The PHP script puts the data into an array and assigns keys for the values. The script then outputs the data as a JSON array. JSON (JavaScript Object Notation) is a standard for data exchange, and formats the data in a way both humans and computers can easily read.
The app parses the JSON and displays the data.
Code!
Part 1: The Server
We’re going to start by setting up the server!
Install WAMP server. Leave the settings at the default values.
Start WAMP server and let it come online.
Try and open http://localhost/phpmyadmin/ - if you installed it correctly, you should be greeted by the phpMyAdmin welcome screen. We're going to be using phpMyAdmin to create our database.
Creating the Database:
Create a database called ‘mytestdatabase’. Now click the SQL tab, paste in the following SQL Code and hit run. This will create a test table called ‘users’ and fill it with data.
The table contains 5 columns: id, FirstName, LastName, Age, Points. It has 6 rows of sample data.
SQL Code:
Code:
-- phpMyAdmin SQL Dump
-- version 3.5.1
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Jun 15, 2013 at 10:07 PM
-- Server version: 5.5.24-log
-- PHP Version: 5.3.13
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
/*!40101 SET [user=714032]@old_[/user][email protected]@CHARACTER_SET_CLIENT */;
/*!40101 SET [user=714032]@old_[/user][email protected]@CHARACTER_SET_RESULTS */;
/*!40101 SET [user=714032]@old_[/user][email protected]@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
--
-- Database: `MyTestDatabase`
--
-- --------------------------------------------------------
--
-- Table structure for table `users`
--
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`FirstName` text NOT NULL,
`LastName` text NOT NULL,
`Age` int(11) NOT NULL,
`Points` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
--
-- Dumping data for table `users`
--
INSERT INTO `users` (`id`, `FirstName`, `LastName`, `Age`, `Points`) VALUES
(1, 'John', 'Doe', 25, 61),
(2, 'Glen', 'Willis', 55, 3145),
(3, 'Helen', 'Cook', 35, 1232),
(4, 'Karen', 'Johnson', 20, 6456),
(5, 'Bill', 'Cooper', 60, 3856),
(6, 'Mary', 'Gomez', 30, 5422);
/*!40101 SET CHARACTER_SET_CLIENT [user=714032]@old_[/user]CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS [user=714032]@old_[/user]CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION [user=714032]@old_[/user]COLLATION_CONNECTION */;
Your database should now look like this:
We’re now ready to move on to the PHP!
Open up your WWW directory (C:\wamp\www) and create a new folder called ‘clientservertest’. In this folder, create a file called ‘login.php’.
Paste the following code into the file. (The PHP code is commented so you can follow what is going on)
PHP:
<?php
#Ensure that the client has provided a value for "FirstNameToSearch"
if (isset($_POST["FirstNameToSearch"]) && $_POST["FirstNameToSearch"] != ""){
#Setup variables
$firstname = $_POST["FirstNameToSearch"];
#Connect to Database
$con = mysqli_connect("localhost","root","", "mytestdatabase");
#Check connection
if (mysqli_connect_errno()) {
echo 'Database connection error: ' . mysqli_connect_error();
exit();
}
#Escape special characters to avoid SQL injection attacks
$firstname = mysqli_real_escape_string($con, $firstname);
#Query the database to get the user details.
$userdetails = mysqli_query($con, "SELECT * FROM users WHERE FirstName = '$firstname'");
#If no data was returned, check for any SQL errors
if (!$userdetails) {
echo 'Could not run query: ' . mysqli_error($con);
exit;
}
#Get the first row of the results
$row = mysqli_fetch_row($userdetails);
#Build the result array (Assign keys to the values)
$result_data = array(
'FirstName' => $row[1],
'LastName' => $row[2],
'Age' => $row[3],
'Points' => $row[4],
);
#Output the JSON data
echo json_encode($result_data);
}else{
echo "Could not complete query. Missing parameter";
}
?>
Testing the Script:
Try accessing http://localhost/clientservertest/login.php from your browser. Do you get this message:
"Could not complete query. Missing parameter"
Then it’s working! The script is looking for a POST variable called “FirstNameToSearch” – we didn't provide any, so it did't work!
To finish testing the script, open the Postman-REST client.
Set it up like so:
Request URL: http://localhost/clientservertest/login.php
Type: POST
Key: FirstNameToSearch
Value: John
Hit send, and you should see this:
Code:
{"FirstName":"John","LastName":"Doe","Age":"25","Points":"61"}
Congrats – your server just returned a result! Try some of the other names in the database (Glen, Helen, Karen, Bill, Mary) and see how their data is returned.
Note: Before we move on to the Android section, we’re going to have to put our WAMP server online. Click the WAMP icon in the taskbar and select 'Put Online'.
Find your computers local network IP address and insert it into the URL like so: http://192.168.1.112/clientservertest/login.php
You should be able to access the script. If this doesn't work, try turning off your firewall - it could be blocking the server.
Part 2: Android
We’re now going to use our Android device to access the web server instead of the Postman client.
I'm not going to go into detail with the boilerplate UI code - I've attached the source code to this post so you can download the project files and browse through them.
Note: Android 3.x+ cannot perform Network operations on the main thread. To solve this, we have to multithread our program. To keep this as simple as possible, we’re going to use an AsyncTask. Again, the code for this can be found in the project download.
Inside of the AsyncTask, we have the most important code - where we create and execute a HTTP POST in Java.
Creating and Executing a HTTP POST in Java:
We have to first setup the name-value pairs for our POST variables. In this case, we use "FirstNameToSearch" as our Key.
Code:
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("FirstNameToSearch", strNameToSearch));
The following code sets up connection timeouts (15 seconds) and creates a HttpClient and HttpPost pointing to our url (http://192.168.1.112/clientservertest/login.php)
Code:
//Create the HTTP request
HttpParams httpParameters = new BasicHttpParams();
//Setup timeouts
HttpConnectionParams.setConnectionTimeout(httpParameters, 15000);
HttpConnectionParams.setSoTimeout(httpParameters, 15000);
HttpClient httpclient = new DefaultHttpClient(httpParameters);
HttpPost httppost = new HttpPost("http://192.168.1.112/clientservertest/login.php");
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
The following code executes the POST, gets the result and converts it to a string:
Code:
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
Finally, the following code creates a JSON object from the result string and extracts our data:
Code:
// Create a JSON object from the request response
JSONObject jsonObject = new JSONObject(result);
//Retrieve the data from the JSON object
strFirstName = jsonObject.getString("FirstName");
strLastName = jsonObject.getString("LastName");
intAge = jsonObject.getInt("Age");
intPoints = jsonObject.getInt("Points");
That's it. It's so simple!
Where do we take it from here?
This combination of PHP/MYSQL is quite powerful. I'd recommend that you learn more about these technologies and build upon the demo in this guide. PHP Tutorials & MySQL Tutorials
Ideas for practice apps:
Online notes application - Sync your notes to the cloud
Build an Activation Server - Users can activate an app with a key
Feedback
Please feel free to leave any followup questions, comments or suggestions! I'll try my best to respond!
You can find the source code over at GitHub. Have fun! (If you fix a bug, please send a pull request)
 
Additional Information
Changelog
November 3, 2013
Added a link to the GitHub repository.
June 26, 2013
Updated PHP Code. It's more reliable and uses the newer MySQL APIs. Thanks to @dbarrera & @vijai2011
July 7, 2013
Updated the Android project and added Internet permissions (ClientServerRESTDemo v2.zip)
Thanks for this amazing guide but I have a issue.I have my own table and columns.So I changed your php code according to that and when I do a post query in rest,I get all null.But if I do the same in phpmyadmin,I have results.
This is what I get in postman:
Code:
{"pid":null,"name":null,"UID":null,"mobile":null,"description":null,"created_at":null,"updated_at":null}
attached the output of phpmyadmin.
And my phpcode:
Code:
<?php
#Setup variables
$firstname = $_POST["FirstNameToSearch"];
#Avoid SQL injection attacks
$firstname = mysql_real_escape_string($firstname);
#Connect to Database
$con = mysql_connect("localhost","user","pass");
if (!$con)
{
die('Could not connect');
}
#Select the test database
mysql_select_db("mydb", $con);
#Get the user details from the database
$userdetails = mysql_query("SELECT * FROM mytable WHERE name = '$firstname'");
#Catch any errors
if (!$userdetails) {
echo 'It seems the server is down.Please try later';
exit;
}
#Get the first row of the results
$row = mysql_fetch_row($userdetails);
#Build the result array (Assign keys to the values)
$result_data = array(
'pid' => $row[1],
'name' => $row[2],
'UID' => $row[3],
'mobile' => $row[4],
'description' => $row[5],
'created_at' => $row[6],
'updated_at' => $row[7],
);
#Output the JSON data
echo json_encode($result_data);
?>
Thanks for help.
Edit: just found that your app is missing internet permission in manifest
Code:
<uses-permission android:name="android.permission.INTERNET" />
:thumbup:
Thanks so much for this. I will try it out soon.
Sent from my HTC Explorer A310e using xda app-developers app
vijai2011 said:
Thanks for this amazing guide but I have a issue.I have my own table and columns.So I changed your php code according to that and when I do a post query in rest,I get all null.But if I do the same in phpmyadmin,I have results.
This is what I get in postman:
Code:
{"pid":null,"name":null,"UID":null,"mobile":null,"description":null,"created_at":null,"updated_at":null}
attached the output of phpmyadmin.
Thanks for help.
Click to expand...
Click to collapse
I was able to reproduce the null result - it means that the result was not available in the database. You'll want to double check the value you are passing to the script in Postman. (When I used 'FirstNameToSearch' and 'test' - I got a correct result. However, when I used 'testa', I got a null result.)
You can try adding this into the PHP script to catch this problem:
Code:
#Get the first row of the results
$row = mysql_fetch_row($userdetails);
[B]#Check to see if a result was returned.
if(!$row){
echo 'User does not exist';
exit;
}[/B]
I also noticed a few things in your PHP script:
In your screenshot, your table name appears to be 'Myapp', however in your PHP script, it looks like you are using 'mytable'
When you build the result array at the end, you are trying to access a column that doesn't exist:
This code tries to access an 8th column/index:
Code:
'pid' => $row[1],
'name' => $row[2],
'UID' => $row[3],
'mobile' => $row[4],
'description' => $row[5],
'created_at' => $row[6],
'updated_at' => $row[7],
You only have seven columns, so it should be:
Code:
'pid' => $row[0],
'name' => $row[1],
'UID' => $row[2],
'mobile' => $row[3],
'description' => $row[4],
'created_at' => $row[5],
'updated_at' => $row[6],
vijai2011 said:
Edit: just found that your app is missing internet permission in manifest
Code:
<uses-permission android:name="android.permission.INTERNET" />
Click to expand...
Click to collapse
Good catch - Thanks! I'll update the project asap.
Alkonic said:
I was able to reproduce the null result - it means that the result was not available in the database. You'll want to double check the value you are passing to the script in Postman. (When I used 'FirstNameToSearch' and 'test' - I got a correct result. However, when I used 'testa', I got a null result.)
:snip:
Good catch - Thanks! I'll update the project asap.
Click to expand...
Click to collapse
That is not a error in table name because I just wanted to hide it out here but actually it got revealed in the screenshot .No issues will try your php code and correct my json array too.thanks
Sent from my GT-N7000 using xda app-developers app
For some reason,the problem was caused by the mysql_real_escape_string.I commented that line and it is working now.
vijai2011 said:
For some reason,the problem was caused by the mysql_real_escape_string.I commented that line and it is working now.
Click to expand...
Click to collapse
Now that's interesting.. I've never experienced a problem with that before.
I took a look at the PHP docs and found that mysql_real_escape_string() is depreciated - that could be contributing to the problem. I'll investigate this further and adjust the guide as necessary.
Thanks for sharing your solution!.
Alkonic said:
Now that's interesting.. I've never experienced a problem with that before.
I took a look at the PHP docs and found that mysql_real_escape_string() is depreciated - that could be contributing to the problem. I'll investigate this further and adjust the guide as necessary.
Thanks for sharing your solution!.
Click to expand...
Click to collapse
Maybe you are using ancient php module .BTW Can I also put data into tables using your php and slightly modifying "mysql_query" and using post?Or should I use put along with mysql_query?If later is the solution,could give me the snippet of how a put variable looks?because I dono php and I was waiting for someone to write this guide because before I was connecting to db with JDBS which isnt safe.Thanks and sorry for the trouble.
Edit: I got it to work like I said.But only issue is the created at and updated at time stamp which is not the part of php nor the app.I will correct it from mysql.Thanks once again.Will be happy to trouble you soon lol...No dont take it serious BTW
vijai2011 said:
Maybe you are using ancient php module .BTW Can I also put data into tables using your php and slightly modifying "mysql_query" and using post?Or should I use put along with mysql_query?If later is the solution,could give me the snippet of how a put variable looks?because I dono php and I was waiting for someone to write this guide because before I was connecting to db with JDBS which isnt safe.Thanks and sorry for the trouble.
Edit: I got it to work like I said.But only issue is the created at and updated at time stamp which is not the part of php nor the app.I will correct it from mysql.Thanks once again.Will be happy to trouble you soon lol...No dont take it serious BTW
Click to expand...
Click to collapse
Ha you beat me to it! I'll definitely try and add a section into the guide about updating tables. I appreciate your feedback on the guide, and I'm glad it helped you. Feel free to trouble me
Perfect! Just what i needed for my next week exam!
Sent from my GT-S5830M using Tapatalk 2
Super, thx!
But please tell me what I'm doing wrong.
Code:
HttpResponse response = httpclient.execute(httppost); //throw...​
i save errors in log (attached)
pls help ;(
objaa said:
Super, thx!
But please tell me what I'm doing wrong.
Code:
HttpResponse response = httpclient.execute(httppost); //throw...​
i save errors in log (attached)
pls help ;(
Click to expand...
Click to collapse
You are doing something on the main thread which actually has to be done in a different thread.I suspect its at line #119.If you show the entire code,somebody might point it out easily for you
Sent from my GT-N7000 using xda app-developers app
vijai2011 said:
You are doing something on the main thread which actually has to be done in a different thread.I suspect its at line #119.If you show the entire code,somebody might point it out easily for you
Sent from my GT-N7000 using xda app-developers app
Click to expand...
Click to collapse
ok, all code:
package com.nsp.obja;
import java.util.ArrayList;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;
public class MainActivity extends Activity {
@override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.myscreen);
post();
}
@override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
void post()
{
try
{
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("FirstNameToSearch", "wow"));
//Create the HTTP request
HttpParams httpParameters = new BasicHttpParams();
//Setup timeouts
HttpConnectionParams.setConnectionTimeout(httpParameters, 15000);
HttpConnectionParams.setSoTimeout(httpParameters, 15000);
HttpClient httpclient = new DefaultHttpClient(httpParameters);
HttpPost httppost = new HttpPost("http://www.xda-developers.com/");
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
Toast.makeText(this, result.length(), Toast.LENGTH_LONG).show();
}
catch(Exception e)
{
Log.e("ClientServerDemoX", "Error: ", e);
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
objaa said:
ok, all code:
<!----Snip!---->
Click to expand...
Click to collapse
Do post() in async because it has to do http request which needs to be done in another thread.
vijai2011 said:
You are doing something on the main thread which actually has to be done in a different thread.I suspect its at line #119.If you show the entire code,somebody might point it out easily for you
Sent from my GT-N7000 using xda app-developers app
Click to expand...
Click to collapse
vijai2011 said:
Do post() in async because it has to do http request which needs to be done in another thread.
Click to expand...
Click to collapse
hoooww :crying::crying:
Thanks, I figured out and got the code page of our glorious forum
I'm having an issue while testing the Query... I'm using Firefox and using RESTClient for debugging... and testing whatever value, db always responds null (See attachment)...
dbarrera said:
I'm having an issue while testing the Query... I'm using Firefox and using RESTClient for debugging... and testing whatever value, db always responds null (See attachment)...
Click to expand...
Click to collapse
Exactly what I experienced first time.Try after commenting the line which prevents mysql injection and see if it works.If you run latest mysql,the chances are probably that its the issue
vijai2011 said:
Exactly what I experienced first time.Try after commenting the line which prevents mysql injection and see if it works.If you run latest mysql,the chances are probably that its the issue
Click to expand...
Click to collapse
Already tried that... No go... Had to write the whole thing using w3schools example code as base... Just resolved a couple minutes ago and completed the project (it can be viewed @ Github:CardManager (App) and cardmanager_json (Web Service, only principal.php is the one handling the whole thing))...
Maybe a good add to the tutorial would be to have a config.php file with the user, passwd, database and table data calling it through require_once()... The DBConexion and DBGestion files (in my github) are supposed to do that, but didn't work either (hence doing the principal.php code all over again)...
dbarrera said:
Already tried that... No go... Had to write the whole thing using w3schools example code as base... Just resolved a couple minutes ago and completed the project (it can be viewed @ Github:CardManager (App) and cardmanager_json (Web Service, only principal.php is the one handling the whole thing))...
Maybe a good add to the tutorial would be to have a config.php file with the user, passwd, database and table data calling it through require_once()... The DBConexion and DBGestion files (in my github) are supposed to do that, but didn't work either (hence doing the principal.php code all over again)...
Click to expand...
Click to collapse
Interesting.. I'll take a look at at your script, revisit the W3 tutorials, and then re-write mine. It's really rudimentary and tends to fail easily. I wanted to write about the config.php, however, I also wanted to keep this guide as simple as possible for newer users. Maybe I'll add in an advanced section.
I'll update the guide in a few days, as I'm right in the middle of exams :/
Thanks for the feedback!

How to search StorageFiles

I need a way to search in StorageFiles with dynamically pattern, which comes from a TextBox. The directive "Windows.Storage.Search" doesnt exist in windows phone 8.1 runtime, as i saw. Now my question is, how can i do this in alternative way?
The only way to do it with WP 8.1 since Microsoft ALWAYS fails to implement the important things are to query using LINQ.
Ex:
Code:
var result = (await Windows.Storage.ApplicationData.Current.LocalFolder.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByName)).
Where(x => x.Name.
Contains(x => txtBox.Text));
That's about all you can do pretty much. (Thanks Microsoft).
Thank you for the example. But it wont work for me, it shows me the following error(s):
Code:
A local variable named 'x' cannot be declared in this scope because it would give a different meaning to 'x', which is already used in a 'parent or current' scope to denote something else
and
Code:
Cannot convert lambda expression to type 'string' because it is not a delegate type
Thats really odd from Microsoft, that they havent implementet the search function like in WinRT (Windows Store App).
The first error is pretty simple. You already have the variable named "x" and it would be very bad if compiler didn't give you that error.
Change the name of the variable to something else that you don't use in that scope and it will work.
And for second problem, try this one:
Code:
private List<string> Result()
{
var result = ((List<Windows.Storage.Search.CommonFileQuery>)Windows.Storage.ApplicationData.Current.LocalFolder.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByName)).Where(x => x.ToString().Contains(txtBox.Text));
return result as List<string>;
}
private async Task<List<string>> ResultAsync()
{
return await Task.Run(() => Result()).ConfigureAwait(continueOnCapturedContext: false);
}
You should call ResultAsync method and get the result in this way:
Code:
List<string> myList = ResultAsync().Result;
That's not going to work. You can't cast a StorageFile as a string.
To fix my code (simple lambda typo)
Code:
var result = (await Windows.Storage.ApplicationData.Current.LocalFolder.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByName)).
Where(x => x.Name.
Contains(txtBox.Text));
if(result.Any())
{
// Do shtuff
}
Also, you should never access the .Result of an async task because you never know if it completed yet.
Ok, first error is done, but the second error is still here
Code:
Cannot convert lambda expression to type 'string' because it is not a delegate type
You are missing the point of the TAP (Task Async Pattern).
Both main thread and async method will be in execution in the same time. When the async method finish his work, main thread will stop and catch the result trough the Result property.
TAP is the recommended way of asynchronous programming in C#. The only thing with TAP is to use ConfigureAwait method in non-console type of apps to avoid deadlock.
Sooner or later you will get the result from TAP method. Nothing will get in the conflict with the main thread.
Oh wait, @andy123456 I updated my response. I forgot String.Contains ISNT a lambda .
@Tonchi91, I know all about the TAP. I've been using it since it was CTP. I've seen the awkward situations with threading in WP .
Now... if he did
Code:
List<string> myList;
ResultAsync().ContinueWith(t=> { myList = t.Result; });
I wouldn't be worried .
Ok the errors are gone, but the debugger show me the following exception:
Code:
Value does not fall within the expected range
Is this search method case-sensitive? I tried with an exact input in the TextBox.
Hmmm. Let's see your full code.
its actually only for testing, so i added your code to a button (asnyc) and will show the output in a textBlock.
Code:
private async void buttonTest_Click(object sender, RoutedEventArgs e)
{
//Result();
var result = (await Windows.Storage.KnownFolders.CameraRoll.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByName)).
Where(x => x.Name.
Contains(textBox_test.Text));
if (result.Any())
{
// Do shtuff
textBlock_test.Text = result.ToString();
}
}
The error is coming from here
Code:
var result = (await Windows.Storage.KnownFolders.CameraRoll.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByName))
andy123456 said:
its actually only for testing, so i added your code to a button (asnyc) and will show the output in a textBlock.
Code:
private async void buttonTest_Click(object sender, RoutedEventArgs e)
{
//Result();
var result = (await Windows.Storage.KnownFolders.CameraRoll.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByName)).
Where(x => x.Name.
Contains(textBox_test.Text));
if (result.Any())
{
// Do shtuff
textBlock_test.Text = result.ToString();
}
}
The error is coming from here
Code:
var result = (await Windows.Storage.KnownFolders.CameraRoll.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByName))
Click to expand...
Click to collapse
Oh Camera Roll.. You MIGHT need to have the capability to view the camera roll enabled. I forget what it's called, but you need a specific cap in order to view from there. Also, I would try to see if you can use a generic folder instead.
I would try Windows.Storage.ApplicationData.Current.LocalFolder.GetFilesAsync() as your method after the await just to test whether you can read correctly.
Yes but in wp8.1 runtime app, there arent caps anymore. The capability for access to the pictures is simply calles pictures library and is enabled. I have tested it as you said, but it gives me the same exception.
A quick tip: another way to do this is to use the Win32 C runtime API. You can, for example, use the FindFirst/NextFile functions (http://msdn.microsoft.com/en-us/library/windows/desktop/aa364418(v=vs.85).aspx) which support searches using wildcards (* and ? characters in the first parameter). These functions are wrapped in my NativeLibraries classes, but are also just publicly available for third0party developers to call from their own C++ DLLs.
Alternatively, you can use the .NET System.IO.Directory class, which has functions like EnumerateFiles(String path, String searchPattern). This is probably the better way to do it, actually.
Of course, if you want these operations to not block the current thread, you'll need to explicitly put them in their own thread or async function.
EDIT: This also assumes you have read access to the relevant directories. You application data directory works fine, for example (you can get its path from the relevant StorageFolder object). Other directories that can be accessed via WinRT functions may go through a broker function instead of being directly readable.
The point is, that i have an array with filenames. Now i need the StorageFile files which contains these filenames. My idea was to search for these files and return the files as StorageFile, so i can work with these. Or is there a simpler / another way?
http://msicc.net/?p=4182 <-- try this
Thank you, i have already done this and its working. But how can i compare the Files to read, with already read files and take only the not yet read files?

[Tutorial] Manage System Permissions in Android Marshmallow

Hello,
I create that thread to offer you a new tutorial aiming to learn how to manage System Permissions in Android Marshmallow. You can discover the tutorial in video also :
Manage System Permissions on Android 6 Marshmallow
Beginning in Android 6 Marshmallow, users grand permissions to apps while the app is running, not when they install the app. This approach gives the user more control over the app's functionality. Thus, he can choose to give the access to read contacts but not to the device location. Furthermore, users can revoke the permissions at any time, by going to the app's Settings screen.
Note that system permissions are divided into two categories : normal and dangerous. Normal permissions are granted automatically. For dangerous permissions, the user has to give approval to your application at runtime. So, developers must manage permissions at runtime before using some dangerous features.
To manage permissions inside an application, we're going to imagine we want to read contacts. This feature will use the READ_CONTACTS permission that is marked as dangerous. So, the first step is to check for READ_CONTACTS permission. If the permission has already been granted, you can use the feature that read contacts. If not, you have to request for permissions with a custom request code that will be named MY_PERMISSIONS_REQUEST_READ_CONTACTS in our example.
Code:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[] { Manifest.permission.READ_CONTACTS },
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
} else {
readContacts();
}
Note that when your application requests for permissions, the system shows a standard dialog box to user that cannot be customized. Now, you need to handle the permissions request response by overriding the onRequestPermissionsResult method :
Code:
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS :
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
readContacts();
} else {
if(ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_CONTACTS)) {
new AlertDialog.Builder(this).
setTitle("Read Contacts permission").
setMessage("You need to grant read contacts permission to use read" +
" contacts feature. Retry and grant it !").show();
} else {
new AlertDialog.Builder(this).
setTitle("Read Contacts permission denied").
setMessage("You denied read contacts permission." +
" So, the feature will be disabled. To enable it" +
", go on settings and " +
"grant read contacts for the application").show();
}
}
break;
}
}
Like you can see, managing permissions in your Android application is not really hard.
Don't hesitate to give me your feedbacks or ideas for new tutorials.
Thanks.
Sylvain
Nice Tutorial.
Keep them coming
Black_Eyes said:
Nice Tutorial.
Keep them coming
Click to expand...
Click to collapse
Thanks
Hello,
The tutorial is now also available on my blog : http://www.ssaurel.com/blog/manage-permissions-on-android-6-marshmallow/ .
Don't hesitate to give me your advice and ideas for future tutorials.
Thanks.
Sylvain
They were intimidating at first but once you do it once, you've pretty much got the hang of it.
Jay Rock said:
They were intimidating at first but once you do it once, you've pretty much got the hang of it.
Click to expand...
Click to collapse
True. When you understand the mechanism, it becomes simple to use permissions in your Android code.
Christie37 said:
As I'm new mobile developer this tutorial helped me lot. Thanks keep going!!
Click to expand...
Click to collapse
Great . I made some other tutorials that could be interesting for you. Don't hesitate to look at them
Thanks man awsome
nice bro
@DSttr said:
nice bro
Click to expand...
Click to collapse
Thanks
@sylsau Thanks..
BTW, does this work properly on Android 5.1.1 and below?
I mean, what does this below code do for 5.1.1 and below? :
Code:
ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
Does it always return true, or is there a chance of exceptions or errors?
I'm asking this because I don't have Android Device below 5.1 to test it..
Or should I wrap it up like this:
Code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions();
}

Categories

Resources