[Q] How can I DISPLAY an array of Strings? - Java for Android App Development

I have searched all over for what feels like should be a simple thing to do, but to no success.
Like the title says, how should I go about displaying an array of strings to the android device? Just as a simple line of text, I don't care how it looks. I don't care if there are no spaces or organization I just want it displayed...

An Array should just have a toString.
When your Array is called strarr, you should do
Code:
strarr.toString();
to get the contents ready for printing.
Now, normally in Java, you would wrap this in a System.out.println call, but this is Android, and we have no simple console.
To display in a TextView txtv, I would try txtv.setText(strarr.toString());?

bassie1995 said:
An Array should just have a toString.
When your Array is called strarr, you should do
Code:
strarr.toString();
to get the contents ready for printing.
Now, normally in Java, you would wrap this in a System.out.println call, but this is Android, and we have no simple console.
To display in a TextView txtv, I would try txtv.setText(strarr.toString());?
Click to expand...
Click to collapse
Just so you know, this will give you [element1, element2, element3] in your string. If you want to make it so it prints it all out on a line without that stuff (or with something else, like just spaces instead of commas or newlines) you can loop through the array:
Code:
arrayDisplay = (TextView) findViewById(R.id.txtView1);
String out = "";
for(int i=0; i<strArray.length; i++) {
out += strArray[i] + " "; //adds a space after each element
}
arrayDisplay.setText(out);
In the for loop, you could also do this:
Code:
out += strArray[i] + "\n";
if you want to put them each on newlines (not sure how textView handles that though, I could be wrong. might wanna cross-reference me on that).

import antigravity said:
Just so you know, this will give you [element1, element2, element3] in your string. If you want to make it so it prints it all out on a line without that stuff (or with something else, like just spaces instead of commas or newlines) you can loop through the array:
Code:
arrayDisplay = (TextView) findViewById(R.id.txtView1);
String out = "";
for(int i=0; i<strArray.length; i++) {
out += strArray[i] + " "; //adds a space after each element
}
arrayDisplay.setText(out);
In the for loop, you could also do this:
Code:
out += strArray[i] + "\n";
if you want to put them each on newlines (not sure how textView handles that though, I could be wrong. might wanna cross-reference me on that).
Click to expand...
Click to collapse
Your method is right but there are several conditions for the toString() function. Let us consider int[] a = new int[5];
1. System.out.println(a.toString()). [Output would be the memory location of the object]
2. System.out.println(Arrays.toString(a)) [Output would be [0, 0, 0, 0, 0]]
Also, for the second option you will need to import java.util.Arrays or java.util.*;

import antigravity said:
Just so you know, this will give you [element1, element2, element3] in your string. If you want to make it so it prints it all out on a line without that stuff (or with something else, like just spaces instead of commas or newlines) you can loop through the array:
Code:
arrayDisplay = (TextView) findViewById(R.id.txtView1);
String out = "";
for(int i=0; i<strArray.length; i++) {
out += strArray[i] + " "; //adds a space after each element
}
arrayDisplay.setText(out);
In the for loop, you could also do this:
Code:
out += strArray[i] + "\n";
if you want to put them each on newlines (not sure how textView handles that though, I could be wrong. might wanna cross-reference me on that).
Click to expand...
Click to collapse
I know, but that's a bit more advanced. It seemed like a good idea to keep it basic .
abcdjdj said:
Your method is right but there are several conditions for the toString() function. Let us consider int[] a = new int[5];
1. System.out.println(a.toString()). [Output would be the memory location of the object]
2. System.out.println(Arrays.toString(a)) [Output would be [0, 0, 0, 0, 0]]
Also, for the second option you will need to import java.util.Arrays or java.util.*;
Click to expand...
Click to collapse
See above, I think we're getting into detail more than necessary .
Sent from my GT-I9300 using Tapatalk 4 Beta

Related

Why is Sample Notepad app inserting blank lines?

