Transfer an custom object from activity to activity with activity context? - java

Problem is a bit complex ,First of all both activity A and activity B activity B have android:noHistory = true in manifest. i have a custom serializable class suppose MyClass , that custom class is actually storing the context of the Activity B through constructor. And i have an object name obj in Activity B of type MyClass , Now i want to transfer this object to Activity C through intent when back button is pressed in Activity B.
From Activity A there is a button that open activity B without an issue, issue starts when i try to open activity C through B in onBackPressed(), with transferring serializable object . i am receiving NULL in Activity C.
[Updated] MyClass:
#SuppressWarnings("serial")
public class MyClass implements Serializable{
private final String SHAREDKEY_HIGHSCORE = "High Scores";
private final String FIELDKEY_HIGHSCORE = "HighScore";
private final String FIELDKEY_HIGHTIME = "HighTime";
private SharedPreferences sp;
private SharedPreferences.Editor spEditor;
public MyClass(Context context) {
resetScore();
sp = context.getSharedPreferences(SHAREDKEY_HIGHSCORE, Context.MODE_PRIVATE);
spEditor = sp.edit();
}
public void resetScore(){
newTime = 0;
newScore = 0;
highTime = 0;
highScore = 0;
}
}
Activity B:
public class ActivityB extends Activity {
MyClass scores;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
scores = new MyClass(this);
}
#Override
public void onBackPressed() {
Intent intent = new Intent(this, ActivityC.class);
in.putExtra("Scores", scores);
startActivity(intent);
}
}
Activity C:
public class ActivityC extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_c);
MyClass score = (MyClass) getIntent().getSerializableExtra("Scores");
//score is null here always
}
}
Manifest:
<activity
android:name=".ActivityA"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ActivityB"
android:noHistory="true">
</activity>
<activity android:name=".ActivityC">
How can receive my custom class in activity C successfully ? please help

the problem is clearly here // i have to store context of Activity B no matter what.
NO! You do not have to store context of Activity B. You're trying to do it, for the wrong reasons.
In Android you must never try to keep an activity for longer than its lifecycle, and you should never try to Serialize a Context. It just doesn't work like this and that's the reason it will not work.
I'm putting this as an answer (instead of a comment) because that's what is is.
The solution to your problem is: re-think the architecture of your app. There're several different correct ways to passing or sharing information through activities, but trying to hold to a context and serialize it, is not one of them.

According to the Android documentation, when you declare an Activity with noHistory, it will not stay in the Activities Stack.
Your problem is happening after your onBackPressed finishes. Your Activity B context is cleaned by the Android OS GC, so when Activity C is created the pointer you had to that context is pointing to a null location.
I suggest using another architecture to pass information between your activities. Try searching for "Android extending Application class" in google :)

I don't know what you're trying to achieve , but storing some Activity's Context is not gonna get you there. As #Budius stated , you should rethink what you're trying to do. The docs say about Context:
Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.
I don't see any reasons why one would need to keep and serialize it . Even if you need a "global" context , you can always call getApplication() inside your Activity.

Related

How can I find context and start a new Activity from Android firebase ML-Kit BarcodeScannerProcessor onSuccess

