I am using the library barcodescanner from https://github.com/dm77/barcodescanner.
Currently the scanner displays a rectangle and a laser across the middle.
that looks similar to:
I am looking to make this view into a square since I am only scanning QR codes and to remove the laser and would appreciate some help.
My code that I have written so far for the scanner fragment is below
public class ScannerFragment extends Fragment implements
ZBarScannerView.ResultHandler
{
private static final String FLASH_STATE = "FLASH_STATE";
private static final String AUTO_FOCUS_STATE = "AUTO_FOCUS_STATE";
private static final String SELECTED_FORMATS = "SELECTED_FORMATS";
private static final String CAMERA_ID = "CAMERA_ID";
private ZBarScannerView mScannerView;
private boolean mFlash;
private boolean mAutoFocus;
private ArrayList<Integer> mSelectedIndices;
private int mCameraId = -1;
Communicator messenger;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
messenger=(Communicator) getActivity();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) {
mScannerView = new ZBarScannerView(getActivity());
if (state != null) {
mFlash = state.getBoolean(FLASH_STATE, false);
mAutoFocus = state.getBoolean(AUTO_FOCUS_STATE, true);
mSelectedIndices = state.getIntegerArrayList(SELECTED_FORMATS);
mCameraId = state.getInt(CAMERA_ID, -1);
} else {
mFlash = false;
mAutoFocus = true;
mSelectedIndices = null;
mCameraId = -1;
}
setupFormats();
return mScannerView;
}
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
setHasOptionsMenu(true);
}
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
MenuItem menuItem;
if (mFlash) {
menuItem = menu.add(Menu.NONE, R.id.menu_flash, 0, R.string.flash_on);
} else {
menuItem = menu.add(Menu.NONE, R.id.menu_flash, 0, R.string.flash_off);
}
MenuItemCompat.setShowAsAction(menuItem, MenuItem.SHOW_AS_ACTION_ALWAYS);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.menu_flash:
mFlash = !mFlash;
if (mFlash) {
item.setTitle(R.string.flash_on);
} else {
item.setTitle(R.string.flash_off);
}
mScannerView.setFlash(mFlash);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onResume() {
super.onResume();
mScannerView.setResultHandler(this);
mScannerView.startCamera();
mScannerView.setFlash(mFlash);
mScannerView.setAutoFocus(mAutoFocus);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(FLASH_STATE, mFlash);
outState.putBoolean(AUTO_FOCUS_STATE, mAutoFocus);
outState.putIntegerArrayList(SELECTED_FORMATS, mSelectedIndices);
outState.putInt(CAMERA_ID, mCameraId);
}
#Override
public void handleResult(Result rawResult) {
new Thread(new Runnable() {
#Override
public void run() {
try {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(getActivity().getApplicationContext(), notification);
r.play();
}
catch (Exception e) {
}
}
}).start();
QRResults scanResult = QRResults.getInstance();
scanResult.Extract(rawResult.getContents());
if (scanResult.dataExtractedOK)
{
if (scanResult.canPerformElectricityComparison() || scanResult.canPerformGasComparison())
{
messenger.updateTextView("Found Code");
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
Intent i = new Intent(getActivity(), SearchResult.class);
startActivity(i);
}
}, 2000);
}
}
else
{
messenger.updateTextView("Invalid Code");
// Restart Camera after 2 second delay
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
mScannerView.startCamera();
mScannerView.setFlash(mFlash);
mScannerView.setAutoFocus(mAutoFocus);
messenger.updateTextView("Finding code...");
}
}, 2000);
}
}
public void onFormatsSaved(ArrayList<Integer> selectedIndices) {
mSelectedIndices = selectedIndices;
setupFormats();
}
public void setupFormats() {
List<BarcodeFormat> formats = new ArrayList<BarcodeFormat>();
formats.add(BarcodeFormat.QRCODE);
}
#Override
public void onPause() {
super.onPause();
mScannerView.stopCamera();
}
I think I need to extend a class from the library and override some of the methods in it but I'm not sure how to do this and have the overridden methods used in my scanner class.
Thank you for your time.
Add library module in a project (not as a dependency). Here is a tutorial how to add a library module in Android Studio.
Go to library module and find in ViewFinderView.java class drawLaser(Canvas canvas) method (draws the line in the middle).
Related
I'm making an app where I ask a question and the answering machine answers me depending on the question, but the problem is that the cell phone listens but it does not respond, that is, it does not talk.
She is speak in open app with welcome, but after no talk
My code
public class MainActivity extends AppCompatActivity {
private TextToSpeech myTTS;
private SpeechRecognizer mySpeechReconizer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Button mic = (Button) findViewById(R.id.mic);
mic.setOnClickListener((view) ->
{
Intent i = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
i.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
i.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1);
mySpeechReconizer.startListening(i);
});
initializeTextToSpeech();
initializeSpeechReconizer();
}
private void initializeSpeechReconizer() {
if (SpeechRecognizer.isRecognitionAvailable(this)) {
mySpeechReconizer = SpeechRecognizer.createSpeechRecognizer(this);
mySpeechReconizer.setRecognitionListener(new RecognitionListener() {
#Override
public void onReadyForSpeech(Bundle params) {
}
#Override
public void onBeginningOfSpeech() {
}
#Override
public void onRmsChanged(float rmsdB) {
}
#Override
public void onBufferReceived(byte[] buffer) {
}
#Override
public void onEndOfSpeech() {
}
#Override
public void onError(int error) {
}
#Override
public void onResults(Bundle bundle) {
List<String> res = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
processResult(res.get(0));
}
#Override
public void onPartialResults(Bundle partialResults) {
}
#Override
public void onEvent(int eventType, Bundle params) {
}
});
}
}
private void processResult(String s) {
s = s.toLowerCase();
//Qual é o teu nome?
if (s.indexOf("What") != -1){
if (s.indexOf("your name") != -1){
speak("two");
}
if (s.indexOf("time") != -1){
Date now = new Date();
String time = DateUtils.formatDateTime(this,now.getTime(),
DateUtils.FORMAT_SHOW_TIME);
speak(time);
}
}
else if (s.indexOf("open") != -1){
if (s.indexOf("browser") != -1){
}
speak("Sou a Lian, fui fundada pelo Leandro e moro em Baião.");
}
}
private void initializeTextToSpeech() {
myTTS = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (myTTS.getEngines().size()==0){
Toast.makeText(MainActivity.this, "Teste", Toast.LENGTH_LONG).show();
finish();
} else {
Locale l1 = new Locale("pt","PT");
myTTS.setLanguage(l1);
speak("Olá Leandro, estou pronta,podes falar!");
}
}
});
}
private void speak(String s) {
if (Build.VERSION.SDK_INT >=21){
myTTS.speak(s,TextToSpeech.QUEUE_FLUSH,null,null);
} else{
myTTS.speak(s,TextToSpeech.QUEUE_FLUSH,null);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onPause() {
super.onPause();
myTTS.shutdown();
}
}
I have created app that detects otg cable,when otg cable is plugged in or out popup message appears that says otg connected or otg disconnected.How to make that popup appears when button on toolbar is clicked,popup message should only appear in action bar when otg cable is not connected,when it's connected it's should be hidden?
public class MainActivity extends AppCompatActivity
{
private Process suProcess;
public static final String IS_CONNECTED_KEY = "isConnectedValue";
public void startOtgService()
{
startService(new Intent(MainActivity.this, OtgService.class));
}
public void stopOtgService()
{
stopService(new Intent(MainActivity.this, OtgService.class));
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button_autootg);
button.setTag(0);
button.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
button.setText("");
final int status = (Integer) view.getTag();
switch (status)
{
case 0:
startOtgService();
button.setText("OTG Service Enabled");
button.setBackgroundColor(Color.GREEN);
view.setTag(1);
break;
case 1:
stopOtgService();
button.setText("OTG Service Disabled");
button.setBackgroundColor(Color.RED);
view.setTag(0);
break;
}
}
});
}
private void getRoot()
{
try
{
suProcess = Runtime.getRuntime().exec("su");
}
catch (IOException e)
{
}
}
#Override
protected void onNewIntent(Intent intent)
{
if (intent.getExtras() == null)
{
super.onNewIntent(intent);
Log.e("###", "No extras");
return;
}
if (intent.hasExtra(IS_CONNECTED_KEY))
{
Log.e("###", "Displaying dialog");
boolean isConnected = intent.getExtras().getBoolean(IS_CONNECTED_KEY);
final AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("Otg state changed");
if (isConnected)
alertDialog.setMessage("OTG connected");
else
alertDialog.setMessage("OTG disconnected");
alertDialog.show();
}
else
{
Log.e("###", "Does not contain key");
super.onNewIntent(intent);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
int id = item.getItemId();
if (id == R.id.action_settings)
{
return true;
}
if(id == R.id.action_cable)
{
}
return super.onOptionsItemSelected(item);
}
}
public class OtgService extends Service
{
private boolean mOtgConnected = false;
private Handler mHandler;
Timer taskTimer = new Timer();
TimerTask task = new TimerTask()
{
private int last_Length = -1;
#Override
public void run()
{
Context context = OtgService.this.getBaseContext();
File directory = new File("/sys/bus/usb/devices");
File[] contents = directory.listFiles();
int conn_length = contents.length;
if(conn_length ==last_Length)
{
return;
}
else
{
last_Length = conn_length;
}
if(conn_length == 0)
{
mOtgConnected = false;
mHandler.post(flagChangedTask);
}
else if (conn_length > 0) //Might get a -1
{
mOtgConnected = true;
mHandler.post(flagChangedTask);
}
if(conn_length == 0)
{
displayDialog(false);
}
else if (conn_length > 0) //Might get a -1
{
displayDialog(true);
}
}
};
//Will post this to the main thread
Runnable flagChangedTask = new Runnable()
{
#Override
public void run()
{
if (mOtgConnected)
Toast.makeText(OtgService.this,"otg connected",Toast.LENGTH_SHORT).show();
else
Toast.makeText(OtgService.this,"otg not connected",Toast.LENGTH_SHORT).show();
}
};
public OtgService()
{
}
public void displayDialog(boolean isConnected)
{
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(MainActivity.IS_CONNECTED_KEY, isConnected);
startActivity(intent);
}
private void onStartCompat(Intent intent)
{
Log.e("###", "Starting service!");
if (mHandler == null)
mHandler = new Handler(getMainLooper());
taskTimer.scheduleAtFixedRate(task, 0, 1000);
}
// This is the old onStart method that will be called on the pre-2.0
// platform. On 2.0 or later we override onStartCommand() so this
// method will not be called.
#Override
public void onStart(Intent intent, int startId)
{
onStartCompat(intent);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
onStartCompat(intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
#Override
public void onDestroy()
{
//task.cancel();
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
}
Add the following code in your code. When cable state changed, call cableStateWasChanged(boolean isConnected). This will show the popup button in your toolbar. When the button is clicked, a popup is shown and the button disappears. You can change the popup title and message depending on the cable state as you want it to be.
private boolean isCableConnected = false;
private boolean cableStateChanged = false;
private boolean popupWasShown = false;
#Override
public boolean onPrepareOptionsMenu(Menu menu){
MenuItem item = menu.findItem(R.id.action_popup);
if (cableStateChanged && !popupWasShown) {
item.setVisible(true);
cableStateChanged = false;
} else if (popupWasShown) {
item.setVisible(false);
}
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == ...) {
...
} else if (id == R.id.action_popup) {
popupWasShown = true;
invalidateOptionsMenu();
// You can change the popup title, message and buttons here
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(isCableConnected ? "Cable was connected" : "Cable was disconnected");
builder.setMessage("foo bar");
builder.setPositiveButton("OK", null);
builder.setNegativeButton(null, null);
builder.create().show();
}
return super.onOptionsItemSelected(item);
}
private void cableStateWasChanged(boolean isConnected) {
isCableConnected = isConnected;
cableStateChanged = true;
popupShown = false;
invalidateOptionsMenu();
}
Also I suggest you to use Handler instead of TimerTask, see this post
I can't figure out why my onClick method for my buttons are not working. Everytime I click the button, my logcat says ViewPostImeInputStage Action_Down.
I appreciate any help!
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
BluetoothConnect fragment = new BluetoothConnect();
transaction.add(R.id.sample_content_fragment, fragment);
transaction.commit();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
And this is my fragment.
public class BluetoothConnect extends Fragment {
//For debugging purposes
private static final String TAG = "BluetoothConnect";
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
private static final int REQUEST_ENABLE_BT = 3;
//Main buttons
private Button shareButton;
private Button listenButton;
private TextView test;
/**
* Name of the connected device
*/
private String mConnectedDeviceName = null;
/**
* Local Bluetooth adapter
*/
private BluetoothAdapter mBluetoothAdapter = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
//Get local Bluetooth adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//If the adapter is null, then Bluetooth is not supported
if (mBluetoothAdapter == null) {
FragmentActivity activity = getActivity();
Toast.makeText(activity, "Bluetooth is not available", Toast.LENGTH_LONG).show();
activity.finish();
}
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_main, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
listenButton = (Button) view.findViewById(R.id.listen);
shareButton = (Button) view.findViewById(R.id.share);
test = (TextView) view.findViewById(R.id.test);
}
#Override
public void onStart() {
super.onStart();
//If BT is not on, request that it be enabled
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
} else {
setupButtons();
}
}
#Override
public void onDestroy() {
super.onDestroy();
//Figure out what to do if we need to destroy
}
#Override public void onResume() {
super.onResume();
//figure out what to do if person pauses out of app
}
public void setupButtons() {
Log.d(TAG, "setupButtons()");
//Initialize the music buttons
listenButton.setOnClickListener(new ButtonOnClickListener("listen"));
Log.d(TAG, "finished listenButton");
shareButton.setOnClickListener(new ButtonOnClickListener("share"));
}
private class ButtonOnClickListener implements View.OnClickListener {
String type;
public ButtonOnClickListener(String button) {
Log.d(TAG, this.type);
this.type = button;
}
public void onClick(View view) {
if (this.type == "listen") {
listenMusic();
} else {
shareMusic();
}
}
}
private void ensureDiscoverable() {
if (mBluetoothAdapter.getScanMode() !=
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
}
private void listenMusic() {
Log.d(TAG, "OMG ITS WORKING");
}
private void shareMusic() {
Log.d(TAG, "OMG ITS WORKING");
}
}
Thanks so much!
have a look here
https://stackoverflow.com/a/32016362/5281187
Wrap your layout over the one you already have
This worked when the Glass in on XE12, I have opened the solution after about 2 Months and now with XE17 the menu items are not shown when tapped on the Live card, instead the live card is disappearing.
I have updated the GDK, I have changed the code to support the latest GDK sneak peek version 2 changes according to this (https://developers.google.com/glass/release-notes#xe12)
This is the code
public class MenuActivity extends Activity {
private static final String TAG = MenuActivity.class.getSimpleName();
private VisionService.VisionBinder mVisionService;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (service instanceof VisionService.VisionBinder) {
mVisionService = (VisionService.VisionBinder) service;
openOptionsMenu();
}
// No need to keep the service bound.
unbindService(this);
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
};
private boolean mResumed;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindService(new Intent(this, VisionService.class), mConnection, 0);
}
#Override
protected void onResume() {
super.onResume();
mResumed = true;
openOptionsMenu();
}
#Override
protected void onPause() {
super.onPause();
mResumed = false;
}
#Override
public void openOptionsMenu() {
if (mResumed && mConnection != null) {
super.openOptionsMenu();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_send) {
mVisionService.requestWorkOrderCard();
finish();
return true;
} else if (id == R.id.action_refresh) {
mVisionService.requestTopWorkOrders();
finish();
return true;
} else if (id == R.id.action_finish) {
stopService(new Intent(this, VisionService.class));
finish();
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
#Override
public void onOptionsMenuClosed(Menu menu) {
super.onOptionsMenuClosed(menu);
}
}
This is the error I am getting
.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
And this Log(not error) too
Rebinding view with mis-matched type: com.google.glass.home.timeline.TimelineApiAdapter
It would be great if any body could help on this. Thank You
You need to change the way menu gets opened for XE 16 or 17. Below is my code that works:
public class MenuActivity extends Activity {
private boolean mAttachedToWindow;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
mAttachedToWindow = true;
openOptionsMenu();
}
#Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
mAttachedToWindow = false;
}
#Override
public void openOptionsMenu() {
if (mAttachedToWindow) {
super.openOptionsMenu();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
...
}
public class AppService extends Service {
private static final String TAG = "AppService";
private static final String LIVE_CARD_ID = "HelloGlass";
private AppDrawer mCallback;
private LiveCard mLiveCard;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mLiveCard == null) {
mLiveCard = new LiveCard(this, LIVE_CARD_ID);
mCallback = new AppDrawer(this);
mLiveCard.setDirectRenderingEnabled(true).getSurfaceHolder().addCallback(mCallback);
Intent menuIntent = new Intent(this, MenuActivity.class);
mLiveCard.setAction(PendingIntent.getActivity(this, 0, menuIntent, 0));
mLiveCard.publish(PublishMode.REVEAL);
}
return START_STICKY;
}
...
}
Also, the GDK samples Stopwatch and Timer (https://developers.google.com/glass/samples/gdk) have menu-related code that works perfectly well.
I have a trouble with getting Activity(Nullpointerexception) after that I have rotate screen and received callback from AsyncTask to update my views of the fragment. If I wont change orientation then everything is OK(but not all the time, sometimes this bug appears)
My main activity:
public class MainActivity extends SherlockFragmentActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pager_layout);
fm = getSupportFragmentManager();
fm.addOnBackStackChangedListener(this);
session = new SessionManager(getApplicationContext());
if (session.isAuthorizated()) {
disableTabs();
FragmentTransaction ft = fm.beginTransaction();
if (session.termsAndConditions()) {
ft.replace(android.R.id.content, new TermsAndConditionsFragment(), "terms-and-conditions").commit();
}
}
} else {
enableTabs();
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(actionBar.newTab().setText("Log in"), LoginFragment.class, null);
mTabsAdapter.addTab(actionBar.newTab().setText("Calculator"), CalculatorFragment.class, null);
}
}
That`s my fragment:
public class TermsAndConditionsFragment extends SherlockFragment implements OnClickListener, OnTouchListener, OnEditorActionListener, ValueSelectedListener, AsyncUpdateViewsListener {
private static final String TAG = "TermsAndConditionsFragment";
private TermsAndConditionsManager termsAndConditionsM;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prepareData();
}
public void prepareData() {
if (getSherlockActivity() == null)
Log.d(TAG, "Activity is null");
termsAndConditionsM = new TermsAndConditionsManager(getSherlockActivity().getApplicationContext());
termsAndConditions = termsAndConditionsM.getTermsAndConditions();
...
// some stuff
...
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = init(inflater, container);
return rootView;
}
private View init(LayoutInflater inflater, ViewGroup container) {
rootView = inflater.inflate(R.layout.fragment_terms_and_conditions, container, false);
//bla bla bla
return rootView;
}
public void updateTermsAndConditionsView() {
//update views here
}
#Override
public void onClick(View v) {
ft = fm.beginTransaction();
switch (v.getId()) {
case R.id.etHowMuch:
d = NumberPaymentsPickerFragment.newInstance(getSherlockActivity(), Integer.valueOf(howMuch.replace("£", "")), 0);
d.setValueSelectedListener(this);
d.show(getFragmentManager(), Const.HOW_MUCH);
break;
}
}
#Override
public void onValueSelected() {
Bundle args = new Bundle();
...
ExecuteServerTaskBackground task = new ExecuteServerTaskBackground(getSherlockActivity());
task.setAsyncUpdateViewsListener(this);
task.action = ServerAPI.GET_TERMS_AND_CONDITIONS;
task.args = args;
task.execute();
}
#Override
public void onUpdateViews() {
prepareData();
updateTermsAndConditionsView();
}
}
My AsyncTask with callback:
public class ExecuteServerTaskBackground extends AsyncTask<Void, Void, Void> {
private static final String TAG = "ExecuteServerTaskBackground";
Activity mActivity;
Context mContext;
private AsyncUpdateViewsListener callback;
public ExecuteServerTaskBackground(Activity activity) {
this.mActivity = activity;
this.mContext = activity.getApplicationContext();
}
public void setAsyncUpdateViewsListener(AsyncUpdateViewsListener listener) {
callback = listener;
}
#Override
protected Void doInBackground(Void... params) {
ServerAPI server = new ServerAPI(mContext);
if (!args.isEmpty())
msg = server.serverRequest(action, args);
else
msg = server.serverRequest(action, null);
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
callback.onUpdateViews();
}
}
Why does it behave so? How can I get activity correctly if I change orientation.
EDIT:
As I understand correctly nullpointer appears after orientation changed and asynctask executed due to wrong reference between asyctask and Activity. Recreated activity doesnt have this reference thats why when I receive callback I use wrong activity reference which isn`t exist anymore. But how can I save current activity reference?
EDIT:
I have decided to try realize my task throughout Service and that`s what I have done.
Activity:
public class MainFragment extends Fragment implements ServiceExecutorListener, OnClickListener {
private static final String TAG = MainFragment.class.getName();
Button btnSend, btnCheck;
TextView serviceStatus;
Intent intent;
Boolean bound = false;
ServiceConnection sConn;
RESTService service;
ProgressDialog pd = new ProgressDialog();
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
intent = new Intent(getActivity(), RESTService.class);
getActivity().startService(intent);
sConn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.d(TAG, "MainFragment onServiceConnected");
service = ((RESTService.MyBinder) binder).getService();
service.registerListener(MainFragment.this);
if (service.taskIsDone())
serviceStatus.setText(service.getResult());
bound = true;
}
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "MainFragment onServiceDisconnected");
bound = false;
}
};
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.main_fragment, container, false);
serviceStatus = (TextView) rootView.findViewById(R.id.tvServiceStatusValue);
btnSend = (Button) rootView.findViewById(R.id.btnSend);
btnCheck = (Button) rootView.findViewById(R.id.btnCheck);
btnSend.setOnClickListener(this);
btnCheck.setOnClickListener(this);
return rootView;
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnSend:
pd.show(getFragmentManager(), "ProgressDialog");
service.run(7);
service.run(2);
service.run(4);
break;
case R.id.btnCheck:
if (service != null)
serviceStatus.setText(String.valueOf(service.taskIsDone()) + service.getTasksCount());
break;
}
}
#Override
public void onStart() {
super.onStart();
Log.d(TAG, "Bind service");
getActivity().bindService(intent, sConn, 0);
}
#Override
public void onPause() {
super.onDestroy();
Log.d(TAG, "onDestroy: Unbind service");
if (!bound)
return;
getActivity().unbindService(sConn);
service.unregisterListener(this);
bound = false;
}
#Override
public void onComplete(String result) {
Log.d(TAG, "Task Completed");
pd.dismiss();
serviceStatus.setText(result);
}
}
Dialog:
public class ProgressDialog extends DialogFragment implements OnClickListener {
final String TAG = ProgressDialog.class.getName();
public Dialog onCreateDialog(Bundle savedInstanceState) {
setRetainInstance(true);
AlertDialog.Builder adb = new AlertDialog.Builder(getActivity())
.setTitle("Title!")
.setPositiveButton(R.string.yes, this)
.setNegativeButton(R.string.no, this)
.setNeutralButton(R.string.maybe, this)
.setCancelable(false)
.setMessage(R.string.message_text)
.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
return true;
}
});
return adb.create();
}
public void onClick(DialogInterface dialog, int which) {
int i = 0;
switch (which) {
case Dialog.BUTTON_POSITIVE:
i = R.string.yes;
break;
case Dialog.BUTTON_NEGATIVE:
i = R.string.no;
break;
case Dialog.BUTTON_NEUTRAL:
i = R.string.maybe;
break;
}
if (i > 0)
Log.d(TAG, "Dialog 2: " + getResources().getString(i));
}
public void onDismiss(DialogInterface dialog) {
Log.d(TAG, "Dialog 2: onDismiss");
// Fix to avoid simple dialog dismiss in orientation change
if ((getDialog() != null) && getRetainInstance())
getDialog().setDismissMessage(null);
super.onDestroyView();
}
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
Log.d(TAG, "Dialog 2: onCancel");
}
}
Service:
public class RESTService extends Service {
final String TAG = RESTService.class.getName();
MyBinder binder = new MyBinder();
ArrayList<ServiceExecutorListener> listeners = new ArrayList<ServiceExecutorListener>();
Handler h = new Handler();
RequestManager mRequest;
ExecutorService es;
Object obj;
int time;
StringBuilder builder;
String result = null;
public void onCreate() {
super.onCreate();
Log.d(TAG, "RESTService onCreate");
es = Executors.newFixedThreadPool(1);
obj = new Object();
builder = new StringBuilder();
}
public void run(int time) {
RunRequest rr = new RunRequest(time);
es.execute(rr);
}
class RunRequest implements Runnable {
int time;
public RunRequest(int time) {
this.time = time;
Log.d(TAG, "RunRequest create");
}
public void run() {
Log.d(TAG, "RunRequest start, time = " + time);
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Log.d(TAG, "RunRequest obj = " + obj.getClass());
} catch (NullPointerException e) {
Log.d(TAG, "RunRequest error, null pointer");
}
builder.append("result " + time + ", ");
result = builder.toString();
sendCallback();
}
}
private void sendCallback() {
h.post(new Runnable() {
#Override
public void run() {
for (ServiceExecutorListener listener : listeners)
listener.onComplete();
}
});
}
public boolean taskIsDone() {
if (result != null)
return true;
return false;
}
public String getResult() {
return result;
}
public void registerListener(ServiceExecutorListener listener) {
listeners.add(listener);
}
public void unregisterListener(ServiceExecutorListener listener) {
listeners.remove(listener);
}
public IBinder onBind(Intent intent) {
Log.d(TAG, "RESTService onBind");
return binder;
}
public boolean onUnbind(Intent intent) {
Log.d(TAG, "RESTService onUnbind");
return true;
}
public class MyBinder extends Binder {
public RESTService getService() {
return RESTService.this;
}
}
}
As you mention in your edit, the current Activity is destroyed and recreated on orientation change.
But how can I save current activity reference?
You shouldn't. The previous Activity is no longer valid. This will not only cause NPEs but also memory leaks because the AsyncTask might hold the reference to old Activity, maybe forever.
Solution is to use Loaders.