A problem with image capture on Motorola Milestone - android

Below is the simple code fragment to illustrate the problem.
Why the value of the field "tag" logged in method "onActivityResult" not being "tag_modified"?
I also tried others async call of "startActivityForResult", but no such problem exists.
The problem merely occurs on my Moto Milestone, but everything goes well on HTC G7.
public class HelloSnapshot extends Activity {
private static Logger logger = Logger.getLogger(HelloSnapshot.class.getName());
final int REQUESTCODE_SNAPSHOT = 1;
String tag = "tag_initial";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button button = new Button(this);
button.setText("BUTTON");
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tag = "tag_modified";
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, REQUESTCODE_SNAPSHOT);
}
});
setContentView(button, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
public void onActivityResult(int requestCode, int resultCode , Intent data) {
switch (requestCode) {
case REQUESTCODE_SNAPSHOT:
if (resultCode == Activity.RESULT_OK) {
logger.info(tag);
}
break;
}
}
}

I`ve found it out...
Some android OS kill the snapshot calling Activity to avoid memory related exception.
So, I have to save all the states via method onSaveInstanceState, and retrieve them when the calling activity was constructed again.
Further more, I also found out that, all the information stored in the memory is prone to be erased, like those Singleton objects. Thus I have to do saving by some persistent storage approaches, and restore them later.

Related

Is it fine to pass an activity instance to a class?

There is a scenario in which i need to pass activity and its button to a java class.
I did following and its working fine, I am only concerned if its the right way of integrating this.
MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button= findViewById(R.id.btn);
UIComponents uiComponents= new UIComponents();
uiComponents.setActivity(this, button);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d("result", String.valueOf(requestCode));
}
UIComponents.class
public class UIComponents {
public void setActivity(final AppCompatActivity activity, Button btn){
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent= new Intent(activity, ResultActivity.class);
activity.startActivityForResult(intent, 999);
}
});
}
This works perfectly fine, It displays toast message on my activity screen, also i am able to receive onActivityResult callback on my activity. I am concerned if this can lead to any performance related issues.
you can just pass only the Button and use the getContext method available e.g
public class UIComponents {
public void setActivity(Button btn){
Context activity = btn.getContext();
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent= new Intent(activity, ResultActivity.class);
activity.startActivityForResult(intent, 999);
}
});
}
The most important thing to consider here is the lifecycle of your components. In general you shouldn't pass a reference to an activity to any object which might outlive it. In theory (probably very rear), your activity might be killed between the time the user clicks the button and the time the OnClickListener (if it wasn't garbage collected yet) will be executed and you'll get a NullPointerException. Also, you might pass (even accidentally) UIComponents to some other object with a different lifecycle.
Best practice in such a case is usually using MVP architecture. The specific case of handling button clicks is described here among other places.
In addition, following the "Guide to App Architecture" by Google is probably a good idea.

Intent putExtra bitmap issue

I have the following code:
((ImageButton)findViewById(R.id.fish)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(StartupActivity.this, GameActivity.class);
intent.putExtra(NAME_EXTRA, ((EditText)findViewById(R.id.name)).getText().toString().trim());
intent.putExtra(TYPE_EXTRA, FishTypes.FISH.toString());
intent.putExtra(WORLD_TYPE_EXTRA, worldType);
intent.putExtra(LOGO_EXTRA, BitmapFactory.decodeResource(getResources(), R.drawable.logo));
startActivity(intent);
}
});
If I start activity and click on ImageButton it send me to the same Activity I was before (StartupActivity). However if I comment out the last putExtra like this:
//intent.putExtra(LOGO_EXTRA, BitmapFactory.decodeResource(getResources(), R.drawable.logo));
Then it works fine. It sends me to the GameActivity as I want. What could be the problem?
EDIT
My GameActivity looks like this:
public class GameActivity extends Activity {
public static GamePanel gamePanel;
public static String name;
public static FishTypes type;
public static String worldType;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(getWindow().FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
name = getIntent().getStringExtra(StartupActivity.NAME_EXTRA);
type = FishTypes.parse(getIntent().getStringExtra(StartupActivity.TYPE_EXTRA));
worldType = getIntent().getStringExtra(StartupActivity.WORLD_TYPE_EXTRA);
gamePanel = new GamePanel(this);
//gamePanel.bitmaps.put("logo", (Bitmap)getIntent().getParcelableExtra(StartupActivity.LOGO_EXTRA));
setContentView(gamePanel);
if(!StartupActivity.isNetworkAvailable()) {
Toast.makeText(StartupActivity.getInstance(), "You have no internet connection...", Toast.LENGTH_LONG).show();
finish();
}
}
#Override
protected void onDestroy() {
if(gamePanel.client != null)
gamePanel.client.disconnect();
StartupActivity.getInstance().reopen();
super.onDestroy();
}
}
What I want to achieve is preloading this bitmap in StartupActivity and then just send it to the GameActivity to the GamePanel and then draw it on the canvas as a loading image. I can't load this image in GameActivity because it will be late to show it. Do you understand?
So first of all, there is an Intent payload limit, as far as I know there is a limit of 1MB, but in some cases can be 500kb. If this limit is overreached the app will crash, in your case crashed and restarted.
Second of all, Bundle and Intent are used to send small amount of data to Activity and Fragments, usually some configs/params so that the activity/fragment will know how to build itself.
Third, is a really bad practice to pass around instances of bitmaps, you need just a second of distraction to create a huge leak in your app, that will cost you a lot of time to find and fix it.
Now the solution for you is really simple. You can pass the id of the bitmap you want to use in the next activity.
Intent intent = new Intent(StartupActivity.this, GameActivity.class);
intent.putExtra(NAME_EXTRA, ((EditText)findViewById(R.id.name)).getText().toString().trim());
intent.putExtra(TYPE_EXTRA, FishTypes.FISH.toString());
intent.putExtra(WORLD_TYPE_EXTRA, worldType);
intent.putExtra(LOGO_EXTRA, R.drawable.logo); // R.drawable.logo is actually an int.
startActivity(intent);
In your GameActivity
#Override
public void onCreate(Bundle savedInstanceState) {
setContentView(...)
int myAwesomeDrawable = getIntent().getExtra(LOGO_EXTRA, 0); // 0 is default value in case nothing is added to the key
if(myAwesomeDrawable != 0){ // safety check
imageView.setImageResource(myAwesomeDrawable);
// or do whatever you like with it.
}

How do I change an activities's boolean values or other variable values in another activity?

So I have a boolean value in Activity A that is set to false. Then, in another activity I want to change that value to true. Then when i press the back button back to activity A, that boolean is now true and it runs that in the onCreate.
here's what I mean, Activity A
private static boolean newCardcheck = false;
#Override
protected void onCreate(Bundle savedInstanceState)
{
}
public static void setNewCardcheck() {
newCardcheck = true;
}
#Override
public void onResume() {
super.onResume();
if(newCardcheck)
{
Toast.makeText(this,"hey everyone",Toast.LENGTH_SHORT).show();
}
else
{
alfunction();
sendCards(storeCards);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if(requestCode == RESULT_LOAD_IMAGE)
{
newCardcheck = true;
}
}
Activity B:
#Override
public void onBackPressed()
{
MyActivity.setNewCardcheck();
super.onBackPressed();
setResult(Activity.RESULT_OK, getIntent());
finish();
}
So when I press back, I want newCardcheck to be true and run the "if" statement not the else statement.
Hope you guys can help.
thanks.
And I also tried putting setNewCard() method in an onClick it didn't work either.
The best way to do this is through SharedPreferences. SharedPreferences will write your data to a private file in a key/value within your app's apk that will persist even you turn your device off.
You can initialize SharedPreferences in onCreate like so: SharedPreferences sharedPreferences = getSharedPreferences(getPackageName(), MODE_PRIVATE).
To store a value simply call: sharedPreferences.edit().putString("myKey", stringValue).commit();
To retrieve that value anywhere from your application, initialize SharedPreferences, and then use the following code: String myData = sharedPreferences.getString("myKey");
Let me know if that helps!
EDIT: You may also want to look into getting a result from your Intent. See Getting a Result from an Activity. Use SharedPreferences if you need the boolean to be persistent (ie: written to storage and available on reboot), otherwise you may want to try onActivityResult.
Edit 2:
Try overriding onActivityResult in Activity A as so:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
myBoolean = true;
}
}
Then in Activity B try
setResult(Activity.RESULT_OK, getIntent());
finish();
This is the standard way of passing data to and from activities. Check out my link above about getting a result from an activity to delve a little deeper.

pause an activity meanwhile another one is running

I would like to get voice recognition using just one method.
In order to do that i've created 3 classes
the main class
public class Index extends Activity {
private Button boton;
private EditText texto;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_index);
boton = (Button)findViewById(R.id.boton);
texto = (EditText) findViewById(R.id.texto);
boton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
texto.setText(IVRecognition.getInstancia().getComando(Index.this));
}
});
}
}
the intermediate
public class IVRecognition {
//*******************singleton********************
private static IVRecognition instancia;
private IVRecognition (){}
public static IVRecognition getInstancia(){
if (instancia==null) instancia = new IVRecognition();
return instancia;
}
//************************************************
public static String resultado = null;
public String getComando(Context content){
Intent intent = new Intent(content, VRecognition.class);
content.startActivity(intent);
//pause here untill VRecognition.onActivityResult is executed
return resultado;
}
}
and the recognition one
public class VRecognition extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startRecognition();
}
public void startRecognition (){
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,this.getPackageName());
startActivityForResult(intent, 1 /*VOICE_RECOGNITION_REQUEST_CODE*/);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == 1 /*VOICE_RECOGNITION_REQUEST_CODE*/ && resultCode == RESULT_OK){
ArrayList<String> result = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
IVRecognition.getInstancia().resultado = result.get(0);
}
this.finish();
}
}
The problem is that when I call VRecognition activity using content.startActivity(intent); the execution of the aplication keeps on going, so the variable called resultado has null value until onActivityResult is executed, which results in a null return value.
Hope you can help me. Cheers
Ian's answer is good. But from your comment, I'd recommend using an IntentService and the BroadcastManager. That way you don't need the intermediate activity. You call the startService(intent) from any activity that wants the VR result (and implements BroadcastReceiver). Then the IntentService calls startActivityForResult(intent,1) and Broadcasts the result.
More info:
http://developer.android.com/training/run-background-service/index.html
It sounds like you want to pause execution until voice recognition is complete. You may want to rethink this; you're calling getComando() from your UI thread, so your application UI will be frozen until recognition is complete. In the (probably quite likely) event that recognition takes more than five seconds, the system will pop up an Application Not Responding dialog. (Also, since you're implementing getComando() by starting another activity within your process, blocking the UI thread in getComando() would prevent recognition from ever running.)
The right way to do this is to use a completion callback. For instance, you could create an IVRecognitionListener interface:
public interface IVRecognitionListener {
public void onRecognitionComplete(String resultado);
}
and pass an instance of that to getComando(). Then instead of just setting IVRecognition.resultado in onActivityResult(), you could call onRecognitionComplete() to notify the caller of the result.

Accessing an Instance's Variable from another Activity - Android Developement

I have creted a program that has 3 Activities: MainActivity, UpgradeActivity and UpgradesActivity.
Main Activity contains a timer and it also contains an instance of a Vehicle class.
public class MainActivity extends Activity {
TextView vehicleSpeed, vehicleName, vehicleDistance, vehicleLocation,
vehicleStatus, vehicleNews, vehicleInfo, vehicleMoney;
ProgressBar vehicleFuel;
public static Vehicle vehicle;
boolean launched;
public static PartType selectedType;
Handler handler = new Handler();
I have a button in MainActivity, that when pressed will take me to a page where i can select which part of the vehicle i wish to upgrade. For example i select: Engine. The engine Button takes me to the Upgrade Activity. In this activity i can buy the upgrade which should be applied to the vehicle in MainActivity. For the purpose of this question, lets say it set vehicles speed to +3.
My question is in regards to how to access the vehicle instance inside the MainActivity from the UpgradeActivity. I've tried making the instance static but that didn't work. How do i gain access and how can i change the vehicles variables from the other activities.
Here is where i am making the instance:
#Override
protected void onCreate(Bundle savedInstanceState) {
this.selectedType = PartType.Antenna;
this.launched = false;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vehicle = new Vehicle();
vehicle.setupCar();
Here is where i am accessing the variable in Upgrades, it call the upgrade function inside of the Vehicle Class:
buyUp1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MainActivity.vehicle.upgradeEngine(MainActivity.vehicle.engineLvl + 1);
Intent activityChangeIntent = new Intent(UpgradesActivity.this, MainActivity.class);
UpgradesActivity.this.startActivity(activityChangeIntent);
}
});
And this is the function within the Vehicle Class:
public void upgradeEngine(int lvl) {
engineLvl += 3;
engine = parts.getEngine(lvl);
}
The vehicle Stores an integer called: EngineLvl. This determines what level the cars engine is. The level is incremented by +3 everytime the engine is updated.
The problem is that the engine level never changes. Even if i make the Vehicle instance and all of the variables within vehicle STATIC;
MAINACTIVITY:
Vehicle
Button to UpgradesActivity
UPGRADESACTIVITY:
Button to UpgradeActivity
UPGRADEACTIVITY:
Change vehicle enginelvl Int
Button back to MainActivity
Main>Upgrades>Upgrade
Thank you for your time
Hard to say what is wrong without seeing the code, but I would advise you to use the Intent extras to move your data between activities. You will need to make your Vehicle class implement Parcelable (there is an example of how to implement Parcelable on that page, and countless others on the net). You pass your object as extra to the intent launching your UpgradeActivity like this :
Intent upgradeIntent = new Intent(this, UpgradeActivity.class);
upgradeIntent.putExtra("com.example.model.Vehicle", yourVehicleObject);
startActivityForResult(upgradeIntent, UPGRADE_CAR_REQUEST_CODE);
//UPGRADE_CAR_REQUEST_CODE is a unique private static final int
Then you can retrieve it in your UpgradeActivity onCreate method :
Intent intent = getIntent();
Vehicle vehicleFromLastActivity = intent.getParcelableExtra("com.example.model.Vehicle");
Before going back to your MainActivity you do something like this :
Intent dataIntent = new Intent();
dataIntent.putExtra("com.example.model.Vehicle", yourModifiedVehicleObject);
setResult(RESULT_OK, dataIntent);
finish();
Then finally in MainActivity you need to handle the result, it is done like this :
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case UPGRADE_CAR_REQUEST_CODE:
if(resultCode == android.app.Activity.RESULT_OK) {
Vehicle modifiedObject = data.getParcelableExtra("com.example.model.Vehicle");
// Now you can use that object which is coming from UpgradeActivity
}
}
}
Of course this could cause issues if your Vehicle class takes a lot of memory. You could then consider passing only the relevant information through the Intent to rebuild the object in the UpgradeVehicle Activity, for example only the id & name.

Categories

Resources