In Googles sample Notepad app (the final version using NotepadV3Solution), if you select Add Note (launching the NoteEdit activity), then just hit the back button, a blank line is then inserted into the Notepad activity, and it cannot be deleted. Does anyone know why? Below is the java code for this activity...
package com.android.demo.notepad3;
import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class NoteEdit extends Activity {
private EditText mTitleText;
private EditText mBodyText;
private Long mRowId;
private NotesDbAdapter mDbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDbHelper = new NotesDbAdapter(this);
mDbHelper.open();
setContentView(R.layout.note_edit);
mTitleText = (EditText) findViewById(R.id.title);
mBodyText = (EditText) findViewById(R.id.body);
Button confirmButton = (Button) findViewById(R.id.confirm);
mRowId = savedInstanceState != null ? savedInstanceState.getLong(NotesDbAdapter.KEY_ROWID)
: null;
if (mRowId == null) {
Bundle extras = getIntent().getExtras();
mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID)
: null;
}
populateFields();
confirmButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
setResult(RESULT_OK);
finish();
}
});
}
private void populateFields() {
if (mRowId != null) {
Cursor note = mDbHelper.fetchNote(mRowId);
startManagingCursor(note);
mTitleText.setText(note.getString(
note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE)));
mBodyText.setText(note.getString(
note.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY)));
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putLong(NotesDbAdapter.KEY_ROWID, mRowId);
}
@Override
protected void onPause() {
super.onPause();
saveState();
}
@Override
protected void onResume() {
super.onResume();
populateFields();
}
private void saveState() {
String title = mTitleText.getText().toString();
String body = mBodyText.getText().toString();
if (mRowId == null) {
long id = mDbHelper.createNote(title, body);
if (id > 0) {
mRowId = id;
}
} else {
mDbHelper.updateNote(mRowId, title, body);
}
}
}
When you hit the back button the onpause function is called which calls savestate. In savestate it doesn't check to see it fields title and body are blank. So it writes a record with blank or null values.
________________________________
http://ron-droid.blogspot.com
I'm still trying to figure all this java out. Any chance you could tell me specifically what I need to add to fix it?
greydarrah said:
I'm still trying to figure all this java out. Any chance you could tell me specifically what I need to add to fix it?
Click to expand...
Click to collapse
Modify the saveState() function to check to see if the body or titles are empty.
You can do something like:
Code:
if (title.isEmpty() || body.isEmpty())
return;
Which will make the save state not needlessly update or add to the db if a field is blank. This disallows you to add blank notes though (ie. notes with only a title, no body). Though I'm OK with that. But the save-state is where you want to start, because that's what's happening.
And for the love of Christ please wrap your code in code tags (select the code, hit the # sign in the top menu bar).
I'd do something like this;
private void saveState() {
String title = mTitleText.getText().toString();
String body = mBodyText.getText().toString();
If (title == null || title == "") return;
________________________________
http://ron-droid.blogspot.com
rigman said:
I'd do something like this;
private void saveState() {
String title = mTitleText.getText().toString();
String body = mBodyText.getText().toString();
If (title == null || title == "") return;
________________________________
http://ron-droid.blogspot.com
Click to expand...
Click to collapse
I'm sorry for being such an idiot, but when I put:
If (title == null || title == "") return;
in saveState, I get red mark right after the closing paren (just before return. If I hold my cursor over the red mark, it says syntax error, insert ";" to complete statement. Any idea why Eclipse doesn't like this?
Edit...A little more to the story:
The first error I got was this...
The method fi(boolean) is undefined fo rthe type NoteEdit
Quick fix: create method If(boolean)
So I did the quick fix. Now I'm thinking that I should add a ";" at the end if the if statement and put the return; in the new If(boolean) mentod. It would look like this:
Code:
private void saveState() {
String title = mTitleText.getText().toString();
String body = mBodyText.getText().toString();
If (title == null || title == "");
if (mRowId == null) {
long id = mDbHelper.createNote(title, body);
if (id > 0) {
mRowId = id;
}
} else {
mDbHelper.updateNote(mRowId, title, body);
}
}
private void If(boolean b) {
// TODO Auto-generated method stub
return;
}
Is that correct, or am I totally retarded?
Well, I'm not sure what's going on in the code above, but it doesn't work...still inserts blank lines. I wish I knew more about what I'm doing.
If anyone can help me figure this out, I'm ONLY concerned with the note title (if it equals "", don't save the blank line). I don't care if the body has text in it or not.
greydarrah said:
Well, I'm not sure what's going on in the code above, but it doesn't work...still inserts blank lines. I wish I knew more about what I'm doing.
If anyone can help me figure this out, I'm ONLY concerned with the note title (if it equals "", don't save the blank line). I don't care if the body has text in it or not.
Click to expand...
Click to collapse
I'm sorry, I thought isEmpty() was a standard function of the String library in Java.
Aside from that, can I ask what your issue is with my solution?
If you don't want to check to see if the body is empty, don't. If you are only concerned with whether or not the title is empty, use Java's built in string functionality. So in your saveState function, put this after:
Code:
String title = mTitleText.getText().toString();
String body = mBodyText.getText().toString();
if (title.length() == 0) // if string length is 0
{
return;
}
What this will do, is if the title is empty (ie. == "") it will return from the saveState function, without updating or adding the note to the database. You CANNOT use the "==" operator, as that will run a comparison of the objects (to see if they're the same string instance), ie.:
Code:
String a = "hi";
String b = "hi";
if (a == b); // false
if (a.equals(b)); // true ([I]this calls the comparison operator on the strings, which is built into the String class[/I])
if (a == a); // true (they're the same object)
If you're checking to see if a string is empty, you can do:
Code:
if (a.equals("")) ... // checks if it's the equivalent of the empty string
OR
if (a.length() == 0) ... // Checks if size of string is 0
Either will work. Hopefully that clears it up for you, you can check if the String is empty, or you can see if it equals the empty string.
It sounds like you're new to programming in general, is this the case? Or are you just new to Android? If you are more accustomed to another language I can possibly (probably) give you better analogies from there...unless it's some weird language .
Syndacate said:
I'm sorry, I thought isEmpty() was a standard function of the String library in Java.
Aside from that, can I ask what your issue is with my solution?
If you don't want to check to see if the body is empty, don't. If you are only concerned with whether or not the title is empty, use Java's built in string functionality. So in your saveState function, put this after:
Code:
String title = mTitleText.getText().toString();
String body = mBodyText.getText().toString();
if (title.length() == 0) // if string length is 0
{
return;
}
Click to expand...
Click to collapse
Thanks so much. This worked perfectly. As to my programming, I'm a long time VB programmer (since VB 3), but brand new to java. In these early stages, I'm having issues getting my mind wrapped around it, but I'll get there.
I'm thankful to everyone that responded to this thread. This is how a forum should work.
greydarrah said:
As to my programming, I'm a long time VB programmer (since VB 3), but brand new to java.
Click to expand...
Click to collapse
That explains your syntax error problems above. Unlike VB, Java is case-sensitive, and you used an upper-case "If" instead of the correct lower-case "if". The compiler did not recognize this as a keyword and assumed you wanted to use a method called "If(boolean)" but forgot to define it.
So, change all capital letters in all keywords to lower case, and remove the auto-generated "If(boolean)" method again.
Cheers
tadzio
greydarrah said:
Thanks so much. This worked perfectly. As to my programming, I'm a long time VB programmer (since VB 3), but brand new to java. In these early stages, I'm having issues getting my mind wrapped around it, but I'll get there.
I'm thankful to everyone that responded to this thread. This is how a forum should work.
Click to expand...
Click to collapse
Ah, I see. Haven't used VB in forever, barely remember it, haha. Glad it works for you, though.

[Q] Making selected spinner items into array references

Hello, i'm making an app, and i need for the app to populate a list view, i've got this to work, the listview is populated by arrays in the values resources folder. the name for this array is defined by the selected items of two spinners combined with a "_" in the middle. How do i set this custom array ID?
here is my current main activity code: (i've used a existing array id to test that it works "tener_future")
Code:
package org.townsend.spanish.donate;
import android.app.Activity;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Spinner;
public class Main extends Activity implements OnClickListener {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
View conjugateButton = findViewById(R.id.conjugate_button);
conjugateButton.setOnClickListener(this);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void verbAndTense() {
Resources res = getResources();
String[] listItems = res.getStringArray(R.array.tener_conditional);
Spinner verbs = (Spinner) findViewById(R.id.verbs);
Spinner verb_tenses = (Spinner) findViewById(R.id.verb_tenses);
ListView conjugated = (ListView) findViewById(R.id.ListView01);
conjugated.setAdapter(new ArrayAdapter(this,
android.R.layout.simple_list_item_1, listItems));;
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.conjugate_button:
verbAndTense();
break;
}
}
}
If I understand your question correctly, you are trying to get a reference to an Id stored in the R class, but which reference you need changes at runtime?
If that is the case, I think you may want to program a custom utility/method that can return the correct R reference for you. R is just a static generated class of ints, so it cannot evaluate something like R.id.dynamicterm1_dynamicterm2 where dynamicterm1 and dynamicterm2 change at runtime.
One way to do this might be a static util class like this:
Code:
package org.townsend.spanish.donate.util;
import org.townsend.spanish.donate.R;
public class ReferenceFinder
{
public static int find(String prefixName, String suffixName)
{
int returnValue = -1; // -1 indicates an error
if ( prefixName.equals("verb") && suffixName.equals("tense") )
{
returnValue = R.id.verb_tense;
}
else if( prefixName.equals("adj") && suffixName.equals("tense") )
{
returnValue = R.id.adjective_tense;
}
return returnValue;
}
Then you would call it like so:
Code:
Resources res = getResources();
int resourceID = ReferenceFinder.find("verb", "tense") ;
String[] listItems = res.getStringArray( resourceID );
I'm sure there are other ways to do this, but this is the first that came to mind. Hope that helps
would that mean that in the resource finder class that i'd have to define every possible outcome? because i'll have hundreds of outcomes once i have loaded the full list's and their outcome array's
and i think you have understood me correctly, basically it's and app (for spanish) where in one spinner you input a verb, in another you input a tense, and when you press a button it fills a list view with the 6 conjugations.
also it seems like in the second snippet of code i would have to actually set the "verb" and "tense" or could i put something dynamic like
Code:
verbs.getSelectedItem() + "_" + verb_tenses.getSelectedItem
Thanks for the help
hmm.... you might be able to do it via reflection actually, so that you wouldnt have to define each one.
I'm not 100% sure what the code would be but it would probably looks something like this:
Code:
String className= "com.example.myapp.R.id";
Class cl = Class.forName( className );
String fieldName = verbs.getSelectedItem() + "_" + tenses.getSelectedItem();
Field f = cl.getDeclaredField ( fieldName );
//since field is static, the "object" is ignored
int resourceID = f.getInt ( new Object() );
ok thanks i'm trying to get it to fit in, and i believe i have:
Code:
@SuppressWarnings({ "unchecked", "rawtypes" })
private void verbAndTense() {
Spinner verbs = (Spinner) findViewById(R.id.verbs);
Spinner verb_tenses = (Spinner) findViewById(R.id.verb_tenses);
verb_tenses.getSelectedItem();
String className= "org.townsend.spanish.donate.R.array";
Class cl = Class.forName( className );
String fieldName = verbs.getSelectedItem() + "_" + verb_tenses.getSelectedItem();
Field f = cl.getDeclaredField ( fieldName );
//since field is static, the "object" is ignored
int resourceID = f.getInt ( new Object() );
String[] listItems = f.getStringArray( resourceID );
ListView conjugated = (ListView) findViewById(R.id.ListView01);
conjugated.setAdapter(new ArrayAdapter(this,
android.R.layout.simple_list_item_1, listItems));
}
where it says :
Code:
String[] listItems = f.getStringArray( resourceID );
is it correct to put the "f" in there? and second is asks to define "Field" what should i import it as? or do i need to declare it in another format?
should be something like
String[] listItems = getResources.getStringArray( resourceID );
resourceID is an int just like R.id.something_something
i changed getResources to res, since it was defined as:
Code:
Resources res = getResources();
however my problem with "Field" in the line:
Code:
Field f = cl.getDeclaredField ( fieldName );
still exists, it says "Field cannot be resolved to a type" and gives me a load of options including imports, making a new class, interface, enum or adding a parameter. what should i do? I've tried several of the imports but then other segments suchs as:
Code:
cl.getDeclaredField ( fieldName );
become errored.
Thank you for all your guys' help so far
If you're using the Field class and don't IMPORT it, well, that's a problem
You're best friend --> http://developer.android.com/reference/java/lang/reflect/Field.html
thank you yes my porblem was i was unsure which to import it as, although i was more confident about it being that one (i had about 8 options from eclipse)
previous code however has now given me errors, :
Code:
Class cl = [U]Class.forName( className )[/U];
this section saying : "Unhandled exception type ClassNotFoundException"
Code:
Field f = [U]cl.getDeclaredField ( fieldName )[/U];
this with: "Unhandled exception type NoSuchFieldException"
and
Code:
int resourceID = [U]f.getInt ( new Object() )[/U];
with: "Unhandled exception type IllegalAccessException"
I looked through the field resource page and the last one where it says this error occurs when the field is not accesible....:/
I then checked the Class resources page and the first one said that type ClassNotFoundException is thrown when requested class cannot be found, and i thought i had declarred it in the previous
Code:
String className= "org.townsend.spanish.donate.R.array";
I know that in the example you provided me you put R.id, howeve this is a value array so it should be array right?
and the second says its thrown when the field cannot be found.
Im guessing that means that the first one is affecting the rest? how could i correct this,
if you wish to see the entire void it is here
Code:
@SuppressWarnings({ "rawtypes", "unchecked" })
private void verbAndTense() {
Spinner verbs = (Spinner) findViewById(R.id.verbs);
Spinner verb_tenses = (Spinner) findViewById(R.id.verb_tenses);
verb_tenses.getSelectedItem();
String className= "org.townsend.spanish.donate.R.array";
Class cl = Class.forName( className );
String fieldName = verbs.getSelectedItem() + "_" + verb_tenses.getSelectedItem();
Field f = cl.getDeclaredField ( fieldName );
//since field is static, the "object" is ignored
Resources res = getResources();
int resourceID = f.getInt ( new Object() );
String[] listItems = res.getStringArray( resourceID );
ListView conjugated = (ListView) findViewById(R.id.ListView01);
conjugated.setAdapter(new ArrayAdapter(this,
android.R.layout.simple_list_item_1, listItems));
}
Thank you
Yes, sorry it should be R.array or whatever
As for the "unhandled exceptions", if you use eclipse, just do the "recommended fix" and it will add a try/catch for you.
You may have to define some fields outside the try catch block and move some stuff around a bit after eclipse adds the try/catch.
Also, just as an aside, you may want to read a tutorial or two on reflection in Java so what I am saying doesnt sound as new/strange. Not required but it always helps to know a bit of reflection I think

Sending and Receiving MMS in Android

How to Send and Receive MMS in Android:
This is a guide I am creating to help all of you out there making messaging apps like sliding messaging, hopefully it will help someone at least get started in the right direction! This guide will not be a guide on how to read MMS messages, which is actually very simple. Here is a tutorial on that which will get you started: How to read MMS data in Android (The first answer is a lifesaver, it will get you where you need to go). Now onto sending and receiving!
First off, I want to say that all of this may seem very daunting, especially to a first time, independent Android app developer like I was when this started out, trying to manange time between this and college studies! A messaging app can be extremely difficult to write since there is no supported API to it at all and you have to go through lines and lines trying to decipher stock source code. Stick to it and you can definitely get there eventually I do feel that Google should add this type of thing into their API and document it though, so as to make it easier for us 3rd party developers without a giant team behind us! Come on Google!
Here's the steps in the order that I went through:
1) You need to import a lot of internal android classes, which can all be found here: GrepCode
Here are all of the files you will need to grab (there may be more, but I was able to in the end modify all of these files so that they don't depend on others such as taking out unnecessary lines of code, etc)
Code:
android.annotation.SdkConstant.java
android.database.sqlite.SqliteWrapper.java
android.net.ConnectivityManager.java
android.net.DhcpInfoInternal.java
android.net.IConnectivityManager.java
android.net.INetworkPolicyListener.java
android.net.InetworkPolicyManager.java
android.net.LinkAddress.java
android.net.LinkCapabilities.java
android.net.LinkProperties.java
android.net.NetworkIdentity.java
android.net.NetworkPolicy.java
android.net.NetworkPolicyManager.java
android.net.NetowkrQuotaInfo.java
android.net.NetowrkState.java
android.net.NetworkTemplate.java
android.net.NetworkUtils.java
android.net.ProxyProperties.java
android.net.RouteInfo.java
android.provider.Downloads.java
android.provider.Telephony.java
com.android.internal.annotations.VisibleForTesting.java
com.android.internal.net.LegacyVpnInfo.java
com.android.internal.net.VpnConfig.java
com.android.internal.net.VpnProfile.java
com.android.internal.telephony.EncodeException.java
com.android.internal.telephony.GsmAlphabet.java
com.android.internal.telephony.IccUtils.java
com.android.internal.telephony.SmsConstants.java
com.android.internal.telephony.TelephonyProperties.java
com.android.internal.util.ArrayUtils.java
com.android.internal.util.Objects.java
com.android.internal.util.Preconditions.java
com.android.mms.MmsConfig.java
com.android.mms.transaction.AbstractRetryScheme.java
com.android.mms.transaction.DefaultRetryScheme.java
com.android.mms.transaction.HttpUtils.java
com.android.mms.transaction.MmsSystemEventReceiver.java
com.android.mms.transaction.NotificationTransaction.java
com.android.mms.transaction.Observable.java
com.android.mms.transaction.Observer.java
com.android.mms.transaction.ProgressCalbackEntity.java
com.android.mms.transaction.PushReceiver.java
com.android.mms.transaction.ReadRecTransaction.java
com.android.mms.transaction.RetrieveTransaction.java
com.android.mms.transaction.RetryScheduler.java
com.android.mms.transaction.SendTransaction.java
com.android.mms.transaction.Transaction.java
com.android.mms.transaction.TransactionBundle.java
com.android.mms.transaction.TransactionService.java
com.android.mms.transaction.TransactionSettings.java
com.android.mms.transaction.TransactionState.java
com.android.mms.util.DownloadManager.java
com.android.mms.util.RateController.java
com.android.mms.util.SendingprogressTokenManager.java
com.google.android.collect.Sets.java
com.google.android.mms.ContentType.java
com.google.android.mms.InvalidHeaderValueException.java
com.google.android.mms.MmsException.java
com.google.android.mms.pdu.AcknowledgeInd.java
com.google.android.mms.pdu.Base64.java
com.google.android.mms.pdu.CharacterSets.java
com.google.android.mms.pdu.DeliveryInd.java
com.google.android.mms.pdu.EncodedStringValue.java
com.google.android.mms.pdu.GenericPdu.java
com.google.android.mms.pdu.MultimediaMessagePdu.java
com.google.android.mms.pdu.NotifictionInd.java
com.google.android.mms.pdu.NotifyRespInd.java
com.google.android.mms.pdu.PduBody.java
com.google.android.mms.pdu.PduComposer.java
com.google.android.mms.pdu.PduContentTypes.java
com.google.android.mms.pdu.PduHeaders.java
com.google.android.mms.pdu.PduParser.java
com.google.android.mms.pdu.PduPart.java
com.google.android.mms.pdu.PduPersister.java
com.google.android.mms.pdu.QuotedPrintable.java
com.google.android.mms.pdu.ReadOrigInd.java
com.google.android.mms.pdu.RetrieveConfjava
com.google.android.mms.pdu.SendConf.java
com.google.android.mms.pdu.SendRequ.java
com.google.android.mms.util.AbstractCache.java
com.google.android.mms.util.DownloadDrmHelper.java
com.google.android.mms.util.DrmConvertSession.jav
com.google.android.mms.util.PduCache.java
com.google.android.mms.util.PduCacheEntry.java
com.google.android.mms.util.SqliteWrapper.java
Whew, that was a ton of typing, hopefully its worth it! Haha. May be some typos in there too, but I'm sure you will be able to find the right one.
I know that's a lot, but I found it to be the easiest way of doing things. I'm not actually sure that all of these are required, and I may have missed a couple or added a couple extras, but you get the picture at least and thats most of them. You'll probably only end up using about 10% of those files, but since they all have others imported, I chose to import them all instead of the possibility of messing something up that was necessary. Like I said, its a lot, but almost all of them are really small so they won't increase the size of your app by more then half a megabyte at max (not sure on an exact number) so that's not really something to worry about. If you can make it by this daunting task, you should be good to go for the rest of the tutorial.
2) You need an MMS Part class that will be used to store MMS data you are going to be sending. Here is what mine looks like:
Code:
public class MMSPart {
public String Name = "";
public String MimeType = "";
public byte[] Data;
}
Just copy and paste this class.
Very straightforward as to what this will do for you, it is the actual file that we will be sending through out http connection. MimeType is the type of object that the part is, for example image/png or text/plain are the 2 that I use.
3) Next up, we need a class that will assist us in finding the system APNs. Here is mine:
Code:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.Telephony;
import android.text.TextUtils;
import android.widget.Toast;
public class APNHelper {
public APNHelper(final Context context) {
this.context = context;
}
@SuppressWarnings("unchecked")
public List<APN> getMMSApns() {
final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"), null, null, null, null);
if ( apnCursor == null ) {
return Collections.EMPTY_LIST;
} else {
final List<APN> results = new ArrayList<APN>();
if ( apnCursor.moveToFirst() ) {
do {
final String type = apnCursor.getString(apnCursor.getColumnIndex(Telephony.Carriers.TYPE));
if ( !TextUtils.isEmpty(type) && ( type.equalsIgnoreCase("*") || type.equalsIgnoreCase("mms") ) ) {
final String mmsc = apnCursor.getString(apnCursor.getColumnIndex(Telephony.Carriers.MMSC));
final String mmsProxy = apnCursor.getString(apnCursor.getColumnIndex(Telephony.Carriers.MMSPROXY));
final String port = apnCursor.getString(apnCursor.getColumnIndex(Telephony.Carriers.MMSPORT));
final APN apn = new APN();
apn.MMSCenterUrl = mmsc;
apn.MMSProxy = mmsProxy;
apn.MMSPort = port;
results.add(apn);
Toast.makeText(context, mmsc + " " + mmsProxy + " " + port, Toast.LENGTH_LONG).show();
}
} while ( apnCursor.moveToNext() );
}
apnCursor.close();
return results;
}
}
private Context context;
}
Also, you will need an APN class, here is what that one looks like:
Code:
public class APN {
public String MMSCenterUrl = "";
public String MMSPort = "";
public String MMSProxy = "";
public APN(String MMSCenterUrl, String MMSPort, String MMSProxy)
{
this.MMSCenterUrl = MMSCenterUrl;
this.MMSPort = MMSPort;
this.MMSProxy = MMSProxy;
}
public APN()
{
}
}
Just copy and paste these classes.
The problem with this is that in Android 4.0 and up, Google blocks 3rd party access to APNs (though from trial and error I believe that you can access them on some touchwiz roms/phones, but not all). To get around this, in Sliding Messaging I had to have users input this information manually, so if you have users who will be on an API higher than 14 (ICS), you will need to have this option or it WILL ABSOLUTELY NOT work. At all. A little further down I'll show you how to implement so that you can try and find APNs, and if it fails then you can set them manually.
4) You need to include these permissions in the app for things to work and not get FCs because of lack of permissions:
Code:
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
Just put them in the AndroidManifest with the rest. If you can't figure this step out maybe its time to start with something a little easier
As for the last one, write apn settings, I know for a fact you will not be able to compile your app through eclipse if you include it and you are working with Android 4.0+. It can only be applied to system apps only for API 14 and up and I don't know if you can include it without error if you are only targeting Gingerbread or not. More then likely you will have to take it out if you are not compiling your app as a system app by building it with the rest of the android source.
Please Note: I'm not actually sure that the internet permission is necessary, but the stock google app has it so I decided to include it.
5) Ok, now we have all of our classes we will use and it is time to send an MMS message. I will just copy the 2 functions that I use to do this directly below, and then explain them after that. Here they are:
Code:
public void sendMMS(final String recipient, final MMSPart[] parts)
{
ConnectivityManager mConnMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
final int result = mConnMgr.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableMMS");
if (result != 0)
{
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION))
{
return;
}
@SuppressWarnings("deprecation")
NetworkInfo mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if ((mNetworkInfo == null) || (mNetworkInfo.getType() != ConnectivityManager.TYPE_MOBILE_MMS))
{
return;
}
if (!mNetworkInfo.isConnected())
{
return;
} else
{
sendData(recipient, parts);
unregisterReceiver(this);
}
}
};
registerReceiver(receiver, filter);
} else
{
sendData(recipient, parts);
}
}
This function is fairly simple. All it does is tell the sytem that we are going to start using a mobile connection and it should connect using the term "enableMMS" so that we start the right type of connection. The variable result is set to the type of connection already active when we call this, and we are looking for it to be set to 0, meaning that our apns are already active. If this is the case, you can just skip right ahead to sending the MMS message. More than likely though, apns will not be active when you start the call, so you need to listen for a change in the connectivity through a broadcast receiver. That is what is going on inside the block of code where (result != 0). Once the receiver gets the correct type of connection, it calls the below function of sendData and unregisters itself so we don't leak receivers.
When the message is ready to be sent:
Code:
public void sendData(final String recipient, final MMSPart[] parts)
{
final Context context = this;
new Thread(new Runnable() {
@Override
public void run() {
final SendReq sendRequest = new SendReq();
final EncodedStringValue[] phoneNumber = EncodedStringValue.extract(recipient);
if (phoneNumber != null && phoneNumber.length > 0)
{
sendRequest.addTo(phoneNumber);
}
final PduBody pduBody = new PduBody();
if (parts != null)
{
for (MMSPart part : parts)
{
if (part != null)
{
try
{
final PduPart partPdu = new PduPart();
partPdu.setName(part.Name.getBytes());
partPdu.setContentType(part.MimeType.getBytes());
partPdu.setData(part.Data);
pduBody.addPart(partPdu);
} catch (Exception e)
{
}
}
}
}
sendRequest.setBody(pduBody);
final PduComposer composer = new PduComposer(context, sendRequest);
final byte[] bytesToSend = composer.make();
List<APN> apns = new ArrayList<APN>();
try
{
APNHelper helper = new APNHelper(context);
apns = helper.getMMSApns();
} catch (Exception e)
{
APN apn = new APN(sharedPrefs.getString("mmsc_url", ""), sharedPrefs.getString("mms_port", ""), sharedPrefs.getString("mms_proxy", ""));
apns.add(apn);
}
try {
HttpUtils.httpConnection(context, 4444L, apns.get(0).MMSCenterUrl, bytesToSend, HttpUtils.HTTP_POST_METHOD, !TextUtils.isEmpty(apns.get(0).MMSProxy), apns.get(0).MMSProxy, Integer.parseInt(apns.get(0).MMSPort));
ConnectivityManager mConnMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
mConnMgr.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE_MMS, "enableMMS");
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Cursor query = context.getContentResolver().query(Uri.parse("content://mms"), new String[] {"_id"}, null, null, "date desc");
query.moveToFirst();
String id = query.getString(query.getColumnIndex("_id"));
query.close();
ContentValues values = new ContentValues();
values.put("msg_box", 2);
String where = "_id" + " = '" + id + "'";
context.getContentResolver().update(Uri.parse("content://mms"), values, where, null);
context.unregisterReceiver(this);
}
};
registerReceiver(receiver, filter);
} catch (Exception e) {
Cursor query = context.getContentResolver().query(Uri.parse("content://mms"), new String[] {"_id"}, null, null, "date desc");
query.moveToFirst();
String id = query.getString(query.getColumnIndex("_id"));
query.close();
ContentValues values = new ContentValues();
values.put("msg_box", 5);
String where = "_id" + " = '" + id + "'";
context.getContentResolver().update(Uri.parse("content://mms"), values, where, null);
((Activity) context).getWindow().getDecorView().findViewById(android.R.id.content).post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "MMS Error", Toast.LENGTH_SHORT).show();
}
});
}
}
}).start();
}
This function is where all the magic happens. First, we need to create a new thread to run on because you can't access an HTTP connection on the UI thread (I ran into this error the first time around since I had never worked with data connections before). Once that thread is running, we create a new SendReq object which is what we will be sending through the http request. You will need to encode your recipient (this part of the code can also be used to support group messaging, but I have not included that code, you will need to write it yourself if you so choose. You can attach multiple addresses by calling sendRequest.addTo() multiple times) and attach it to the sendRequest. Next up, attach your MMSPart file using a for loop. Here is how to initialize that MMSPart to whatever you want to include in it:
Code:
Bitmap b = ________; // Whatever your bitmap is that you want to send
ByteArrayOutputStream stream = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
MMSPart[] parts = new MMSPart[1];
parts[0] = new MMSPart();
parts[0].Name = "Image";
parts[0].MimeType = "image/png";
parts[0].Data = byteArray;
Using this, you can also add text to the request with the mimetype "text/plain" and encode text as a byte array so that it can be attached in the same mannor. I won't post that code, you should be able to figure it out.
Back to the original sendData function, we can now attach the pduBody which includes all of the byte arrays that we want to send, in this specific case, just an image and no text. After that, all that is left is to actually create the byte array to send, bytesToSend, which can be done very easily through internal classes.
Now we are ready to make the actual send request, which must be done through the users APNs using an http_post method. But first, we need to retrieve APNs. As I said earlier, if a user is running an Android version less then 4.0, then the app should be able to get the system defined APNs through the APN helper class that I provided (still no promises on this though as it has been untested, I don't have an old phone anymore to test on). Surround the request to APNHelper with a try/catch block so that we can catch the error of insigificant permissions, and then apply your user defined custom APNs that will actually work. I have users enter these in settings, thats why you see them being set through sharedPreference strings. you can manually type in whatever strings you want to for your network during testing phases though and that should work fine, just remember different networks use different APNs.
Ahh finally we are ready to make our Http request. This is fairly simple, as it is just one line of code which you should be able to directly take from my example if you initialize apns the same way I have:
Code:
HttpUtils.httpConnection(context, 4444L, apns.get(0).MMSCenterUrl, bytesToSend, HttpUtils.HTTP_POST_METHOD, !TextUtils.isEmpty(apns.get(0).MMSProxy), apns.get(0).MMSProxy, Integer.parseInt(apns.get(0).MMSPort));
You can look at javadocs for this function if you want to know what all of this is, but just know that it will make a post request through your MMSC you have defined and then send the message through the proxy and port (if those are needed, some carriers do not require them). Also, remember to add a catch block around this in case the sending fails for whatever reason, and tell your users that the request has failed. In this example, when the message fails to send, it moves the message to msg_box = 5, which is where MMS with errors are stored. This is simply updating the database with a new location for our recently failed message.
Last thing we have to do is listen for when the message has sent. This is where I've completely made up a function, and it functions correctly for ALMOST everyone (the only people not so far are Sprint users, and I haven't found a way around it yet). To do this, after our request, we register a new connectivity receiver just as we did when we were preparing to send a message, and this time around, when the state of the phones internet connection changes - usually dropping out of the APN request space I believe - we can move the message from the outbox to the sent message box and boom, message sent.
Yay, you should have just been able to send your first MMS message! (Unless I forgot a step in there lol) That's exciting stuff! Notice now though, that although you sent the message (and you have coded in how to change which message box the message is in), the message didn't get saved to the database so you can't actually see it in the app. That doesn't do most of us any good, so next step is how to save it to the SMS database on your phone.
6) Here we save the message, I'll just list out the functions again and then explain them after that:
Code:
public static Uri insert(Context context, String[] to, String subject, byte[] imageBytes)
{
try
{
Uri destUri = Uri.parse("content://mms");
// Get thread id
Set<String> recipients = new HashSet<String>();
recipients.addAll(Arrays.asList(to));
long thread_id = Telephony.Threads.getOrCreateThreadId(context, recipients);
// Create a dummy sms
ContentValues dummyValues = new ContentValues();
dummyValues.put("thread_id", thread_id);
dummyValues.put("body", "Dummy SMS body.");
Uri dummySms = context.getContentResolver().insert(Uri.parse("content://sms/sent"), dummyValues);
// Create a new message entry
long now = System.currentTimeMillis();
ContentValues mmsValues = new ContentValues();
mmsValues.put("thread_id", thread_id);
mmsValues.put("date", now/1000L);
mmsValues.put("msg_box", 4);
//mmsValues.put("m_id", System.currentTimeMillis());
mmsValues.put("read", 1);
mmsValues.put("sub", subject);
mmsValues.put("sub_cs", 106);
mmsValues.put("ct_t", "application/vnd.wap.multipart.related");
if (imageBytes != null)
{
mmsValues.put("exp", imageBytes.length);
} else
{
mmsValues.put("exp", 0);
}
mmsValues.put("m_cls", "personal");
mmsValues.put("m_type", 128); // 132 (RETRIEVE CONF) 130 (NOTIF IND) 128 (SEND REQ)
mmsValues.put("v", 19);
mmsValues.put("pri", 129);
mmsValues.put("tr_id", "T"+ Long.toHexString(now));
mmsValues.put("resp_st", 128);
// Insert message
Uri res = context.getContentResolver().insert(destUri, mmsValues);
String messageId = res.getLastPathSegment().trim();
// Create part
if (imageBytes != null)
{
createPartImage(context, messageId, imageBytes);
}
// Create addresses
for (String addr : to)
{
createAddr(context, messageId, addr);
}
//res = Uri.parse(destUri + "/" + messageId);
// Delete dummy sms
context.getContentResolver().delete(dummySms, null, null);
return res;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
Code:
private static Uri createPartImage(Context context, String id, byte[] imageBytes) throws Exception
{
ContentValues mmsPartValue = new ContentValues();
mmsPartValue.put("mid", id);
mmsPartValue.put("ct", "image/png");
mmsPartValue.put("cid", "<" + System.currentTimeMillis() + ">");
Uri partUri = Uri.parse("content://mms/" + id + "/part");
Uri res = context.getContentResolver().insert(partUri, mmsPartValue);
// Add data to part
OutputStream os = context.getContentResolver().openOutputStream(res);
ByteArrayInputStream is = new ByteArrayInputStream(imageBytes);
byte[] buffer = new byte[256];
for (int len=0; (len=is.read(buffer)) != -1;)
{
os.write(buffer, 0, len);
}
os.close();
is.close();
return res;
}
Code:
private static Uri createAddr(Context context, String id, String addr) throws Exception
{
ContentValues addrValues = new ContentValues();
addrValues.put("address", addr);
addrValues.put("charset", "106");
addrValues.put("type", 151); // TO
Uri addrUri = Uri.parse("content://mms/"+ id +"/addr");
Uri res = context.getContentResolver().insert(addrUri, addrValues);
return res;
}
I didn't write these functions, credit to Vodemki on Stack Overflow. All you have to do is call the insert function and it will do all of the work for you. Send that fuction the activity context, a string array of the numbers who you sent the message to, a subject for the message, and the same byte array of the image you passed earlier to your MMS part file. You can look at the code for inserting the image and reproduce this to do the same for a string of text you are sending with the image.
You will want to actually call these funtions right after you push the send button for example, to first save the message and then you can send it and update it later after it has sent or failed to send.
Ok, now that will successfully allow you to put the MMS message in the database. For some reason, these messages just show up as blank messages in the stock app, not sure why, but Sliding Messaging is able to read them at least, so depending on your implementation, yours should be able to do so as well.
Now all this function does is insert the image. I don't want to give away all of my secrets for Sliding Messaging so you will have to go through and find out how to insert text and group message addresses yourself, I think that's fair enough and if you've made it this far in your app, you shouldn't have to much of a problem with it
Wow, we just sent and saved that message to our phone, that means we are halfway home! (Nice rhyme huh )
Onto receiving in the next post.
7) First up, you'll have to know a little something about querying the mms-sms database, read up on that first if you haven't already (first link I have posted at the top). This is all out of my brain and what I was able to do from experience, and seems to work very well... you won't find a tutorial anywhere else on the internet of how to do this (at least I couldn't anywhere). I'm not going to just give you a simple function for this one though, you will have to adapt the code according to how you want it to be used. Once again, here is the code you will need to use:
Code:
id = ________; // this is the id of your MMS message that you are going to search for
Cursor locationQuery = context.getContentResolver().query(Uri.parse("content://mms/"), new String[] {"m_size", "exp", "ct_l", "_id"}, "_id=?", new String[]{id}, null);
locationQuery.moveToFirst();
String exp = "1";
String size = "1";
try
{
size = locationQuery.getString(locationQuery.getColumnIndex("m_size"));
exp = locationQuery.getString(locationQuery.getColumnIndex("exp"));
} catch (Exception f)
{
}
String location = locationQuery.getString(locationQuery.getColumnIndex("ct_l"));
The above function is where you query the message you are interested in downloading, and get data from it such as expiration date, size, and location on a server. The date will be a date in milliseconds that you can format accordingly and display to the screen if you so choose, and the size will be in bytes, but you will probably want to convert to kb by dividing by 1000. As for the location, that is what we are going to use to download the message:
Code:
List<APN> apns = new ArrayList<APN>();
try
{
APNHelper helper = new APNHelper(context);
apns = helper.getMMSApns();
} catch (Exception e)
{
APN apn = new APN(sharedPrefs.getString("mmsc_url", ""), sharedPrefs.getString("mms_port", ""), sharedPrefs.getString("mms_proxy", ""));
apns.add(apn);
}
Get your APNs the same way as we did before when sending, I won't explain this again.
Code:
try {
byte[] resp = HttpUtils.httpConnection(
context, SendingProgressTokenManager.NO_TOKEN,
downloadLocation, null, HttpUtils.HTTP_GET_METHOD,
!TextUtils.isEmpty(apns.get(0).MMSProxy),
apns.get(0).MMSProxy,
Integer.parseInt(apns.get(0).MMSPort));
RetrieveConf retrieveConf = (RetrieveConf) new PduParser(resp).parse();
PduPersister persister = PduPersister.getPduPersister(context);
Uri msgUri = persister.persist(retrieveConf, Inbox.CONTENT_URI, true,
true, null);
ContentValues values = new ContentValues(1);
values.put(Mms.DATE, System.currentTimeMillis() / 1000L);
SqliteWrapper.update(context, context.getContentResolver(),
msgUri, values, null, null);
SqliteWrapper.delete(context, context.getContentResolver(),
Uri.parse("content://mms/"), "thread_id=? and _id=?", new String[] {threadIds, msgId});
((Activity) context).getWindow().getDecorView().findViewById(android.R.id.content).post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "Message Received", Toast.LENGTH_SHORT).show();
}
});
} catch (Exception e) {
e.printStackTrace();
((Activity) context).getWindow().getDecorView().findViewById(android.R.id.content).post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "Download Failed", Toast.LENGTH_SHORT).show();
}
});
}
This request is much the same as the previous we used when sending the message, except this time we use a get request instead of post, send the funtion a null where before it was out bytesToSend array, and receive a byte array from it. Once you have received this byte array, you can easily use internal classes to save the message to the database (these messages are saved 100% correctly and will show up in the stock app once downloaded, unlike before) and then delete the old message stored there that only had location data for the message to be downloaded. I won't go into much more detail then that, it should be easy enough to understand just from the code.
I have this function tied to a button press, but in theory you should also be able to register a WAP_PUSH_RECEIVED broadcast receiver that saves the message automatically when your phone gets one (WAP is the type of broadcast you get when receiving MMS data). I'm not going to post anything here about that because I haven't done it, but if you want, all of the code is the same and you can easily base it happening off of a setting in your app and the network connectivity state when the message is received.
Another Note: There is probably a way to use the above code with persisters etc to be able to save an MMS to the database in a much easier way, but I haven't looked into that at all, mostly because the code I posted in step 6 works just fine and I don't see a need for much else if you can handle just copying and pasting those functions.
Now I think that may be it... we covered sending MMS, saving sent MMS and finally receiving MMS! Fun stuff!
In conclusion, I just want to give something back to the community that has given my app, Sliding Messaging, so much love over the past couple of months. I hope this helps someone out there, because as far as I know and could find, this is the only full MMS tutorial there is for Android (and the only one at all for actually downloading MMS from the internet) and should get everything done that you need! Ask any questions you want and feel free to PM me if you need more assistance.
Now no one out there should have any excuse for not including at least some MMS support in your messaging apps! Hopefully this will save you from days upon days of research to no avail on the subject and unjust criticism from people who know absolutely nothing about the topic like I did (Had one person tell me to f-off and if I couldn't get it working, then his $0.99 entitled him to say that I needed to hire someone else who was actually competent at programming and spend all of my college savings so that person would do it for me ... to that person I say, HAHA, I did it. lol) Your users will be happy people if you get this implemented!
Also guys, I wouldn't mind getting a little credit if anyone out there uses this tutorial to get things up and running, but its not necessary if you don't want! Instead you could just buy me a beer and donate to me To the people who actually read through these last 3 paragraphs, I say thank you! Hopefully this tutorial can at least get you started, wish I had it reference when I was adding the support in!
Sources:
1) How to Read MMS Data in Android
2) Android Add MMS to Database
3) MMS in Android: Part 1
4) GrepCode
5) My own experience
Cheers, and good luck to anyone trying this out this is my first tutorial so if you find anything missing or any typos, let me know!
grepcode files missing
I tried to download classes from your given link 'Grepcode'.
It is missing the contents of com.google folder even it do not contain folder named google in com folder. (i tried different versions like 4.2.1,4.2.2 etc .. still same problem )
can you give me any other link to download classes ?
Cool, thanks.
(You might want to add [Guide] to your thread title. For now it looks like a question. )
Thanks very much for doing this. Had to do a bit of searching on the internet for some of the files, and some of the functions needed slight modification but this was enough of a push in the right direction that I've got mms sending working. Great job and good luck with the continued success of your app!
Also- your responses on the android marketplace to people leaving stupid feedback make me laugh!
Getting Connection Refused error
Hi,
I tried your code. I am getting the APN settings perfectly. But a soon as the httpClient tries to connect to my MMSC it throws ConnectionRefused Error.
Please help me. Its been head-scratcher 3 days in a row now.
Thanks. in advance.
Please help
I am not able to import the classes with name
com.android.mms.*
and
com.google.*
I downloaded the android-4.2.2_r1.jar and also android-4.4_r1.jar
But these jars do not contain all required classes.
Please help how to add these classes.
Regarding the missing classes
Hi,
I am looking for a solution to programmatically sending MMS through my Android Application.
Some classess are missing(com.google.*) in the jar downloaded from grepcode.
Can anybody help in this regard?
Thanks.
Missing Function
hi
When I want to insert MMS message in DB, eclipse says "Telephony.Threads.getOrCreateThreadId" is undefined!
What should I do?
Thanks
CursorIndexOutOfBoundsException
hi ,
I get exception like this
android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
AS per yourCode
Cursor query = context.getContentResolver().query(Uri.parse("content://mms"), new String[]
{
"_id"
}, null, null, "date desc");
query.moveToFirst();
String id = query.getString(query.getColumnIndex("_id"));
get force close when i try to get id
Does this still work? I noticed a lot of the comments say there are missing stuff. I need a good tutorial for implementing MMS sending/ receiving.

