How to call an other activity from parent activity by intent setclass? - android

I'm trying to make an dynamical move activity process by using baseActivity through process of defined string value.
But I've faced an problem of "activity is not an enclosing class." error in calling "newIntent.setClassName" method of baseActivity.
Could you help some idea?
First, for explaining about the trying code,
This process purpose is for user sign up process.
Here is used activities.
1. AgreeChildActivity (agree a service terms)
2. VerifyingChildActivity (verifying an user)
3. InputChildActivity (input an user info)
4. CompleteChildActivity (show a service join completed)
1~4 These are children of "GateBaseActivity".
It starts the dynamical move process by onClick method of an "MainActivity".
MainActivity {
String sProcessCase1 = "verifying->input->complete";
String sProcessCase2 = "input->verifying->complete";
String sProcessCase3 = "input->complete";
:
:
public void onClick(View v) {
Intent intent = null;
try {
switch (v.getId()) {
case R.id.goDynamicMenu:
// start dynamic process
Intent newIntent = new Intent()
newIntent.setClassName(this, "AgreeChildActivity");
newIntent.putExtra("MOVE_SEQ", sProcessCase1); <== set processCase.
startActivity(newIntent);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Following is each activities code.
GateBaseActivity (<= This is a parent of all process activity.)
void onResume() { (so executes this method when each process activity shows.)
String sActivitySeq = getintent("MOVE_SEQ"); <= "verifying->input->complete"
String sNextActivity = <= calculate the nextActivity name on sActivitySeq. For simple, omitted.
// "verifying->input->complete"
// verifying => VerifyingChildActivity
// input => InputChildActivity
// complete => CompleteChildActivity
String sThisChildSimpleName = this.getClass().getSimpleName();
Intent newIntent = new Intent();
// execute here when childActivity is the "AgreeChildActivity".
if ("AgreeChildActivity".equals(sThisChildSimpleName)) {
newIntent.setClassName(AgreeChildActivity(<=Here occured "not an enclosing class err.", How to solve this error?).this, sNextActivity);
}
// execute here when childActivity is the "VerifyingChildAcitivty".
else if ("VerifyingChildActivity".equals(sThisChildSimpleName)) {
newIntent.setClassName(VerifyingChildActivity(<=Here occured "not an enclosing class err.", How to solve this error?).this, sNextActivity);
}
// execute here when childActivity is the "InputChildAcitivty".
else if ("InputChildActivity".equals(sThisChildSimpleName)) {
newIntent.setClassName(InputChildActivity(<=Here occured "not an enclosing class err.", How to solve this error?).this, sNextActivity);
}
// execute here when childActivity is the "CompleteChildActivity".
else if ("CompleteChildActivity".equals(sThisChildSimpleName)) {
newIntent.setClassName(CompleteChildActivity(<=Here occured "not an enclosing class err.", How to solve this error?).this, sNextActivity);
}
newIntent.putExtra("MOVE_SEQ", sActivitySeq);
startActivity(intent);
}
// These are child activities of "GateBaseActivity".
AgreeChildActivity implement GateBaseActivity
void onResume() {
super.onResume();
Log.d("autoTest", "Here is AgreeChildActivity.");
}
VerifyingChildActivity implement GateBaseActivity
void onResume() {
super.onResume();
Log.d("autoTest", "Here is VerifyingChildActivity.");
}
InputChildActivity implement GateBaseActivity
void onResume() {
super.onResume();
Log.d("autoTest", "Here is InputChildActivity.");
}
CompleteChildActivity implement GateBaseActivity
void onResume() {
super.onResume();
Log.d("autoTest", "Here is CompleteChildActivity.");
}

Try-
Context context = getApplicationContext();
Intent intent = new Intent(context, AgreeChildActivity.class);
You have to use existing activity context to start new activity, new activity is not created yet, and you cannot use its context or call methods upon it.
not an enclosing class error is thrown because of your usage of this keyword. this is a reference to the current object — the object whose method or constructor is being called. With this you can only refer to any member of the current object from within an instance method or a constructor.

Related

Is it possible to make a loop pause waiting for activity inside it to finish?

An idea I'm trying to implement is: loop through elements of a list, displaying and waiting to hear back from different activities depending on a particular value an element has.
What I thought would work:
for (Model item:questionBank) {
if (item.getTaskType() == "taskType1") {
Intent intent = new Intent(MainActivity.this, 2ndactivity.class);
intent.putExtra("word", item.getWord());
startActivityForResult(intent,REQUEST_CODE);
}}
plus an override method onActivityResult later in the code.
What happens is application starts the activity but it also continues looping through elements without waiting for started activity to finish...
Is it possible to make it wait for started activity to finish before moving on?
In your case for loop will not wait for result from other activity. So, I have another logic to solve this problem.
Declare a iterator variable in the class level like int i = 0;
When you want to start another activity for result, get data from the list at the i index questionBank[i] and start activityForResult.
In the onActivityResult method increment i.
i++
String word = questionBank[i];
startActivityForResult(intent,REQUEST_CODE);
In this way, you can achieve your desired results.
There is a solution no need startforResult or changes in Child activity!! , you can use startActivity(intent) on Parent Activity:
Using the activity lifecycle ,
to stop after call child Activiy and resume after child activity finish.
I think its an elegant solution.
You have a sequence of activities to start inside Parent Class Activty:
.....
startActiviy(intent1)
startActiviy(intent2)
startActiviy(intent3)
.....
It can be a loop like in my case
...
While( ) {
startActiviy(intent)
}
...
the solution is split the sequence in two:
the first startactivity(...) in the end
of the method of Parent activity , so the parent will pause after that;
the other startactivities(...) inside onResume method of Parent activity
in the end of onResume to make sure the Parent activity will stop due the
lifecycle.
You need a class variable to flow control as in loop , defined before call the first startActiviy
and increment it onResume method for each call of startActivity.
The last thing: you need to be able to define intents onResume method , some local variables of "method" should be in Class scope (defined on "method" and accessible in "onResume".
Class Parent Activity {
int r = 0; // control flow of child activities
// variables to define intent inside onResume
// the first call of startactivity goes here
private void method ( )){
.....
// just an example decreasing for each activity call,
r = 3; // call 4 times startActivity I guess, in this example
startActivity (intent) // in the to acitvity stop
}
// all subsequent startactivity goes here
protected void onResume(){
super.onResume();
....
if (r > 0) {
r--;
startActivity(intent);
}
}//end onResum
}//Class end
it works fine for me!
my code I created a method to call each Child activity "callinsertn"
public class TableActivity extends AppCompatActivity implements MainFragment.OnFragmentInteractionListener{
private Iterator< Pair<Integer, Integer> > iter; // control flow
private String[] startup_tcolnames; //need to define my intents
private Set<Pair<Integer, Integer>> selection;//need to define my intents
protected void onCreate ( ) {
....
....
mUpdateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Toast.makeText(getApplicationContext(), "chamou callback na tabela col " + mrowid, Toast.LENGTH_LONG).show();
....
....
iter = selection.iterator();
if (iter.hasNext()) {
Pair<Integer, Integer> pair = iter.next();
callInsertn(pair);
}
}
}
}
protected void onResume(){
super.onResume();
MainFragment.class.getSimpleName();
if(iter !=null) {
if (iter.hasNext()) {
Pair<Integer, Integer> cell_coord = iter.next();
callInsertn(cell_coord);
} else {
//its over. all child activities ran
selection.clear();
selectedcell = false;
Log.i("DEBUG", "final final do update button");
iter =null;
}
}
}
//start my Child activity
//no flow control variables only accessing class vars to define intent
private void callInsertn(Pair<Integer, Integer> cell_coord){
mfrag_ind = cell_coord.second;
mrowid = (long) cell_coord.first;
Intent i = new Intent(TableActivity.this, Insertn.class);
i.putExtra("operation", "update");
// i.putExtra
// i.putExtra
startActivity (i);//start the Child activity
}
The Child activity doesnt even wonder who is its Parent , when it finishes the lifecycle returns to Parent so no communication from Child to Parent. All code goes on Parent Activity!
I hope you enjoy the solution!

How to make a result from function to show in another activity

public void doSomething(View view) {
String url, link_url, pro;
url = textIn.getText().toString();
pro = spin.getSelectedItem().toString();
c1 = new ConnectInternetClass(this);
if (!url.isEmpty()) {
if (url.contains(".") && !(url.contains(" "))) {
if (url.split("\\.").length > 1) {
if (checkConnection()) {
link_url = pro+url;
c1.execute(link_url);
} else {
Toast.makeText(this, "check your internet connection", Toast.LENGTH_SHORT).show();
myText.setText("No Internet Connection");
}
} else {
myText.setText("Unknown domain");
}
} else {
myText.setText("Invalid URL");
}
} else {
myText.setText("URL can\'t empty");
}
}
I have that code to show a web page source. I want to show the result in another activity, but I don't know how. I use the create object from the first activity, but it's not method
public class ShowActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show);
MainActivity ma = new MainActivity();
}
Passing data from a activity , linkUrl is your variable which data you want to pass :
Intent intent = new Intent (YourActivity.this, ShowActivity.class) ;
intent.putExtra("KEY_LINK" , linkUrl);
startActivity(intent);
Receiving data from ShowActivity , Access the data by the key in onCreate():
String url = getIntent().getStringExtra("KEY_LINK");
Link : How do I pass data between Activities in Android application?
Link : https://developer.android.com/training/basics/firstapp/starting-activity.html
Why you use this kind of things. If you want to load a web page in an activity use webview for it. no need two activities to do that. Another way you can create a class which has your doSomething method (it should be public static) and call it from an activity by using that's class object. When you coding don't create unnecessary activities.

How onNewIntent() of Activity called from Unity

I am working on unity android project.
I have called the android side methods from unity like this
AndroidJavaObject aObj = new AndroidJavaObject("com.mypackage.UnityBridge",param1,param2);
aObj.Call("callme");
And on Android side
public class UnityBridge{
public UnityBridge(final String param1, final int param2) {
activity = UnityPlayer.currentActivity;
this.param1= param1;
this.param2= param2;
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
// INITIALIZATION OF ANDROID CLASS CONSTRUCTOR HERE
}
});
}
public void callme() {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
if(obj!= null)
{
// ANDROID METHOD CALL HERE
}
}
});
}
This much is working perfectly.
If I want to call Activity specific methods like onPause(), onResume(), so there is a method in unity to do so.
void OnApplicationPause(bool pauseStatus) {
// HERE I CAN CALL activity specific **onPause()** and **onResume()** based on pauseStatus
}
Is there anything in unity from which I can give call to onNewIntent(Intent i) of Android. If not then how is it possible to call onNewIntent()
Please help to resolve this.
I wrote a post how this problem can be solved without overriding Unity activity (its about onActivityResult but the principle is the same): https://medium.com/#tarasleskiv/unity-android-plugins-and-onactivityresult-callback-abef4b6bbc87#.6d7sl8z81
Basically you create a custom empty activity and start it just to receive these callbacks and finish it immediately after that.
Check also this post about how to create activity for onNewIntent callback: https://blog.getsocial.im/android-unity-app-and-the-intent-issue/
Here is the example code of the intermediate activity yo have to create:
public class MyDeepLinkingActivity extends Activity
{
private static String TAG = "GetSocial GetSocialDeepLinkingActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
Log.v(TAG, "Forward the intent");
// Do with intent what you need to
Log.v(TAG, "Returning to main activity");
//start main activity
Intent newIntent = new Intent(this, getMainActivityClass());
this.startActivity(newIntent);
finish();
}
private Class<?> getMainActivityClass() {
String packageName = this.getPackageName();
Intent launchIntent = this.getPackageManager().getLaunchIntentForPackage(packageName);
try {
return Class.forName(launchIntent.getComponent().getClassName());
} catch (Exception e) {
Log.e(TAG, "Unable to find Main Activity Class");
return null;
}
}
}
Looks like there is no built it way to get onNewIntent callback in Unity. However i can suggest to export google android project from unity and override this method in main unity activity
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//some code
}
Or you can create android plugin with your own activity which extends unity activity, but keep in mind that some plugins could stop working if you do this.

