I have a preference screen in my application and I want to save the user preferences in the server, but I don't want any update button in the settings, I was hoping to make this update api call when the activity is finishing, maybe I can call the api in onPause(), the problem is, if the api takes more time than expected to return then I will have a network call running without an activity, which in my general knowledge is a memory leak. If I try to have this network call in the main thread and the call takes too long I will get an ANR.
How can I achieve this behaviour in my application. I am using retrofit2 with rxjava2 to make api calls.
You can create an AsyncTask for the Networking since the doInBackground() creates a background thread which you need to avoid networking on MainThread. Also, Activity stop doesn't stop the AsyncTask.
If you need a response (for example a Toast to inform user that preferences have successfully saved) use IntentService, otherwise Service. For detailed description of the differences see: Service vs IntentService.
For the implementation (with a good example) take a look at:
https://developer.android.com/guide/components/services and
https://developer.android.com/guide/components/broadcasts (for implementing broadcast receiver in order to process the result)
Here is a simple app. In Main Activity we go to SecondActivity. There we set some values, start a service to process them and finish the activity. When everything is ready, the MainActivity is updated automatically.
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.sytes.csongi.servicetest">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".SecondActivity">
</activity>
<service
android:name="services.MyIntentService"
android:exported="false"
>
</service>
</application>
</manifest>
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/main_result_txt"
android:text="Test"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/main_open_intent_btn"
android:text="start"
android:layout_gravity="center"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
activity_second.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".SecondActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/second_edit_01_txt"
android:hint="Enter some text here"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/second_edit_02_txt"
android:hint="another text here"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/second_start_process_btn"
android:text="start processing"
android:layout_gravity="center"/>
</LinearLayout>
MainActivity.java:
package net.sytes.csongi.servicetest;
import android.content.*;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import services.MyIntentService;
public class MainActivity extends AppCompatActivity {
private static final String TAG=MainActivity.class.getSimpleName();
private BroadcastReceiver mBroadcastReceiver;
private IntentFilter mIntentFilter;
#BindView(R.id.main_open_intent_btn)
Button mOpenIntentBtn;
#BindView(R.id.main_result_txt)
TextView mResultTxt;
public static final String ACTION_MAIN_ACTIVITY = "ACTION_MAIN_ACTIVITY";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
mIntentFilter=new IntentFilter();
mIntentFilter.addAction(ACTION_MAIN_ACTIVITY);
mBroadcastReceiver=new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive:::: called");
String action=intent.getAction();
if(action!=null&& ACTION_MAIN_ACTIVITY.equals(action)){
processReceivedIntent(intent);
}
}
};
registerReceiver(mBroadcastReceiver,mIntentFilter);
mOpenIntentBtn.setOnClickListener(v->
{
Intent startSecondActivity=new Intent(this,SecondActivity.class);
startActivity(startSecondActivity);
});
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy:::: called, unregistering Receiver");
unregisterReceiver(mBroadcastReceiver);
}
private void processReceivedIntent(Intent intent) {
Log.d(TAG, "processReceivedIntent:::: called");
StringBuilder builder=new StringBuilder("The values recieved: \n");
String returnedString=intent.getStringExtra(MyIntentService.EXTRA_TO_PROCESS);
builder.append(returnedString);
mResultTxt.setText(builder.toString());
}
}
SecondActivity.java:
package net.sytes.csongi.servicetest;
import android.content.ContentValues;
import android.os.Bundle;
import android.support.annotation.StringDef;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import butterknife.BindView;
import butterknife.ButterKnife;
import services.MyIntentService;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import static net.sytes.csongi.servicetest.SecondActivity.ValuesToSend.EDIT_TEXT_ONE;
import static net.sytes.csongi.servicetest.SecondActivity.ValuesToSend.EDIT_TEXT_TWO;
public class SecondActivity extends AppCompatActivity {
private static final String TAG=SecondActivity.class.getSimpleName();
#BindView(R.id.second_edit_01_txt)
EditText mSecondEditOne;
#BindView(R.id.second_edit_02_txt)
EditText mSecondEditTwo;
#BindView(R.id.second_start_process_btn)
Button mStartProcess;
#Retention(RetentionPolicy.SOURCE)
#StringDef({EDIT_TEXT_ONE,
EDIT_TEXT_TWO})
public #interface ValuesToSend {
/**
* edit text key for textField_01
*/
String EDIT_TEXT_ONE = "EDIT_TEXT_ONE";
/**
* edit text key for textField_02;
*/
String EDIT_TEXT_TWO = "EDIT_TEXT_TWO";
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
ButterKnife.bind(this);
mStartProcess.setOnClickListener(v -> {
startProcess();
});
}
private void startProcess() {
Log.d(TAG, "startProcess:::: called");
finish();
}
#Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop:::: called");
ContentValues valuesToSend=new ContentValues();
valuesToSend.put(EDIT_TEXT_ONE,mSecondEditOne.getText().toString());
valuesToSend.put(EDIT_TEXT_TWO,mSecondEditTwo.getText().toString());
Log.d(TAG, "onStop:::: contentValues size="+valuesToSend.size());
Bundle toSend=new Bundle();
toSend.putParcelable(MyIntentService.BUNDLE_CONTENT_VALUES_KEY,valuesToSend);
MyIntentService.startActionProcess(this,toSend);
}
}
MyIntentService.java:
package services;
import android.app.IntentService;
import android.content.ContentValues;
import android.content.Intent;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import net.sytes.csongi.servicetest.MainActivity;
import java.util.Iterator;
import java.util.Set;
/**
* An {#link IntentService} subclass for handling asynchronous task requests in
* a service on a separate handler thread.
* <p>
* helper methods.
*/
public class MyIntentService extends IntentService {
private static final String TAG=MyIntentService.class.getSimpleName();
// IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS
public static final String ACTION_PROCESS = "services.action.PROCESS";
public static final String BUNDLE_TO_PROCESS="BUNDLE_TO_PROCESS";
public static final String BUNDLE_CONTENT_VALUES_KEY = "BUNDLE_CONTENT_VALUES_KEY";
public static final String EXTRA_TO_PROCESS = "EXTRA_TO_PROCESS";
public MyIntentService() {
super("MyIntentService");
Log.d(TAG, "MyIntentService:::: instantiated");
}
/**
* Starts this service to perform action Foo with the given parameters. If
* the service is already performing a task this action will be queued.
*
* #see IntentService
*/
public static void startActionProcess(Context context, Bundle bundle) {
Log.d(TAG, "startActionProcess:::: called");
Intent intent = new Intent(context, MyIntentService.class);
intent.setAction(ACTION_PROCESS);
intent.putExtra(BUNDLE_TO_PROCESS, bundle);
context.startService(intent);
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent:::: called");
if (intent != null) {
final String action = intent.getAction();
if (ACTION_PROCESS.equals(action)) {
final Bundle bundleToProcess = intent.getBundleExtra(BUNDLE_TO_PROCESS);
handleAction(bundleToProcess);
}
}
}
private void handleAction(Bundle bundleToProcess) {
// here we run the long process
Log.d(TAG, "handleAction:::: called");
ContentValues contentValues= bundleToProcess.getParcelable(BUNDLE_CONTENT_VALUES_KEY);
StringBuilder builder=new StringBuilder("Processed values are:\n");
int numberOfValues=contentValues.size();
Set<String> valuesKeySet=contentValues.keySet();
Iterator<String> iterator=valuesKeySet.iterator();
while(iterator.hasNext()){
builder.append(contentValues.getAsString(iterator.next())+"\n");
try{ // simulating latency
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// send result to appropriate activity
Intent resultIntent=new Intent();
resultIntent.setAction(MainActivity.ACTION_MAIN_ACTIVITY);
resultIntent.putExtra(EXTRA_TO_PROCESS,builder.toString());
sendBroadcast(resultIntent);
}
}
Hope I could help you.
Related
I have a simple app that generates notifications on button Click. I also have an editText so that the content Text is typed by the user. I have two buttons that generates two different notifications. My requirement is that on every button click there should be only one notification generated and the rest should be in the notification stack. I have tried using notification setGroup property but the method doesn't seem to work. I have attached my code below for further reference.
Main Activity(Java file):-
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.app.NotificationCompat;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
private static final String GROUP_NOTIFICATIONS="group_notifications";
NotificationCompat.Builder notification;
NotificationCompat.Builder notification1;
PendingIntent pIntent;
NotificationManager manager,manager1;
Intent resultIntent;
Button button,button1;
EditText editText;
int a=0,b=100;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText= (EditText) findViewById(R.id.edittext);
button= (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startNotification();
}
});
button1= (Button) findViewById(R.id.button2);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Notifications();
}
});
}
public void buttonClick(View view)
{
startNotification();
}
public void startNotification()
{
// Intent intent=new Intent(MainActivity.this,MyService.class);
// intent.putExtra("id",Integer.toString(a));
// startService(intent);
// PendingIntent pendingIntent=PendingIntent.getService(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
String str=editText.getText().toString();
notification=new NotificationCompat.Builder(this);
notification.setContentTitle("ABC");
notification.setContentText(str);
notification.setTicker("New Message Arrived");
notification.setSmallIcon(R.mipmap.ic_launcher);
notification.setGroup(GROUP_NOTIFICATIONS);
notification.setGroupSummary(true);
int num=0;
// notification.setNumber(++num);
Uri uri=RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
notification.setSound(uri);
manager= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(a,notification.build());
a++;
}
public void Notifications()
{
String str=editText.getText().toString();
notification1=new NotificationCompat.Builder(MainActivity.this);
notification1.setContentTitle("ABC");
notification1.setContentText(str);
notification1.setTicker("New Message Arrived");
notification1.setSmallIcon(R.mipmap.ic_launcher);
notification1.setGroup(GROUP_NOTIFICATIONS);
notification1.setGroupSummary(true);
int num=0;
// notification1.setNumber(++num);
Uri uri=RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
notification1.setSound(uri);
manager1= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager1.notify(a,notification1.build());
a++;
}
}
activity_main.xml(XML file)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.pratik.stacked.MainActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/edittext"
android:textColor="#color/colorPrimary"
android:textSize="20sp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show Stacked Notification"
android:id="#+id/button"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show Stacked notifiction 1"
android:id="#+id/button2"
android:layout_above="#+id/button"
android:layout_alignLeft="#+id/button"
android:layout_alignStart="#+id/button"
/>
</RelativeLayout>
AndroidManifest.xml(Manifest file)
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
This is all about setting properly flags.
FLAG_GROUP_SUMMARY
The problem is that you are incrementing (a++) the notification ID:
manager1.notify(a,notification1.build());
a++;
If you want to update an existing notification you should call notify with the notification ID that you want to update. You can refer to the documentation
If you are on Android >= 4.1 you can use expanded layouts. Take into account that in this case you may want to ensure compatibility following these guidelines.
I am developing an app that requires the user to press a button and it goes to another activity. The problem is that I cannot continue from there. I want to be able to simulate a button press and go back to the previous activity it was on. Here is my code.
package com.example.guy.smsclassproject;
import android.os.Looper;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.widget.Button;
import android.widget.EditText;
import java.util.ArrayList;
/**
* Created by ksl130230 on 11/5/2015.
*/
public class DraftsActivityTest extends ActivityInstrumentationTestCase2<DraftsActivity> {
private DraftsActivity tester;
private EditText searchText;
private Button searchButton;
private DraftsDatabase draftsDatabase;
private MessageObject messageObject1;
private MessageObject messageObject2;
private MessageObject messageObject3;
Button[] draftButtons;
ArrayList<MessageObject> messagesToBeDisplayed;
public DraftsActivityTest() {
super(DraftsActivity.class);
}
#Override
#UiThreadTest
public void setUp() throws Exception {
super.setUp();
if (Looper.myLooper() == null)
{
Looper.prepare();
}
draftsDatabase = new DraftsDatabase();
draftsDatabase.clearData();
messageObject1 = new MessageObject("hi", "5554",null, true);
messageObject2 = new MessageObject("hi hi", "5555554",null, true);
messageObject3 = new MessageObject("sup", "5435555554",null, true);
draftsDatabase.addMessage(messageObject1);
draftsDatabase.addMessage(messageObject2);
draftsDatabase.addMessage(messageObject3);
tester = getActivity();
messagesToBeDisplayed = tester.messagesToBeDisplayed;
searchText = (EditText) tester.findViewById(R.id.searchText);
searchButton = (Button) tester.findViewById(R.id.searchButton);
}
#SmallTest
#UiThreadTest
public void testSearch() {
searchText.setText("hij");
searchButton.performClick();
messagesToBeDisplayed = tester.messagesToBeDisplayed;
assertEquals("Messages with the word hi", 0, messagesToBeDisplayed.size());
searchText.setText("sup");
searchButton.performClick();
messagesToBeDisplayed = tester.messagesToBeDisplayed;
assertEquals("Messages with the word sup", 1, messagesToBeDisplayed.size());
searchText.setText("yo");
searchButton.performClick();
messagesToBeDisplayed = tester.messagesToBeDisplayed;
assertEquals("Messages with the word yo", 0, messagesToBeDisplayed.size());
searchText.setText("i");
searchButton.performClick();
messagesToBeDisplayed = tester.messagesToBeDisplayed;
assertEquals("Messages with the word i", 2, messagesToBeDisplayed.size());
}
#SmallTest
#UiThreadTest
public void testRedisplay()
{
assertNotNull(tester.draftButtons[0]);
tester.draftButtons[0].performClick();
messagesToBeDisplayed = tester.messagesToBeDisplayed;
assertEquals("Size of the list after deletion is 2", 2, messagesToBeDisplayed.size()); //presses the first button, which deletes it from the drafts
getActivity();
String buttonText0 = tester.draftButtons[0].getText().toString();
if(buttonText0.equals("5555554: hi hi")) assertSame("Text redisplayed on the first button", buttonText0, messageObject2.toString()); //gets the text of the current button, since the messageobject1 was in draftsButtons0 before, not it should have messageobject2
assertNotNull(tester.draftButtons[1]);
String buttonText1 = tester.draftButtons[1].getText().toString();
if(buttonText1.equals("5435555554: sup"))
assertSame("Text redisplayed on the second button", buttonText1, messageObject3.toString());
}
#SmallTest
#UiThreadTest
public void testMessageButtons()
{
assertNotNull(tester.draftButtons[0]);
tester.draftButtons[0].performClick();
//THE PROBLEM IS LOCATED HERE.
//As soon as I press the button, the app goes to another activity.
//I want it to go back from the activity.
assertNotNull(tester.draftButtons[1]);
tester.draftButtons[1].performClick();
messagesToBeDisplayed = tester.messagesToBeDisplayed;
assertEquals("The draftsDatabase now only contains 1 message", 1, messagesToBeDisplayed.size());
assertNotNull(tester.draftButtons[0]);
tester.draftButtons[0].performClick();
assertNull(draftsDatabase); //after you press all the buttons, the draftsDatabase should be empty because all the messages have been deleted
}
}
This is my code of application which I recently made. If user press a button it goes to another activity from this you will be to simulate a button press and go back to the previous activity and I also have made some modification that you can pass data from text view to second activity
MainActivity
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view) {
Intent i = new Intent(this, Main2Activity.class);
final EditText inputText = (EditText) findViewById(R.id.inputText);
String mesg = inputText.getText().toString();
i.putExtra("mm",mesg );
startActivity(i);
}
}
Main2Activity
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.transition.Transition;
import android.transition.TransitionManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class Main2Activity extends AppCompatActivity {
ViewGroup RLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Bundle data = getIntent().getExtras();
if(data == null){
return;
}
String mm = data.getString("mm");
final TextView textVieww = (TextView) findViewById(R.id.textVieww);
textVieww.setText(mm);
RLayout = (ViewGroup) findViewById(R.id.RLayout);
RLayout.setOnTouchListener(
new RelativeLayout.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
moveButton();
return true;
}
});
}
public void onClickk(View view) {
Intent i = new Intent(this, MainActivity.class);
startActivity(i);
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.user.razaali.third" >
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".Main2Activity"
android:label="#string/title_activity_main2" >
</activity>
</application>
</manifest>
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity"
android:background="#53ff00">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="First Screen"
android:id="#+id/textView"
android:layout_above="#+id/inputText"
android:layout_centerHorizontal="true"
android:layout_marginBottom="33dp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Change"
android:id="#+id/button"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:onClick="onClick" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/inputText"
android:width="250dp"
android:layout_above="#+id/button"
android:layout_centerHorizontal="true"
android:layout_marginBottom="32dp" />
</RelativeLayout>
activity_main2.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="com.example.razaali.third.Main2Activity"
android:background="#fff306"
android:id="#+id/RLayout">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Secound Screen"
android:id="#+id/textVieww"
android:layout_above="#+id/button2"
android:layout_centerHorizontal="true"
android:layout_marginBottom="51dp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Change"
android:id="#+id/button2"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:onClick="onClickk" />
</RelativeLayout>
This is my main class that will be forwarding the username to my GoalActivity class. I cannot figure out where the issue is. It keeps crashing for an unknown reason to me. I've followed various tutorials, and I cannot figure out the issue. It seems that I retrieve the username correctly, and then convert it into a string. Then create an Intent and pass the username value with a key.
MainActivity.java
import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.example.agray.carpediem.LoginDataBaseAdapter;
import com.example.agray.carpediem.R;
import com.example.agray.carpediem.SignUPActivity;
public class MainActivity extends Activity
{
Button btnSignIn,btnSignUp;
LoginDataBaseAdapter loginDataBaseAdapter;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//create instance of SQLite Database
loginDataBaseAdapter=new LoginDataBaseAdapter(this);
loginDataBaseAdapter=loginDataBaseAdapter.open();
//create reference to the buttons used
btnSignIn=(Button)findViewById(R.id.buttonSignIN);
btnSignUp=(Button)findViewById(R.id.buttonSignUP);
// Signup button w/onclick listener
btnSignUp.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
// TODO Auto-generated method stub
/// Create Intent for SignUpActivity
Intent intentSignUP=new Intent(getApplicationContext(),SignUPActivity.class);
//start the activity w/intent
startActivity(intentSignUP);
}
});
}
// Methods to handleClick Event of Sign In Button
public void signIn(View View)
{
final Dialog dialog = new Dialog(MainActivity.this);
dialog.setContentView(R.layout.login);
dialog.setTitle("Login");
//get the References of views
final EditText editTextUserName=
(EditText)dialog.findViewById(R.id.editTextUserNameToLogin);
final EditText editTextPassword=
(EditText)dialog.findViewById(R.id.editTextPasswordToLogin);
Button btnSignIn=(Button)dialog.findViewById(R.id.buttonSignIn);
//Signin Button w/ onClickListener
btnSignIn.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
//store username and password as strings
String userName=editTextUserName.getText().toString();
String password=editTextPassword.getText().toString();
//fetch the Password from the DB for respective username
String storedPassword=loginDataBaseAdapter.getSingleEntry(userName);
// check if the Stored password matches with Password entered by user
if(password.equals(storedPassword))
{
Toast.makeText(MainActivity.this, "Congrats: Login is Successful " + userName,
Toast.LENGTH_LONG).show();
dialog.dismiss();
// final EditText editTextUserName=
// (EditText)dialog.findViewById(R.id.editTextUserNameToLogin);
// String userName=editTextUserName.getText().toString();
//create intent that will start the goals activity w/some data
Intent intro = new Intent(getApplicationContext(), GoalActivity.class);
//put the username into intent
intro.putExtra("USER_NAME", userName);
startActivity(intro);
}
else
{
Toast.makeText(MainActivity.this, "Access Denied: User Name or Password " +
"does not match",
Toast.LENGTH_LONG).show();
}
}
});
dialog.show();
}
#Override
protected void onDestroy() {
super.onDestroy();
// Close The Database
loginDataBaseAdapter.close();
}
}
Here is my GoalActivity class that receives info from the MainActivity class.
GoalActivity.java
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
public class GoalActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.goals_page);
//get the username from the intent
String enteredUserName = getIntent().getStringExtra("USER_NAME");
final TextView tv = (TextView)findViewById(R.id.user_name_forwarded);
tv.setText(enteredUserName);
}
}
login.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<EditText
android:id="#+id/editTextUserNameToLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="User Name"
android:ems="10" >
<requestFocus />
</EditText>
<EditText
android:id="#+id/editTextPasswordToLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPassword"
android:hint="Password" />
<Button
android:id="#+id/buttonSignIn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Sign In" />
</LinearLayout>
goals_page.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/welcome_goals"
android:textSize="50sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/user_name_forwarded"
android:text="#string/emptyString"
android:layout_weight="0.09"/>
</LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.agray.carpediem" >
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="CarpeD"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.agray.carpediem.MainActivity"
android:label="CarpeD" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SignUPActivity"/>
<activity android:name=".GoalActivity"/>
</application>
</manifest>
Try this, e.g. in ActivityA:
Intent i = new Intent(ActivityA.this, ActivityB.class);
i.putExtra("USER_NAME", userNameString);
startActivity(i);
In ActivityB:
Bundle extras = getIntent().getExtras();
if (extras == null) {
return;
}
String USERNAME = extras.getString("USER_NAME");
Solved. It was a very careless mistake. I had updated all the other activities in the Manifest but the activity tag for the GoalActivity.java. Thanks guys for all your help!
I'm trying to have my app announce some information to my custom AccessibilityService when the user starts an Activity. I have a TextView that calls requestFocus() when the activity starts, and then I send an AccessibilityEvent to have the AccessibilityService read the TextView's content description. I've isolated the problem into a small application.
Here's the main Activity:
package com.example.ttstest;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View v = findViewById(R.id.textView1);
v.requestFocus();
v.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT);
}
}
The layout file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.ttstest.MainActivity" >
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:contentDescription="Secondarily focused text view"
android:text="#string/hello_world" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView2"
android:layout_marginLeft="54dp"
android:layout_marginTop="145dp"
android:layout_toRightOf="#+id/textView2"
android:contentDescription="Initially focused text view"
android:focusable="true"
android:focusableInTouchMode="true"
android:text="Initially focused text view" />
</RelativeLayout>
And the AccessibilityService:
package com.example.ttstest;
import android.accessibilityservice.AccessibilityService;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
public class TextToSpeechService extends AccessibilityService {
private static TextToSpeech textToSpeech = null;
private static boolean ttsReady = false;
#Override
protected void onServiceConnected() {
super.onServiceConnected();
Log.e("TextToSpeechService", "Got to onServiceConnected()");
textToSpeech = new TextToSpeech(this.getApplicationContext(), new OnInitListener() {
#Override
public void onInit(int status) {
if(status == TextToSpeech.SUCCESS) {
ttsReady = true;
}
}
});
}
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.e("TextToSpeechService", "Entering onAccessibilityEvent().");
Log.e("TextToSpeechService", "Event type: " + event.getEventType() + ", from class " + event.getClassName());
if(event.getContentDescription() != null) {
Log.e("TextToSpeechService", "" + event.getContentDescription());
}
if(textToSpeech != null && ttsReady == true) {
if(event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
CharSequence contentDescription = event.getContentDescription();
if(contentDescription != null) {
String say = contentDescription.toString();
textToSpeech.speak(say, TextToSpeech.QUEUE_FLUSH, null);
}
} else if (event.getEventType() == AccessibilityEvent.TYPE_ANNOUNCEMENT) {
CharSequence contentDescription = event.getContentDescription();
if(contentDescription != null) {
textToSpeech.speak(event.getContentDescription().toString(), TextToSpeech.QUEUE_FLUSH, null);
}
}
}
Log.e("TextToSpeechService", "Exiting onAccessibilityEvent().");
}
#Override
public void onInterrupt() {
Log.e("TextToSpeechService", "Entering onInterrupt()");
if(textToSpeech != null && ttsReady == true) {
textToSpeech.stop();
}
}
}
This has been added to my AndroidManifest.xml in the appropriate location:
<service android:name="com.example.ttstest.TextToSpeechService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data android:name="android.accessibilityservice"
android:resource="#xml/accessibilityservice"/>
</service>
My accessibilityservice.xml settings:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:notificationTimeout="100"
android:accessibilityFeedbackType="feedbackSpoken"
android:accessibilityFlags="flagDefault"
android:canRetrieveWindowContent="true"
android:packageNames="com.example.ttstest"/>
And finally, the problem. When I first start the application, neither the TextView gaining focus from requestFocus() or the call to sendAccessibilityEvent() actually send anything to the AccessibilityService. If I tab through the TextViews by attaching a physical keyboard, the focus events are received. I have made sure to turn on the AccessibilityService in the settings, and I have proof from the application I made this example from that the AccessibilityService is enabled when requestFocus() and sendAccessibilityEvent() are called. This doesn't help. It seems like when an Activity is first started, neither of these methods send anything to the AccessibilityService. I've also tried calling announceForAccessibility() with similar results.
Am I doing this wrong? How can I fix it, or at least get around it? Specifically, I want to send an event to my AccessibilityService when an Activity first starts.
More information: I have tried moving the requestFocus() and sendAccessibilityEvent() calls to onStart() and onWindowFocusChanged(); neither of these work either.
I may be mistaken but the "UI" isn't ready until onResume() is called so perhaps that is the issue?
My code is written to first bring up a button in the LoginActivity and then when pressed load another activity. But as of right now, the app crashes both on my S4 and an emulator on launch. I have tried debugging mode but haven't received any useful information. Here is my LoginActivity code (main activity):
package com.JTInc.tag;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
public class LoginActivity extends FragmentActivity {
public void gotomap (View View){
Intent ii = new Intent(getActivity(), MapActivity.class);
startActivity(ii);
}
private void startActivity(Intent ii) {
// TODO Auto-generated method stub
}
private Context getActivity() {
//TODO Auto-generated method stub
return null;
}
}
Here is the mapviewer.xml code (the main layout)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/gotomap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/gotomap"
android:onClick="gotomap" />
</LinearLayout>
Any and all help is appreciated, Thanks.