Grabbing data from a website and putting it into my app?

Hi!
My friend talks about this website a lot and said its a great help, and I need some help.
I'm making a app that's grabs images from a couple of websites, and the website updates all the time with new images, and I want my app to dynamically update with it.
I also want my app to precisely filter through the images and put the right images in the right respective folders.
The problem is I don't know how to do this and I can't really find any resources online that can properly explain this (the grabbing data part).
Could someone offer some advice?
google "android parse html" and you will find help. You will need to parse the html for the url of images.
Then you could look over this for an example how to load an image in to an imageview:
http://stackoverflow.com/questions/12172928/android-image-view-from-url
Thanks
Maybe, I'll look into it when I'm done with my exam.
there are thousands of images I want my app to filter through, its gonna take a while to learn
thanks so much for the suggestion
If you know the url of the images you want to fetch beforehand, then use a library such as Picasso by Square Inc., it will allow you to asynchronously load images into your views by calling a single line of code most of the time :
Code:
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Otherwise, if you don't know the urls and want to fetch the images by grabbing the content of the <img src="XXX"/> tags, then you want to look at regular expressions, you could grab the code of the webpage into an InputStream, use a BufferedReader to loop through it line by line and see if it matches your regex, in which case it returns the "XXX", web-crawler style.
Androguide.fr said:
If you know the url of the images you want to fetch beforehand, then use a library such as Picasso by Square Inc., it will allow you to asynchronously load images into your views by calling a single line of code most of the time :
Code:
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Otherwise, if you don't know the urls and want to fetch the images by grabbing the content of the <img src="XXX"/> tags, then you want to look at regular expressions, you could grab the code of the webpage into an InputStream, use a BufferedReader to loop through it line by line and see if it matches your regex, in which case it returns the "XXX", web-crawler style.
Click to expand...
Click to collapse
How to get the html code:
Code:
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 4000);
HttpConnectionParams.setSoTimeout(params, 5000);
HttpClient client = new DefaultHttpClient(params);
HttpGet request = new HttpGet("www.google.com"); //your url goes here
HttpResponse response = client.execute(request);
InputStream is = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while((line = reader.readLine()) != null) {
//do something with the information
Log.d("line", line);
}
nikwen said:
How to get the html code:
Code:
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 4000);
HttpConnectionParams.setSoTimeout(params, 5000);
HttpClient client = new DefaultHttpClient(params);
HttpGet request = new HttpGet("www.google.com"); //your url goes here
HttpResponse response = client.execute(request);
InputStream is = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while((line = reader.readLine()) != null) {
//do something with the information
Log.d("line", line);
}
Click to expand...
Click to collapse
Well, while we're at it, here's the code to retrieve the url(s) contained in the src attribute of <img> tags on a website^^
There's probably a more elegant regex but this should work
Code:
// [user=5101348]@nikwen[/user] 's code
// ...
InputStream is = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
ArrayList<String> array = new ArrayList<String>();
while((line = reader.readLine()) != null) {
// If the line matches our regex, extract the url and add it to our ArrayList
String regex = "(*+<img\\s*+src=\")(.+)(\");
if (line.matches(regex)) {
line = line.replaceAll(regex, "$1");
array.add(line);
}
for (int i = 0; i < array.size(); i++) {
Log.d("URL: ", array.get(i));
}
}
Androguide.fr said:
Well, while we're at it, here's the code to retrieve the url(s) contained in the src attribute of <img> tags on a website^^
There's probably a more elegant regex but this should work
Code:
// [user=5101348]@nikwen[/user] 's code
// ...
InputStream is = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
ArrayList<String> array = new ArrayList<String>();
while((line = reader.readLine()) != null) {
// If the line matches our regex, extract the url and add it to our ArrayList
String regex = "(*+<img\\s*+src=\")(.+)(\");
if (line.match(regex)) {
line = line.replaceAll(regex, "$1");
array.add(line);
}
for (int i = 0; i < array.size(); i++) {
Log.d("URL: ", array.get(i));
}
}
Click to expand...
Click to collapse
What's more performant? The contains or the matches method? I guess the contains method, right?
(However, I don't know a way to use the contains method here.)
nikwen said:
What's more performant? The contains or the match method? I guess the contains method, right?
(However, I don't know a way to use the contains method here.)
Click to expand...
Click to collapse
I really couldn't tell which one is faster, it's a good question though.
EDIT: you made me realize I made a typo, the method is .matches() and not .match(), correcting the previous post.
Androguide.fr said:
Well, while we're at it, here's the code to retrieve the url(s) contained in the src attribute of <img> tags on a website^^
There's probably a more elegant regex but this should work
Code:
// [user=5101348]@nikwen[/user] 's code
// ...
InputStream is = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
ArrayList<String> array = new ArrayList<String>();
while((line = reader.readLine()) != null) {
// If the line matches our regex, extract the url and add it to our ArrayList
String regex = "(*+<img\\s*+src=\")(.+)(\");
if (line.matches(regex)) {
line = line.replaceAll(regex, "$1");
array.add(line);
}
for (int i = 0; i < array.size(); i++) {
Log.d("URL: ", array.get(i));
}
}
Click to expand...
Click to collapse
Can you explain what is happening here in the String regex line as well as the line = line.replaceAll(), please?
Shizznizz said:
Can you explain what is happening here in the String regex line as well as the line = line.replaceAll(), please?
Click to expand...
Click to collapse
Sure, my regular expression is here divided into 3 groups (each between parenthesis), let's run through them:
*+<img\\s*+src=\"
This basically says "match any character any number of times (*+) followed by <img and a blankspace (\s escaped twice as it's in a string), followed by any character any number of times again (*+, to cover cases where other attributes are placed before src), followed by src="
.+
This corresponds to the actual URL we are looking for, it matches any character any number of times except 0 times (.+)
\"
Self explanatory, the closing quote for our src="X" attribute, escaped as contained within a String
The grouping comes into play in the line.replaceAll(), basically, it says replace the whole line string with group n°2 of our regex, which is our URL.
When grouping a regex, the second parameter of replaceAll() can be set as $X, where X is the target group's 0-based index, in our case the second group so $1
So, to conclude, the schema of the snippet is:
Grab the whole html code of the webpage
Loop through it line by line
If a line contains a <img> tag, retrieve the string contained within the src attribute of its <img> tag and add it to an array
Otherwise, go to next line and repeat previous step
Androguide.fr said:
Sure, my regular expression is here divided into 3 groups (each between parenthesis), let's run through them:
*+<img\\s*+src=\"
This basically says "match any character any number of times (*+) followed by <img and a blankspace (\s escaped twice as it's in a string), followed by any character any number of times again (*+, to cover cases where other attributes are placed before src), followed by src="
.+
This corresponds to the actual URL we are looking for, it matches any character any number of times except 0 times (.+)
\"
Self explanatory, the closing quote for our src="X" attribute, escaped as contained within a String
The grouping comes into play in the line.replaceAll(), basically, it says replace the whole line string with group n°2 of our regex, which is our URL.
When grouping a regex, the second parameter of replaceAll() can be set as $X, where X is the target group's 0-based index, in our case the second group so $1
So, to conclude, the schema of the snippet is:
Grab the whole html code of the webpage
Loop through it line by line
If a line contains a <img> tag, retrieve the string contained within the src attribute of its <img> tag and add it to an array
Otherwise, go to next line and repeat previous step
Click to expand...
Click to collapse
That was very helpful. Thank you!
Androguide.fr said:
I really couldn't tell which one is faster, it's a good question though.
EDIT: you made me realize I made a typo, the method is .matches() and not .match(), correcting the previous post.
Click to expand...
Click to collapse
Ok, so I did some benchmarking:
Code:
import java.util.ArrayList;
public class Benchmark {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
ArrayList<String> list2 = new ArrayList<String>();
for (int i = 0; i < 10000000; i++) {
String s = String.valueOf(i);
if ((i % 78) == 0) {
s += "test" + i;
}
list.add(s);
}
list2.addAll(list);
long time = System.currentTimeMillis();
for (String line: list) {
if (line.matches("(.*)test(.*)")) {
System.out.println(line);
}
}
long timeMatches = System.currentTimeMillis();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long time2 = System.currentTimeMillis();
for (String line: list2) {
if (line.contains("test")) {
System.out.println(line);
}
}
long timeContains = System.currentTimeMillis();
System.out.println("Time for matches(): " + (timeMatches - time));
System.out.println("Time for contains(): " + (timeContains - time2));
}
}
Some results:
Code:
Time for matches(): 7116
Time for contains(): 893
Time for matches(): 6973
Time for contains(): 1027
Time for matches(): 8264
Time for contains(): 858
Time for matches(): 8098
Time for contains(): 1216
Even if it is no perfect benchmark, you can see the (big) difference.
The contains method is about 8 times faster than matches with a regex that does the same.
Remember, I used a very simple regex. So it should be even slower for more complicated ones.
Of course, it just shows what is faster on the desktop computer. However, it should be the same on an Android device. There's such a big difference in performance.
In my opinion the result makes sense.
The contains method just checks whether it can find the char array (which a String is for the computer) in another.
The matches method has to interpret the regex first. Afterwards, it has to do lots of calculation to check whether the String matches the regex.
nikwen said:
Ok, so I did some benchmarking:
Code:
import java.util.ArrayList;
public class Benchmark {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
ArrayList<String> list2 = new ArrayList<String>();
for (int i = 0; i < 10000000; i++) {
String s = String.valueOf(i);
if ((i % 78) == 0) {
s += "test" + i;
}
list.add(s);
}
list2.addAll(list);
long time = System.currentTimeMillis();
for (String line: list) {
if (line.matches("(.*)test(.*)")) {
System.out.println(line);
}
}
long timeMatches = System.currentTimeMillis();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long time2 = System.currentTimeMillis();
for (String line: list2) {
if (line.contains("test")) {
System.out.println(line);
}
}
long timeContains = System.currentTimeMillis();
System.out.println("Time for matches(): " + (timeMatches - time));
System.out.println("Time for contains(): " + (timeContains - time2));
}
}
Some results:
Code:
Time for matches(): 7116
Time for contains(): 893
Time for matches(): 6973
Time for contains(): 1027
Time for matches(): 8264
Time for contains(): 858
Time for matches(): 8098
Time for contains(): 1216
Even if it is no perfect benchmark, you can see the (big) difference.
The contains method is about 8 times faster than matches with a regex that does the same.
Remember, I used a very simple regex. So it should be even slower for more complicated ones.
Of course, it just shows what is faster on the desktop computer. However, it should be the same on an Android device. There's such a big difference in performance.
In my opinion the result makes sense.
The contains method just checks whether it can find the char array (which a String is for the computer) in another.
The matches method has to interpret the regex first. Afterwards, it has to do lots of calculation to check whether the String matches the regex.
Click to expand...
Click to collapse
Awesome, thanks for taking the time to benchmark it.
Yeah, it does make sense that matches() is slower because of the parsing computation.
But as you said, in this kind of case you can't really use anything else than a regex, and thus you have to use matches()
Either way, the difference shouldn't be noticeable to the human eye I guess, regular expressions can only be so long.
Androguide.fr said:
Awesome, thanks for taking the time to benchmark it.
Yeah, it does make sense that matches() is slower because of the parsing computation.
But as you said, in this kind of case you can't really use anything else than a regex, and thus you have to use matches()
Either way, the difference shouldn't be noticeable to the human eye I guess, regular expressions can only be so long.
Click to expand...
Click to collapse
Yeah, it's not noticeable. It takes about 8 seconds for 10000000 regexes. Thats 0.0000008 seconds per regex.

