I created a list view that uploads files from sd card to and attaches it within the list. Yet I back out of the activity and onDestroyed gets called and I lose all my data from my listView. I am using An ArrayList FileUploaded and adapter to upload the files but I am confused on how I can implement that on "onSavedInstanceState" method.
I've done research but I am still having some issues.
Am I storing the wrong Items?
Please help... any advice at all.
My Variables:
ListView Added_Files;
Button Select_File;
Button Add_To_List;
Button Save_Button;
Button Add_To_DropBox;
TextView selectedFile;
MediaPlayer mediaPlayer;
ArrayList<Uri> FileUpload = new ArrayList<Uri>();
ArrayAdapter adapter;
//method that adds the file to listView when button "Upload to List" is clicked
public void addList(){
adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1,FileUpload);
Add_To_List.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Added_Files.setAdapter(adapter);
adapter.add(uri.getPath());
((BaseAdapter) Added_Files.getAdapter()).notifyDataSetChanged();
selectedFile.setText("");
Make_File_Empty();
// Toast.makeText(AddFiles.this, "File Added", Toast.LENGTH_SHORT).show();
}
});
}
Here is the method when file on sd card is selected and displays it on the screen
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE:
//If file selection was successfull
if (resultCode == RESULT_OK) {
if (data != null) {
//get uri of the selected file
uri = data.getData();
Log.i(TAG, "Uri = " + uri.toString());
try {
//get file path from Uri
// Toast.makeText(AddFiles.this, "File Selected: " + uri.getPath(), Toast.LENGTH_SHORT).show();
selectedFile.setText("Selected File: " + uri.getPath());
addList();
} catch (Exception e) {
Log.e("FileSelectorActivity", "File select error", e);
}
super.onActivityResult(requestCode, resultCode, data);
}
}
}
}
Lastly, the onSaved/restore methods:
#Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
outState.putStringArrayList("key",FileUpload );
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
FileUpload = savedInstanceState.getStringArrayList("key");
}
Take a careful look at this article: https://developer.android.com/guide/components/activities/activity-lifecycle#save-simple-lightweight-ui-state-using-onsaveinstancestate
It looks like in onSaveInstanceState you're saving your state after calling super, which might cause the data to not get saved. You also might want to save and restore the text in your TextView so it's shown when the UI is restored.
Another thing to note is what it says here:Note: onSaveInstanceState() is not called when the user explicitly closes the activity or in other cases when finish()is called.
Saving state is only intended to save data in short term situations (the example saves it before calling super), if you want to save it for longer (between app launches) you might want to use a SQLite database which is a lot more complicated.
I'm not an expert at this stuff specifically but hope this helped! I'd recommend setting breakpoints in onSaveInstanceState and onRestoreInstanceState to see what is being called when if you're still having trouble.
Related
I'm making an app where it uses intent to send data to another app. In case, the other app, which is supposed to receive data from my app, is not installed on users's device then it redirects user to play store with toast message asking user to install it. I used "if else" to achieve this. It worked all good until I found that if the other app is disabled by user (OEM installed app which can't be uninstalled), then my app crashes. In such a condition, I want to let user know that the app is disabled by them and ask them to enable it (through toast message). How can I achieve this?
Here is my complete code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Creates button view which is connected to a view in the XML layout, which gets triggered on touching the view.
TextView textView = (TextView) findViewById(R.id.location);
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Use package name which we want to check
boolean isAppInstalled = appInstalledOrNot("com.google.android.apps.maps");
if(isAppInstalled){
Uri gmmIntentUri = Uri.parse("geo:00,0000,00,0000");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
mapIntent.setPackage("com.google.android.apps.maps");
startActivity(mapIntent);
} else {
Uri uri2 = Uri.parse("market://details?id=com.google.android.apps.maps");
Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri2);
Toast.makeText(MainActivity.this, "Google Maps not Installed", Toast.LENGTH_SHORT).show();
startActivity(goToMarket);
}
}
});
}
private boolean appInstalledOrNot(String uri) {
PackageManager pm = getPackageManager();
try {
pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
return true;
} catch (PackageManager.NameNotFoundException e) {
}
return false;
}
}
I'm not sure if this will work for you, but since you know the package name, you could try this to do a check beforehand.
This question already has answers here:
How to manage startActivityForResult on Android
(14 answers)
Closed 3 years ago.
I am using both an ImagePicker and a barcode reader in a single activity. The main problem is that both of these require onActivityResult() to display the result. As we know a single activity can only have a single onActivityResult() method in it. How can I display both of them?
I have tried using switch cases to assign multiple requestCodes in the onActivityResult() but can't seem to figure out the solution.
Here's the method I tried.
public class MainActivity extends AppCompatActivity{
private TextView mIdentificationNumber;
private IntentIntegrator scanQR;
//Authentication For Firebase.
private FirebaseAuth mAuth;
//Toolbar
private Toolbar mToolBar;
private DatabaseReference mUserRef;
private ImageView mAssetImg;
private EditText massetName, massetModel, massetBarcode, massetArea, massetDescription;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Getting the Present instance of the FireBase Authentication
mAuth = FirebaseAuth.getInstance();
//Finding The Toolbar with it's unique Id.
mToolBar = (Toolbar) findViewById(R.id.main_page_toolbar);
//Setting Up the ToolBar in The ActionBar.
setSupportActionBar(mToolBar);
if (mAuth.getCurrentUser() != null){
mUserRef = FirebaseDatabase.getInstance().getReference().child("Users")
.child(mAuth.getCurrentUser().getUid());
mUserRef.keepSynced(true);
}
massetBarcode = (EditText) findViewById(R.id.BarcodeAsset);
scanQR = new IntentIntegrator(this);
massetBarcode.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
scanQR.initiateScan();
}
});
mAssetImg = (ImageView) findViewById(R.id.asset_img);
mAssetImg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getImage();
}
});
}
//OnStart Method is started when the Authentication Starts.
#Override
public void onStart() {
super.onStart();
// Check if user is signed in (non-null).
FirebaseUser currentUser = mAuth.getCurrentUser();
if (currentUser == null){
startUser();
} else {
mUserRef.child("online").setValue("true");
Log.d("STARTING THE ACTIVITY" , "TRUE");
}
}
#Override
protected void onPause() {
super.onPause();
FirebaseUser currentUser = mAuth.getCurrentUser();
if (currentUser != null){
mUserRef.child("online").setValue(ServerValue.TIMESTAMP);
Log.d("STOPPING THE ACTIVITY" , "TRUE");
}
}
private void startUser() {
//Sending the user in the StartActivity If the User Is Not Logged In.
Intent startIntent = new Intent(MainActivity.this , AuthenticationActivity.class);
startActivity(startIntent);
//Finishing Up The Intent So the User Can't Go Back To MainActivity Without LoggingIn.
finish();
}
//Setting The Menu Options In The AppBarLayout.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
//Inflating the Menu with the Unique R.menu.Id.
getMenuInflater().inflate(R.menu.main_menu , menu);
return true;
}
//Setting the Individual Item In The Menu.(Logout Button)
#Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
if (item.getItemId() == R.id.main_logout_btn){
FirebaseAuth.getInstance().signOut();
startUser();
}
return true;
}
private void getImage() {
ImagePicker.Companion.with(this)
.crop() //Crop image(Optional), Check Customization for more option
.compress(1024) //Final image size will be less than 1 MB(Optional)
.maxResultSize(1080, 1080) //Final image resolution will be less than 1080 x 1080(Optional)
.start();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 0:
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if (result != null) {
if (result.getContents() == null) {
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
} else {
massetBarcode.setText(result.getContents());
Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();
}
}
break;
case 1:
if (resultCode == Activity.RESULT_OK) {
assert data != null;
Uri imageURI = data.getData();
mAssetImg.setImageURI(imageURI);
}
break;
}
}
}
The rest of the answers told to use startActivityForResult() but that method requires Intent to go from one activity to another but I don't want to do this.
In both cases, the libraries you're using provide a way to specify a request code so you can distinguish the results in onActivityResult.
Your scanQR object should set a request code, per the source code:
massetBarcode.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
scanQR.setRequestCode(123).initiateScan();
}
});
You getImage() method should also specify a request code, again, per the library's source code.
private void getImage() {
ImagePicker.Companion.with(this)
.crop() //Crop image(Optional), Check Customization for more option
.compress(1024) //Final image size will be less than 1 MB(Optional)
.maxResultSize(1080, 1080) //Final image resolution will be less than 1080 x 1080(Optional)
.start(456); // Start with request code
}
Now, you can handle each request code as needed:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 123:
// HANDLE BARCODE
break;
case 456:
// HANDLE IMAGE
break;
}
}
Closing thought: I've never used either library. I found the solution by 1) assuming any library that provides an Activity you're supposed to invoke for a result would allow you to specify a request code for it and 2) looking through their documentation and source code for how to do that.
I'd encourage you to thoroughly study the documentation and source code for any open source library you intend to use since as soon as you do their code become your code and their bugs become your bugs, so you better know how to fix or workaround them.
Hope that helps!
In order to get results from fragments to your Activity, you can use an Interface to enable communication between them.
StartActivityForResult is used to start an activity and get a result back from it.
Please read more about it from here.
The startActivityForResult methos can use a second argument, a number so you can distinguish the resul
startActivityForResul(intent, 8)
You dont need to set the code back in the other activity, that is handled under the hood. So you probabbly want to add the number as a contant
private static final CAMERA_INTENT = 2
And then use it like this
startActivityForResul(intent, CAMERA_INTENT)
Finally in the onActivityResult implements the case basis
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (CAMERA_INTENT == requestCode) {
//DO PHOTO STUFF
}
}
The argument you need to eval is requestCode
I have 2 activities ,activity A is having webview and activity B is having button with transparent layout. I want close the activity B and refresh or do something in activity A when I press button from activity B.
I tried shared preferences but that not working without restarting activity A.
Have a look at the docs for Getting a Result from an Activity
Updated to include example
static final int PICK_CONTACT_REQUEST = 1; // The request code
...
private void pickContact() {
Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts"));
pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers
startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request we're responding to
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// The user picked a contact.
// The Intent's data Uri identifies which contact was selected.
// Do something with the contact here (bigger example below)
}
}
}
create a method as refreshmethod in Activity A and call it from Activity B something like this:
ActivityA activitya:
//stuff
activitya = new ActivityA();
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
activitya.refreshmethod();
}
});
hope it helps.
Further to my previous post, I now want to invoke a child activity from the main activity a number of times. In my real project (as opposed to the noddy test below), when the child activity is invoked, its header displays, "Enter first data set" then invites the user to enter some data. This data is actually stored in a common class rather than being returned to the main activity. Then the child needs to be called again with a new prompt "Enter second data set", and the same thing happens.
What I cannot work out is how to do this. If I include two calls to the child, every time, only the second call appears to happen, the prompt appearing in the child activity being "Enter second data set" every time. This startActivityForResult() method is I believe, designed to be used when you want to call an activity and wait for the result (which you do with an onActivityResult() do you not), but it does not wait.
How on earth do I do this? Sample code follows.
Thank you to anyone who can clearly explain where I'm going wrong and what the right code should be.
MainActivity code extract
#Override
public void onResume(){
super.onResume();
TextView maintop = (TextView)findViewById(R.id.maintop);
maintop.setText(Common.mess1);
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button mainbutton = (Button)findViewById(R.id.mainbutton);
mainbutton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
Intent intent1 = new Intent(MainActivity.this,Child.class);
intent1.putExtra("Prompt", "Enter first data set");
startActivityForResult(intent1,1);
onActivityResult(1,1,intent1);
}
});
mainbutton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
Intent intent2 = new Intent(MainActivity.this,Child.class);
intent2.putExtra("Prompt", "Enter second data set");
startActivityForResult(intent2,1);
onActivityResult(1,1,intent2);
}
});
}
You can only have one click listener in the button, so when you call set for the 2nd time it replaces the listener.
What you need to do is set the click listener for the enter first data, don't call to onActivityResult(1,1,intent1) that's not how you do it, you need override the method, and in onActivityResult call the 2nd.
Something like this:
static final int FIRST_INTENT = 1;
static final int SECOND_INTENT = 2;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button mainbutton = (Button)findViewById(R.id.mainbutton);
mainbutton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
Intent intent1 = new Intent(MainActivity.this,Child.class);
intent1.putExtra("Prompt", "Enter first data set");
startActivityForResult(intent1,FIRST_INTENT);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == FIRST_INTENT) {
if (resultCode == RESULT_OK) {
Intent intent2 = new Intent(MainActivity.this,Child.class);
intent2.putExtra("Prompt", "Enter second data set");
startActivityForResult(intent2,SECOND_INTENT);
}
}
}
And in your child activity
//DO SOMETHING
....
setResult(RESULT_OK)
finish();
}
For more check
[http://developer.android.com/intl/es/training/basics/intents/result.html]
[http://developer.android.com/intl/es/reference/android/app/Activity.html#setResult%28int%29]
I am creating a simple note-taking app for my independent study. The problem is that any time the app is exited, the notes created are deleted and the app is completely reset. I have read several tutorials of preferences and the saveoninstance methods, but no matter how many different ways I try to implement them, I can't seem to figure it out.
public class Home extends Activity {
//Declaration of variables
private Button mNoteButton;
private String mText;
private ListView myList;
private int index;
public static final String TAG = Note.class.getSimpleName();
ArrayList<String> myArrayList= new ArrayList<String>();
ArrayAdapter<String> myAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
//Setting the list item to blank
if (mText == null) {
mText = "";
}
Log.d(TAG, mText);
//creating adapter to insert myListArray into the ListView
myAdapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,myArrayList);
//Setting the adapter to myArrayList
myList= (ListView) findViewById(R.id.noteList);
myList.setAdapter(myAdapter);
//Creating and setting the new note button
mNoteButton = (Button)findViewById(R.id.newNoteButton);
//When button is clicked
mNoteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
newNote();
}
});
//When an item in the list is clicked
myList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//Taking the data in the item selected and sending it to the EditNote.java
index = position;
//Selecting item data
String old = myArrayList.get(index);
Intent intent = new Intent(Home.this, EditNote.class);
intent.putExtra("note_text", old);
startActivityForResult(intent, 1);
}
});
}
private void newNote()
{
//Starts and sends data to Note.java and creates a new note
Intent intent = new Intent(this, Note.class);
startActivityForResult(intent, 0);
}
protected void onActivityResult(int requestCode, int resultCode, Intent DATA) {
super.onActivityResult(requestCode, resultCode, DATA);
//Data from the Note activity is received
if (requestCode == 1 && resultCode == RESULT_OK)
{
//Gets data and saves it to myListArray as new edit
Bundle save = DATA.getExtras();
String extra = save.getString("note");
myArrayList.set(index, extra);
myList.setAdapter(myAdapter);
}
if (requestCode == 0 && resultCode == RESULT_OK) {
//Gets data and saves it to myListArray as new note
Bundle pack = DATA.getExtras();
String pageText = pack.getString("note");
myArrayList.add(pageText);
myList.setAdapter(myAdapter);
}
This is the code without saving the collected strings. Can someone please help me figure out how to implement one of the methods to save this data so it can be retrieved after the app is destroyed?
One option is to write the string as a file to internal storage:
http://developer.android.com/guide/topics/data/data-storage.html#filesInternal
String FILENAME = "yourFileName";
String extra = save.getString("note");
FileOutputStream fileOutputStream = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fileOutputStream.write(extra.getBytes());
fileOutputStream.close();
Also of course you are going to have to read in the file when you open your app, in order to set any notes that were previously saved:
Call openFileInput() and pass it the name of the file to read. This returns a FileInputStream.
Read bytes from the file with read().
Then close the stream with close().
You might find this info helpful on converting a fileInputStream to a string:
How to convert FileInputStream into string in java?