Weird behavior when refreshing an Android fragment's view

I am having hard time doing a task which is supposed to be easy. I am not sure whether it is because of the Android platform's bad design or if I am missing something. I simply would like to refresh a fragment's view on resume. Here are the details:
I have two activities, a SplashActivity which retrieves data from a server (using a AsyncTask) and passes the data to my MainActivity. In my MainActivity, I get this data and pass it to a fragment named SummaryFragment. I have a few fragments and a navigation drawer (in my MainActivity). The first visible fragment is the SummaryFragment which reads the data passed to it from the MainActivity and consequently draws a graph.
When the app starts, there might be no active Internet connection, in that case, in my summary fragment I ask the user to enable WiFi. What I want to do is to refresh this SummaryFragment's view after the user comes back to the app after enabling WiFi. What I do right now is that in the onResume() of my MainActivity, I check if the SummaryFragment in visible, and if so, I start the SplashActivity again (and close the current activity). SplashActivity must fetches the data (like it does when the app starts) and start the MainActivity (fed with the fetched data) which loads the summary fragment and shows the graph.
The problem is that it takes a considerably long time (30-40 seconds) after the app is resumed to go from the SplashActivity to the MainActivity and show the graph (meanwhile the users sees the splash screen), whereas when the app starts it takes 1-2 seconds to do so. Before using the current solution (redirecting user to the SplashActivity), in MainActivity.onResume() I tried using the same AsyncTask class that I am using in the SplashScreen to fetch the data and show the summary fragment afterwards, but the result is the same, there is a significant delay.
The following code is my MainActivity's onResume():
Fragment fragment = getVisibleFragment();
if (fragment instanceof SummaryFragment) {
Intent intentSplashActvity = new Intent(this, SplashActivity.class);
Log.d(TAG, "about to start the splash activity");
startActivity(intentSplashActvity);
// close current activity
finish();
super.onResume();
return;
}
super.onResume();
The SplashActivity:
public class SplashActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
new PrefetchData(this).execute();
}
}
The PrefetchData:
public class PrefetchData extends AsyncTask<Void, Void, Void> {
String serverResponseJson = null;
private String data1 = null,
data2 = null,
data3 = null;
private SplashActivity mSplashActivity = null;
private MainActivity mMainActivity;
public PrefetchData(Activity sourceActivity){
if (sourceActivity.getClass() == SplashActivity.class) {
mSplashActivity = (SplashActivity) sourceActivity;
}
}
#Override
protected Void doInBackground(Void... arg0) {
JsonParser jsonParser = new JsonParser();
try {
if (CaratApplication.isInternetAvailable()) {
serverResponseJson = jsonParser
.getJSONFromUrl("http://aURL");
}
} catch (Exception e) {
Log.d("SplashActivity", e.getStackTrace().toString());
}
if (serverResponseJson != null && serverResponseJson != "") {
try {
JSONArray jsonArray = new JSONObject(serverResponseJson).getJSONArray("arrayName");
// Using Java reflections to set fields by passing their name to a method
try {
setFieldsFromJson(jsonArray, 0, "data1");
setFieldsFromJson(jsonArray, 1, "data2");
setFieldsFromJson(jsonArray, 2, "data3");
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
} catch (JSONException e) {
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (mSplashActivity != null) {
Intent intentMainActvity = new Intent(mSplashActivity, MainActivity.class);
if (gotDataSuccessfully()) {
intentMainActvity.putExtra("data1", data1);
intentMainActvity.putExtra("data2", data2);
intentMainActvity.putExtra("data3", data3);
} else {
intentMainActvity.putExtra("data1", Constants.DATA_NOT_AVAIABLE);
intentMainActvity.putExtra("data2", Constants.DATA_NOT_AVAIABLE);
intentMainActvity.putExtra("data3", Constants.DATA_NOT_AVAIABLE);
}
mSplashActivity.startActivity(intentMainActvity);
mSplashActivity.finish();
}
}
}
In MainActivity, upon selection of the "summary" entry in the navigation drawer, I initialize the SummaryFragment, and then replace it using a fragment transaction (replaceFragment(mSummaryFragment, mSummaryFragmentLabel)). Here is the method I use to initialize the summary fragment:
private void initSummaryFragment() {
if (mData1 == 0 && mData2 == 0 && mData3 == 0) {
Intent intent = getIntent();
String data1 = intent.getStringExtra("data1");
String data2 = intent.getStringExtra("data2");
String data3 = intent.getStringExtra("data3");
boolean isDataAvaiable = !data1.equals(Constants.DATA_NOT_AVAIABLE)
&& !data2.equals(Constants.DATA_NOT_AVAIABLE) && !data3.equals(Constants.DATA_NOT_AVAIABLE);
if (isDataAvaiable) {
mData1 = Integer.parseInt(data1);
mData2 = Integer.parseInt(data2);
mData3 = Integer.parseInt(data3);
}
}
mSummaryFragment = new SummaryFragment();
mArgs = new Bundle();
mArgs.putInt("data1", mData1);
mArgs.putInt("data2", mData2);
mArgs.putInt("data3", mData3);
mSummaryFragment.setArguments(mArgs);
mSummaryFragmentLabel = getString(R.string.summary);
}
The SummaryFragment can now retrieve the data it needs from the bundle passed to it.
The problem was with the (rather) undocumented behavior of Android's AsyncTask. An AsyncTask does not run in a separate thread, it runs in a thread that is shared with other AsyncTasks, so if you have other AsyncTasks (or even a plain thread), if they start running before your current AsyncTask, this AsyncTask waits for them to complete their action. I explicitly specified that I would like my AsyncTask to run in a separate thread, and this reduced the delay from about 20-25 seconds to 3-4 seconds for fetching a JSON object (I have other network access calls in progress in parallel). I run the following code as part of my preInitFragments() method in onCreate() method of my main activity.
// The following PrefetchData class is of type AsyncTask<void, void, void>. I moved this class from a stand-alone class to an inner class inside my main activity for easier refreshing of my fragment.
PrefetchData prefetchData = new PrefetchData();
// run this asyncTask in a new thread [from the thread pool] (run in parallel to other asyncTasks)
// (do not wait for them to finish, it takes a long time)
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
prefetchData.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
prefetchData.execute();
After this I call my method initSummaryFragment(). Please note that in my AsyncTask, in doInBackGround(), I set the two fields (mField1 and mField2) you see below (I used to pass them as a bundle to the summary screen, but that way would cause a problem when you were just detaching and attaching the fragment (to refresh its view) without passing a bundle to your fragment). In the onPostExecute() of my asyncTask, I invoke my method refreshSummaryFragment():
private boolean isStatsDataAvailable() {
return mWellbehaved != 0 && mHogs != 0 && mBugs != 0;
}
private void initSummaryFragment() {
if (! isStatsDataAvailable()) {
mSummaryFragment = new SummaryFragment();
}
mSummaryFragmentLabel = "Summary";
}
For refreshing my summary fragment, I simply detach, and attach my summary fragment, and then commit the pending fragment transaction:
public void refreshSummaryFragment() {
if (isStatsDataAvailable()) { // blank summary fragment already attached. detach and attach to refresh
FragmentManager manager = getSupportFragmentManager();
// init the fragment (for later use when user selects an item from the navigation drawer)
mSummaryFragment = getSupportFragmentManager().findFragmentByTag("Summary");
FragmentTransaction fragTransaction = manager.beginTransaction();
// refresh the summary fragment:
fragTransaction.detach(mSummaryFragment);
fragTransaction.attach(mSummaryFragment);
fragTransaction.commit();
} else {
Log.e(TAG, "refreshSummaryFragment(): stats data not avaiable!");
}
}

Update data in local SQLite then return to parent Activity solution

I am learning Android. I am creating an application that have 2 activities: List Activity list all records from a local SQLite and Edit activity will create/update record.
On Edit activity, I have a button. When the button clicked, I will process creating/updating the record then returning back to parent activity (List activity).
On Button click. I have 2 solutions to process Create/Update:
1. Process Create/Update in UI thread ( Not using AsyncTask )
This solution is fine but I may have to show 'Processing' dialog.
2. Use AsyncTask -- so creating/updating happens in background Thread. Here is my code in Edit Activity:
---- NOTE that Edit activity use Fragment so getActivity() method will return the instance of EditActivity
saveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AsyncTask<Phrase, Integer, Integer> asyncTask = new AsyncTask<Phrase, Integer, Integer>() {
#Override
protected Integer doInBackground(Phrase... params) {
Phrase phrase = params[0];
if (phrase._id > 0) {
PhraseDao.update(DbManager.openWrite(getActivity()), phrase);
} else {
PhraseDao.insert(DbManager.openWrite(getActivity()), phrase);
}
return null;
}
#Override
protected void onPostExecute(Integer result) {
Intent intent = new Intent();
getActivity().setResult(Activity.RESULT_OK, intent);
// Close Edit Activity then Go back to List activity
getActivity().finish();
// MY QUESTION: What happens if the EditActivity (getActivity) already destroyed?
// How can I handle destroyed activity here
}
};
asyncTask.execute(a_phrase);
}
});
I don't know how to handle 'onPostExecute' method in the case Edit Activity ( accessed by getActivity()) Already destroyed.
Anyone have any ideas? Thank you!
Add a null check to see if activity exists i.e
if(getActivity() != null){
Intent intent = new Intent();
getActivity().setResult(Activity.RESULT_OK, intent);
getActivity().finish();
}

Categories

Resources