Java Help ?

Hello i am working this code on Programmr.com and i have tried everything to figure this simple code out and any help would be great-full this is from java program from the site. FYI i am a rookie this may be a simple code but i am trying to think different but no luck.
Here is the problem : >
Problem:
You and the Martian start becoming good friends. There is so much in common between the two of you - an interest in camping on volcanic peaks to hunting for quarters in the swimming pool. One summer afternoon, you and your Martian friend decide to play a game of Echo. The purpose of the game is to echo what the other person is saying. If the Martian says "zboggattyu", you have to reply back with "zboggattyu".
The exercise below, asks you to enter some text on the system console. This text will be stored in the variable 'someText'. This is then copied into another variable called '-echo', which is printed back to the system console. However, we are unable to get the code to compile. You have to get the code to compile, so you can play echo with your Martian friend.
What we expect:
Primarily, we expect you to get the code to compile. Once the code is compiled and run, it will ask you to enter a String on the system console. We expect the same String is echoed (printed) back on the system console.
Hint:
There are some rules governing valid variable names
Learning Outcomes:
After completing this exercise, you should have learned what constitutes a valid variable name.
Here is the code
import java.util.Scanner;
public class Echo {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
System.out.println("Please enter something: ");
String someText = scanner.next();
String echo = "";
///{
//start your coding here
// ?
///}
System.out.println(echo);
}
}
That excersie compiled fine for me even without making any modifications to it... However, the solution they're probably looking for is:
Code:
import java.util.Scanner;
public class Echo {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
System.out.println("Please enter something: ");
String someText = scanner.next();
String echo = "";
echo = someText;
System.out.println(echo);
}
}
Which seems to work fine for me, though to be honest that is a bad way of doing it as you don't actually need the echo variable so you're wasting resources by defining a new variable... a more efficient way of doing it is:
Code:
import java.util.Scanner;
public class Echo {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
System.out.println("Please enter something: ");
String someText = scanner.next();
System.out.println(someText);
}
}
Or you could even go one step further and ignore the someText variable altogether like below:
Code:
import java.util.Scanner;
public class Echo {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
System.out.println("Please enter something: ");
System.out.println(scanner.next());
}
}
Edit: After looking at this some more and seeing that the lesson is about variable names I believe that they actually meant to give you the below code to solve:
Code:
import java.util.Scanner;
public class Echo {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
System.out.println("Please enter something: ");
String someText = scanner.next();
String -echo = "";
System.out.println(-echo);
}
}
Where the line of String -echo =""; would be causing the code not to compile because of the rules governing the naming of variables so the solution would have been to change '-echo' to 'echo' - unfortunately it would seem that they messed they're own exercise up there :laugh:
Thank you for the help developers.
Sent from my SGH-M819N using XDA Free mobile app

Categories

Resources