I've ran into an infuriating issue with my Android development- whenever I call startActivityForResult(this, Notepadv3.class);, my app skipps directly over it, not launching the new activity nor returning any result from it. It's as if the code wasn't there!
When I change this to mContext (I have defined mContext as Context mContext; in the beginning of the class), the app crashes with a NullPointerException.
I have used the exact same code layout in a different class, and it runs flawlessly.
I've verified that I'm properly declaring the activities in the Manifest.
I've spent hours searching stackoverflow for answers, as well as looking up countless examples of how to do this particular activity, to no avail. I'm in the process of learning how to write Android apps, and as such have used Google's Notepad tutorial to base my app on. Thanks for the much appreciated assistance in advance!
Code and stack trace is as follows:
NoteEdit.java: (I've skimmed some irrelevant code for readability's sake)
public class NoteEdit extends Activity implements OnClickListener {
Context mContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDbHelper = new NotesDbAdapter(this);
mDbHelper.open();
setContentView(R.layout.note_edit);
setTitle(R.string.edit_item);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == REQUEST_BARCODE) {
if (resultCode == RESULT_OK) {
barcode = (intent.getStringExtra("SCAN_RESULT"));
new updateBarcodeField().execute("");
} else if (resultCode == RESULT_CANCELED) {
}
}else if (requestCode == REQUEST_NEW) {
System.out.println("REQUEST_NEW onActivityResult().");
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveState();
outState.putSerializable(NotesDbAdapter.KEY_ROWID, mRowId);
}
#Override
protected void onPause() {
super.onPause();
saveState();
}
private void saveState(){
System.out.println("saveState()");
doorCall();
mDbHelper.open();
String title = mTitleText.getText().toString();
String barcode = mBarcodeText.getText().toString();
String price = mPriceText.getText().toString();
Intent requestNew = new Intent(mContext, Notepadv3.class);
if (returnCode == 1){
System.out.println("returnCode is 1. Calling validateFields()...");
String errors = validateFields(title);
if (errors.length() > 0) {
Toast.makeText(this, "Oops! Need a title!", duration).show();
System.out.println("Calling Notepadv3...");
startActivityForResult(requestNew, REQUEST_NEW);
}
}
if (returnCode == 2){
System.out.println("returnCode == 2 - Cancelling activity");
}else{
if (title.matches("")){
System.out.println("Variable is null. Returning...");
doorCall();
mDbHelper.close();
return;
}else{
System.out.println("Checking mRowId for null");
if (mRowId == null) {
Toast.makeText(this, "Success, product saved successfully", duration).show();
System.out.println("Switching activity to 'NotesDbAdapter'");
long id = mDbHelper.createNote(title, barcode, price);
mRowId = id;
}else{
System.out.println("mRowId is not null. Calling updateNote");
mDbHelper.updateNote(mRowId, title, barcode, price);
}
}
}
System.out.println("saveState() Finished");
if (doorCall()==true){
System.out.println("Database is Open");
}else{
System.out.println("Database is Closed");
}
}
}
Notepadv3.java:
public class Notepadv3 extends ListActivity implements OnClickListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notes_list);
mDbHelper = new NotesDbAdapter(this);
mDbHelper.open();
mAddButton = (Button) findViewById(R.id.addButton);
mAddButton.setOnClickListener(this);
mScanButton = (Button) findViewById(R.id.scanButtonList);
mScanButton.setOnClickListener(this);
fillData();
registerForContextMenu(getListView());
}
#SuppressWarnings("deprecation")
private void fillData() {
Cursor notesCursor = mDbHelper.fetchAllNotes();
startManagingCursor(notesCursor);
// Create an array to specify the fields we want to display in the list (only TITLE)
String[] from = new String[]{NotesDbAdapter.KEY_TITLE, NotesDbAdapter.KEY_PRICE};
// and an array of the fields we want to bind those fields to (in this case just text1)
int[] to = new int[]{R.id.text1, R.id.text2};
// Now create a simple cursor adapter and set it to display
SimpleCursorAdapter notes =
new SimpleCursorAdapter(this, R.layout.notes_row, notesCursor, from, to);
setListAdapter(notes);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.addButton:
createNote();
break;
case R.id.scanButtonList:
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
intent.putExtra("SCAN_MODE", "ONE_D_MODE");
startActivityForResult(intent, REQUEST_BARCODE);
}
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
switch(item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
mDbHelper.deleteNote(info.id);
fillData();
return true;
}
return super.onContextItemSelected(item);
}
public void createNote() {
Intent i = new Intent(this, NoteEdit.class);
startActivityForResult(i, ACTIVITY_CREATE);
}
private void viewNote() {
System.out.println("viewNote(). Starting NoteEdit...");
Intent i = new Intent(this, NoteView.class);
i.putExtra(NotesDbAdapter.KEY_BARCODE, barcode);
startActivityForResult(i, ACTIVITY_EDIT);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Intent i = new Intent(this, NoteEdit.class);
i.putExtra(NotesDbAdapter.KEY_ROWID, id);
startActivityForResult(i, ACTIVITY_EDIT);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
System.out.println("Notepadv3. requestCode is " + requestCode + ", and resultCode is " + resultCode);
if (requestCode == REQUEST_BARCODE) {
if (resultCode == RESULT_OK) {
barcode = (intent.getStringExtra("SCAN_RESULT"));
System.out.println("Calling viewNote()...");
viewNote();
} else if (resultCode == RESULT_CANCELED) {
} else if (resultCode == RESULT_FIRST_USER) {
}
}else if (requestCode == REQUEST_NEW){
System.out.println("Notepadv3. requestCode is REQUEST_NEW. Calling createNote()...");
createNote();
}
super.onActivityResult(requestCode, resultCode, intent);
fillData();
}
}
Stack trace:
FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to pause activity {com.android.demo.notepad3/com.android.demo.notepad3.NoteEdit}: java.lang.NullPointerException
at android.app.ActivityThread.performPauseActivity(ActivityThread.java:2706)
at android.app.ActivityThread.performPauseActivity(ActivityThread.java:2662)
at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:2640)
at android.app.ActivityThread.access$800(ActivityThread.java:123)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1158)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at android.content.ComponentName.<init>(ComponentName.java:75)
at android.content.Intent.<init>(Intent.java:3148)
at com.android.demo.notepad3.NoteEdit.saveState(NoteEdit.java:206)
at com.android.demo.notepad3.NoteEdit.onPause(NoteEdit.java:187)
at android.app.Activity.performPause(Activity.java:4590)
at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1195)
at android.app.ActivityThread.performPauseActivity(ActivityThread.java:2693)
First of all, if you use mContext, you should initialize it in the onCreate method:
mContext=getApplicationContext();
//I recommend using the application context for avoiding memory leaks
Don't start an Activity from the onPause method.
I fixed it!!!
This won't be a fix for most that are looking for answers, but I hope I can point you in the right direction. As new as I am to Android (and Java in general), I am still totally convinced that this 'skipping' of code is, in fact, a bug.
However! As I'm calling saveState() from another activity, instead of launching a new intent that launches an activity from a separate class, which then launches an activity from the class where the first intent originated from, I simply replaced it with return;. Yeah- still quite derpy with learning the logic, but there it is. Simple, elegant, solution (well, simple and elegant compared to the horrendous code that existed before it :P)
Related
I have implemented FragmentStatePagerSupport. I have 142 pages. I have also an activity that is MyListActivity and has ListView. When I click ListView item, it returns a page number. I want to use this page number for viewPager current page. viewPager.setCurrentItem() doesn't work in onActivityResult.
Here is how I call startActivityForResult:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu1:
Intent intent = new Intent(this, MyListActivity.class);
startActivityForResult(icindekiler, 0);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
And here is the listView of MyListActivity:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ListViewContent selectedItem = (ListViewContent) parent.getItemAtPosition(position);
int pageNo = book.getSpine().getResourceIndex(selectedItem.getResource().getHref());
Intent data = new Intent();
data.putExtra("PageNo", pageNo); // pageNo: 0 or 1 or 2 or ... or 142
setResult(0, data);
finish();
}
});
onActivityResult method in FragmentPageStateSupport activity:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0 && resultCode == 0) {
if (data.hasExtra("PageNo")) {
pageNo = data.getExtras().getInt("PageNo");
Toast.makeText(getBaseContext(), "pageNo is " + pageNo, Toast.LENGTH_SHORT).show();
viewPager.setCurrentItem(pageNo);
}
}
}
For example pageNo is 11, Toast says "pageNo is 11" but viewPager doesn't change. When I use debugging in Android Studio, application runs Looper.java. I try viewPager.setCurrentItem(11) on different method (for example button click), this time it is working.
I have a Fragment in a Viewpager.
I am opening a DialogFragment from it which is taking the data from a ParseQuery. So far so good. Toast the clicked item also works.
I am trying to setText for a TextView in the Fragment that the dialog is called from without success... Anything i try just doesn't work - Intent, Bundle nothing... Going crazy with it already :)
I am not familiar with Interface and Callbacks, if that is needed. I don't know...
Thanks a lot in advance for any answer!!
Want to mention that i am not an advanced programmer, so any detailed explanation will be blessed :)
Here is the DialogFragment code - what i am trying to take from it and set to the TextView is pType.get(position).toString()
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ParseQuery<PropertyTypes> query = ParseQuery.getQuery(PropertyTypes.class);
query.whereExists("propertyType");
query.findInBackground(new FindCallback<PropertyTypes>() {
#Override
public void done(final List<PropertyTypes> pObjects, ParseException e) {
if (e == null) {
final ArrayList<String> pType = new ArrayList<String>();
for (PropertyTypes j : pObjects) {
pType.add(j.getTypeName());
}
ArrayAdapter arrayAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, pType);
mylist.setAdapter(arrayAdapter);
mylist.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
getDialog().dismiss();
Toast.makeText(getActivity(), pType.get(position).toString() + " was clicked", Toast.LENGTH_LONG).show();
// Intent...?
// Bundle...?
}
});
} else {
e.printStackTrace();
}
}
});
}
You can make use of setTargetFragment() method for this. For example, use setTargetFragment() while calling your Dialog Fragment
DialogFragment dialogFragment = new DialogFragment();
dialogFragment.setTargetFragment(this, REQUEST_CODE);
dialogFragment.show();
and on your onItemClick() inside DialogFragment do this
mylist.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
dismiss();
Toast.makeText(getActivity(), pType.get(position).toString() + " was clicked", Toast.LENGTH_LONG).show();
Intent intent = new Intent();
intent.putStringExtra("yourKey", yourStringValue);
getTargetFragment().onActivityResult(
getTargetRequestCode(), Activity.RESULT_OK, intent);
}
});
and you can get that string value in your onActivityResult() of your calling/target Fragment
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(requestCode) {
case REQUEST_CODE:
if (resultCode == Activity.RESULT_OK) {
if(data!=null){
// set value to your TextView
textView.setText(data.getStringExtra("yourKey"));
}
}
break;
}
}
}
Hope this will help.
I am confused and have no idea on how to use the startActivityResults and setResults to get data from previous activity. I have a view class and a activity class.
Basically in my view class i have this dialog and it will actually start the activity class called the colorActivity class. When user selects yes also it will pass the name of the selected circle to the colorActivity class. At the colorActivity class, users are allowed to enter color code for a particular circle and i would like to pass the color code back to the view class. I have problems passing values from activity back to view using the startActivityForResult and setResult method. Adding on, how to make use of the fetched data afterthat?
my code are as follows
Ontouchevent code from my view class:
#Override
public boolean onTouchEvent(MotionEvent event) {
x = event.getX();
y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
for (int i = 0; i < circles.size(); i++) {
if (circles.get(i).contains(x, y)) {
circleID = i;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
AlertDialog.Builder builder = new Builder(
getContext());
final EditText text = new EditText(getContext());
builder.setTitle("Adding colors to circles").setMessage(
"Proceed to Enter color");
builder.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface di,
int i) {
Intent intent = new Intent(
getContext(),
colorActivity.class);
intent.putExtra("circlename", circleNameList.get(circleID));
startActivityForResults(intent, 1); // error incurred here : The method startActivityForResult(Intent, int) is undefined for the type new DialogInterface.OnClickListener(){}
}
});
builder.setNegativeButton("No",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface di,
int i) {
}
});
builder.create().show();
}
}, 3000);
break;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) { // Please, use a final int instead of hardcoded
// int value
if (resultCode == RESULT_OK) {
ccode = (String) data.getExtras().getString("colorcode");
}
}
}
public static String getColorCode() {
return ccode;
}
In the colorActivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_ecolor);
circlenametextview = (TextView)findViewById(R.id.circlenametextview);
String circlename = super.getIntent().getStringExtra("circlename");
circlenametextview.setText(circlename);//get the circle name
savebutton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent = new Intent(colorActivity.this, ?????);//how to return back to the view class?
colorcode = colorEditText.getText().toString();// I am able to get value right up till this point
Intent resultIntent = new Intent();
resultIntent.putExtra("colorcode", colorcode );
setResult(Activity.RESULT_OK, resultIntent);
finish();
}// onclick
});
}
After correcting the other code so that you can run the program, you can retrieve parameters back from your activity colorActivity in this way:
Step1: return some value from colorActivity
Intent resultIntent = new Intent();
resultIntent.putExtra("NAME OF THE PARAMETER", valueOfParameter);
...
setResult(Activity.RESULT_OK, resultIntent);
finish();
Step 2: collect data from the Main Activity
Overriding #onActivityResult(...).
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) { // Please, use a final int instead of hardcoded int value
if (resultCode == RESULT_OK) {
String value = (String) data.getExtras().getString("NAME OF THE PARAMETER");
References
http://developer.android.com/training/basics/intents/result.html
How to manage `startActivityForResult` on Android?
http://steveliles.github.io/returning_a_result_from_an_android_activity.html
STARTACTIVITYFORRESULT IS NOW DEPRECATED
Alternative to it and recommended solution is to use Activity Result API
You can use this code, written in Kotlin language:
Create ResultLauncher:
private var resultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
if (null != data && data.getBooleanExtra("REFRESH_PAGE", false)) {
//do your code here
}
}
}
start Activity by using above result launcher:
val intent = Intent(this, XYZActivity::class.java)
resultLauncher.launch(intent)
Return result from XYZActivity by
val resultIntent = Intent()
resultIntent.putExtra("REFRESH_PAGE", true)
setResult(Activity.RESULT_OK, resultIntent)
finish()
try using
ActivityName.this.startActivityForResult(intent,int)
Oh, and 1 small thing, in your code you have used
startActivityForResults(intent,int) ..replace that with
startActivityForResult(intent,int)
In my app I get a Force Close, and I don't know how to solve this. The problem is that I have a class that extends ListActivity. In this class there is a list of shops, and the user should select one of the shops. If he not select a shop and press button Back I get Force Close, because the previous class expect the name of the shop. How can I catch this error?
Here is my class for selecting a shop :
public class SelectShop extends ListActivity {
private ListView lv1;
SimpleCursorAdapter adapter = null;
Cursor cursor;
DbAdapter db;
ImageView iconshop;
private static final int ADD=Menu.FIRST;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.shopselect);
iconshop = (ImageView) findViewById(R.id.iconshop);
lv1 = getListView();
DbApplication myApplication = (DbApplication) this.getApplication();
db= myApplication.getDatabaseAdapter();
cursor = db.getAllShops();
startManagingCursor(cursor);
if (cursor != null && cursor.moveToFirst()){
adapter = new SimpleCursorAdapter(this, R.layout.shopsrow, cursor,
new String[] { DbAdapter.NAME, DbAdapter.ADRESS }, new int[] {
R.id.title, R.id.address });
setListAdapter(adapter);
}else Toast.makeText(this,
"Choose Menu for adding a shop",
Toast.LENGTH_LONG).show();
lv1.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Intent j = new Intent(SelectShop.this,
com.ShoppingList.NewList.class);
Cursor c = (Cursor) parent.getAdapter().getItem(position);
j.putExtra("shop", c.getString(c.getColumnIndex(db.NAME)));
setResult(RESULT_OK, j);
finish();
}
});
}
/*Adaugarea meniului Add Shop*/
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, ADD, 0, "Add Shop").setIcon(R.drawable.additem);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case ADD:
Intent j = new Intent(SelectShop.this, Shops.class);
startActivityForResult(j, 0);
return true;
}
return false;
}
}
and in previuos class I have this:
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
switch (requestCode) {
case 0: {
Bundle b = intent.getExtras();
shopselect = b.getString("shop");
shop.setText(shopselect);
}
break;
}
}
You have to check the null condition in onActivityResult like below.
if(b != null)
{
shopselect = b.getString("shop"); shop.setText(shopselect);
}
I think you need to implement a mechanism that won't let your user get back to previous activity without choosing any item in the list. Override your onKeyDown() method, and when the user presses Back key you should check whether any item is chosen. If it's not you can throw an alert dialog to inform user what he must do to proceed. Hope this helps!
Check the result code. do your thing only if the result code is Activity.RESULT_OK.
I'm venturing into startActivityForResult for the first time and I'm running into a problem.
Activity A (ActivityMyList) launches Activity B (ActivityQuickList) waiting for a result:
Intent intentLaunchQuickList = new Intent(ActivityMyList.this, ActivityQuickList.class);
startActivityForResult(intentLaunchQuickList, REQUEST_QUICKLIST);
When a user clicks on a list item of Activity B, it returns "ql_id" to Activity A:
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
QuickListItem qlItem = m_Adapter.getItem(position);
if (qlItem != null && qlItem.getQLId() != -1) {
Intent data = new Intent();
data.putExtra("ql_id", Integer.toString(qlItem.getQLId()));
if (getParent() == null) {
setResult(Activity.RESULT_OK, data);
}
else {
getParent().setResult(Activity.RESULT_OK, data);
}
finish();
}
finish();
}
Integer.toString(qlItem.getQLId()) evaluates to "1". This is important because I am not receiving "1"...
I have overridden the onActivityResult handler in Activity A with this:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_QUICKLIST) {
if (resultCode == Activity.RESULT_OK) {
Bundle extras = data.getExtras();
if (extras != null) {
int id = extras.getInt("ql_id");
}
}
}
}
Unfortunately, extras.getInt("ql_id") evaluates to "0". Why is this? It should be "1". I am clearly doing something incorrectly.
Thank you for your help
Ah, nevermind. I'm putting a String into the bundle and pulling an int out.