I am using the quickstart-android code provided by google but after many attempts I cam unable to find a context that is not returning null. The BarcodeScannerProcessor is not itself an Activity, so I have attempted to create an instance of the LivePreviewActivity and use that as the context in the intent, but it's null.
The goal is to once a valid barcode is recognized I want to open a new activity that allows a user to verify value and on the push of a button call a webservice to post the barcode to a database via API. I am having a hard time finding a valid context and the app is crashing when it trys to execute the Intent.
Starting at line 97-107:
https://github.com/jamiekeefer/quickstart-android/blob/master/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/barcodescanning/BarcodeScanningProcessor.java
for (int i = 0; i < barcodes.size(); ++i) {
FirebaseVisionBarcode barcode = barcodes.get(i);
BarcodeGraphic barcodeGraphic = new BarcodeGraphic(graphicOverlay, barcode);
graphicOverlay.add(barcodeGraphic);
System.out.println(barcode.getRawValue());
if (!barcode.getRawValue().equals("") ) {
System.out.println("Got the number:" + barcode.getRawValue() + " Context: " + mContext); //OLD SCHOOL DEBUG OUTPUT
//enter code to start activity
Intent intent = new Intent(mContext, SendScannedBarcode.class);
String message = scannedBarcode;
intent.putExtra(EXTRA_MESSAGE, message);
mContext.startActivity(intent);
}
}
You can back up in the repo to see the instance of the LivePreviewActivity where I trying to get context.
I have tried a number of things and read about Context, Views and Activities and basically have completely confused myself. The only tuts I can find are using Kotlin, which is not helping clarify things.
I appreacite any help in indentifying or contruting a valid Intent from this Context. Thank you.
So I am assuming that in your LivePreviewActivity you are creating an object of the class BarcodeScanningProcessor. What you can do is change the constructor in the BarcodeScanningProcessor class to accept a context and then you pass in your LivePreviewActivity's context.
This is what the code should look like:
In BarcodeScanningProcessor:
public BarcodeScanningProcessor(Context context) {
// Note that if you know which format of barcode your app is dealing with, detection will be
// faster to specify the supported barcode formats one by one, e.g.
// new FirebaseVisionBarcodeDetectorOptions.Builder()
// .setBarcodeFormats(FirebaseVisionBarcode.FORMAT_QR_CODE)
// .build();
detector = FirebaseVision.getInstance().getVisionBarcodeDetector();
this.mContext = context;
}
Then in LivePreviewActivity:
In the particular case of your activity you would do:
case BARCODE_DETECTION:
Log.i(TAG, "Using Barcode Detector Processor");
cameraSource.setMachineLearningFrameProcessor(new BarcodeScanningProcessor(getApplicationContext()));
break;
Or if you just wanted to create an object of the class you could do:
BarcodeScanningProcessor bsp = new BarcodeScanningProcessor(getApplicationContext());
This should now give your BarcodeScanningProcessor class the context of your activity. Now, in BarcodeScanningProcessor, mContext should not be null and will have the context of your activity. I hope this answers your question.
try this create Application class
import android.app.Application;
public class MyApplication extends Application {
static MyApplication instance;
#Override
public void onCreate() {
super.onCreate();
instance=this;
}
public static MyApplication getInstance() {
return instance;
}
}
Register in manifest file
<application
..
android:name="com.yourpackage.MyApplication"
..>
.
.
.
</application>
start activity using this MyApplication.
Intent intent = new Intent(MyApplication.getInstance(), SendScannedBarcode.class);
String message = scannedBarcode;
intent.putExtra(EXTRA_MESSAGE, message);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MyApplication. getInstance().startActivity(intent);
Another way of handling the issue is create new constructor of BarcodeScanningProcessor which takes interface call back and once processing is done pass back result to caller.
public interface BarcodeUpdateListener {
#UiThread
void onBarcodeDetected(Barcode barcode);
}
private BarcodeUpdateListener callback;
public BarcodeScanningProcessor(BarcodeUpdateListener callback){
this.callback = callback;
detector = FirebaseVision.getInstance().getVisionBarcodeDetector();
}
Once you get the result pass result to caller
callback.onBarcodeDetected(<Barcode>)
You can get the context from graphicOverlay:
Context context = graphicOverlay.getContext();

How can I go to second activity but send a data to another activity?

I made an application "Quiz", which has 4 activities. Main activity sends a String with your name from EditText to activity with first question. I have a problem here, because I don't know how to send this string immediately to final activity from main activity, but without going to final activity. I want to go to Activity with first question from main activity, then to activity with second question, and in the end I want to go to final activity.
Thanks for your help!
You could use static fields to pass data.
Inside your FinalActivity class you could add the following variable:
private static String NAME = "";
And with the following getters and setters:
public static String getName(){
return NAME;
}
public static void setName(String name){
NAME = name;
}
You can use the getter setter here at Application class so you can get the string data from anywhere were you want to. This is not the only way but i think it is also the easy way.
public class MyApplication extends Application {
private String someVariable;
public String getSomeVariable() {
return someVariable;
}
public void setSomeVariable(String someVariable) {
this.someVariable = someVariable;
}
}
add this in your manifest
<application
android:name=".MyApplication"
android:icon="#drawable/icon"
android:label="#string/app_name">
hen in your activities you can get and set the variable like so:
/ set
((MyApplication) this.getApplication()).setSomeVariable("foo");
// get
String s = ((MyApplication) this.getApplication()).getSomeVariable();
Some Url which may help you Android global variable
You can use shared preference also but as per our requirement i don't recommend that to you
Android Shared preferences example
You can use Broadcast Receiver for your requirement. In your activity from which you want to send data, do this way:
Intent intent = new Intent();
intent.setAction("fourthactivity");
sendBroadcast(intent);
And In your fourth activity, make a broadcast receiver which receive your intent :
public class IncomingReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("fourthactivity")) {
System.out.println("GOT THE INTENT");
}
}
}
Tell me if this doesn't work or click right if it works for you.
You can use SharedPreference to store the answers as you go from one activity to other and later compare all the answers in the FinalActivity in that way less complex coding and you will achieve your desired result.

Passing Data Between Activities in Android App

Hey I am pretty new to making android apps and I understand that the easiest way to pass data between two activities is through an intent.
In one of my classes (EventOptions.java), I call this line of code:
Intent i = new Intent(EventOptions.this, PhotoFetcher.class);
i.putExtra("imageArray", imageIDs);
startActivity(i);
imageIDs is a string array
In my PhotoFetcher class, I want to set a string array called imageIDs to the imageIDs string array that I am passing through the intent.
I want to set images as a global variable in my class:
public class MainActivity extends Activity implements View.OnClickListener{
Intent it = getIntent();
String[] imageIDs = it.getStringArrayExtra("imageArray");
...
}
This crashes my app however. Is this not allowed? And if so, how can I fix it? Thanks in advance!
Need to call getIntent() in a method instead of at class level. call it inside onCreate :
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// get Intent here
Intent it = getIntent();
String[] imageIDs = it.getStringArrayExtra("imageArray");
}
if I want to use the imageIDs array in another public class defined
in my PhotoFetcher class, do I need to call it again?
To get imageIDsin PhotoFetcher class either declare String[] imageIDs as global variable or pass imageIDs using PhotoFetcher class constructor
You have to use putStringArrayListExtra. You can convert your String[] to an ArrayList first.
Like so
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(imageIDs));
Intent i = new Intent(EventOptions.this, PhotoFetcher.class);
i.putStringArrayListExtra("imageArray", arrayList);
startActivity(i);
And then you can fetch it like you do, preferably in onCreate or after that call.
Intent it = getIntent();
ArrayList<String> imageIDs = it.getStringArrayListExtra("imageArray");
Share data without persisting to disk
It is possible to share data between activities by saving it in memory given that, in most cases, both activities run in the same process.
Note: sometimes, when the user leaves your activity (without quitting it), Android may decide to kill your application. In such scenario, I have experienced cases in which android attempts to launch the last activity using the intent provided before the app was killed. In this cases, data stored in a singleton (either yours or Application) will be gone and bad things could happen. To avoid such cases, you either persist objects to disk or check data before using it to make sure its valid.
Use a singleton class
Have a class to whole the data:
public class DataHolder {
private String data;
public String getData() {return data;}
public void setData(String data) {this.data = data;}
private static final DataHolder holder = new DataHolder();
public static DataHolder getInstance() {return holder;}
}
From the launched activity:
String data = DataHolder.getInstance().getData();
Use application singleton (I would recommend this)
The application singleton is an instance of android.app.Application which is created when the app is launched. You can provide a custom one by extending Application:
import android.app.Application;
public class MyApplication extends Application {
private String data;
public String getData() {return data;}
public void setData(String data) {this.data = data;}
}
Before launching the activity:
MyApplication app = (MyApplication) getApplicationContext();
app.setData(someData);
Then, from the launched activity:
MyApplication app = (MyApplication) getApplicationContext();
String data = app.getData();
ρяσѕρєя K hit the nail on the head, you're running a method where constructors and fields go. To make the variables (the imageIDs) global, it's quite simple and there are a few ways of doing it. Declare them outside any method, and then assign them in your onCreate or onResume (which will always be called).
Try this:
public class MainActivity extends Activity implements View.OnClickListener {
//global variable
String[] imageIDs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get Intent here
Intent it = getIntent();
imageIDs = it.getStringArrayExtra("imageArray");
}
}

Access same data through 3 different activities

I'm new to android development but I give my best.
I want to create an app for scoring a card game for 2 teams playing:
Activity1: Make your bid
Activity2: Evaluate the outcome of the game
Activity3: Show a list with the score of the teams (2 columns)
Start over with Activity1 until someone has won.
So I have activity1 passing data to activity2 (using putExtra with an intent)
Activity2 evaluated the bid and calculates the score of Team1 and Team2.
That data is being passed to activity3.
Here I would like to Show a list with the scores of every round.
But where / how do I save that list data when I move on to activity1 again?
I'm already playing around with a new class which should be extending the application but I do not know how to instantiate that class and how to make it accessible form each activity?
Here is my manifest.xml => extradata as a new class:
<application
android:allowBackup="true"
android:icon="#drawable/notrump"
android:label="#string/app_name"
android:theme="#style/AppTheme"
android:name="extradata">
<activity
This class is set up like this:
public class extradata extends Application{
public static ArrayList<scoredata> scoring = new ArrayList<scoredata>();
#Override
public void onCreate()
{
super.onCreate();
}
And the scoredata class looks like that:
public class scoredata {
private int mScoreteam1;
private int mScoreteam2;
private String mBidteam1;
private String mBidteam2;
public scoredata(int pScoreteam1, int pScoreteam2, String pBidteam1, String pBidteam2){
mScoreteam1 = pScoreteam1;
mScoreteam2 = pScoreteam2;
mBidteam1 = pBidteam1;
mBidteam2 = pBidteam2;
}
public int getScoreteam1(){
return mScoreteam1;
}
public int getScoreteam2(){
return mScoreteam2;
}
public String getBidteam1(){
return mBidteam1;
}
public String getBidteam2(){
return mBidteam2;
}
public void setScoreteam1(int pScoreteam1){
mScoreteam1 = pScoreteam1;
}
public void setScoreteam2(int pScoreteam2){
mScoreteam2 = pScoreteam2;
}
public void setBidteam1(String pBidteam1){
mBidteam1 = pBidteam1;
}
public void setBidteam2(String pBidteam2){
mBidteam2 = pBidteam2;
}
So do I now have an arraylist of scoredata created when the application starts?
And if so how do I access the fields or add an item from my activities?
If you just want to pass the new added values from activity2 to activity1 you can use intents.
Call second activity using startactivityforesult(intent,requestcode). After getting the new values pass the result from activity 2 using setresult().
use this link
Update your arraylist(i.e. add new item) in onActivityResult() function inside activity1.
Use adapter.setnotifychanged to make the updates reflect in listview.
You may want to implement a class as a datastore, and make it a singleton so each of your 3 activities can access the data and modify it.
I don't know if it's the best solution for your problem but it's a simple one.

First attempt to learn about Intent

I have a button on Main's android xml file which once clicked will display another view/activity.
My problem is the error message displays that the application must end unexpectedly.
Here is the button
<Button android:id="#+id/showmeurcode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="OnShowMeUrCode"
>
The method OnShowMeUrCode is defined in the MainActivity class as
private void OnShowMeUrCode(View btn)
{
Intent urCode=new Intent(this,CodePage.class);
startActivity(urCode);
}
CodePage is generated from a class of the same name
public class CodePage extends Activity
{
....
}
That is all I have done in the hope that I could accomplish the simple task with Intent to display another view but I run in an unexpected error and my program fails short.
You need to change your OnShowMeUrCode() function to be public, not private. Since it's part of the Activity class, your Button won't have access to it if it's private.
Plus it's in the docs:
http://developer.android.com/reference/android/widget/Button.html
Based on your code without the error log output, I guess you didn't pass a correct Context to the method.
This is your code:
private void OnShowMeUrCode(View btn)
{
Intent urCode=new Intent(this,CodePage.class);
startActivity(urCode);
}
Try replace the relevant line with:
Intent urCode=new Intent(MainActivity.this,CodePage.class);
Say, I have two Activities, A and B. If I'm calling B from A, I should write something like:
Intent i = new Intent(A.this, B.class);
startActivity(i);
Besides, you need to register your Activity in AndroidManifest.xml each time you create a new activity. In your case, please check if there are 2 activities in your AndroidManifest.xml

Categories