Finish activity when onPostExecute is called (in AsyncTask) - android-asynctask

I use the GMS Drive sample demo.
I want to select a file (with Drive dialog open file), download the file, then finish the activity.
My problem is if I use finish() in the onActivityResult, I cannot get the result in my main activity, if I use finish() in the onPostExecute, the dialog is not closed, and I need to press "Cancel" to return to my main activity (with the result). I would like to return without pressing "cancel" button...
I use the RetrieveContentsActivity and PickFileWithOpenerActivity from the demo.
Here is my code :
public class RestoreActivity extends DriveActivity {
private static final int REQUEST_CODE_OPENER = 1;
#Override
public void onConnected(Bundle connectionHint) {
super.onConnected(connectionHint);
IntentSender intentSender = Drive.DriveApi
.newOpenFileActivityBuilder()
.setSelectionFilter(Filters.contains(SearchableField.TITLE, "settings"))
.build(getGoogleApiClient());
try {
startIntentSenderForResult(intentSender, REQUEST_CODE_OPENER, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
Log.w(TAG, "Unable to send intent", e);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_OPENER:
if (resultCode == RESULT_OK) {
DriveId driveId = data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
new RetrieveDriveFileContentsAsyncTask(RestoreActivity.this).execute(driveId);
}
finish(); // if I put finish() here, I cannot get the result in onActivityResult (main activity)
break;
default:
super.onActivityResult(requestCode, resultCode, data);
}
}
final private class RetrieveDriveFileContentsAsyncTask extends ApiClientAsyncTask<DriveId, Boolean, String> {
public RetrieveDriveFileContentsAsyncTask(Context context) {
super(context);
}
#Override
protected String doInBackgroundConnected(DriveId... params) {
String contents = null;
DriveFile file = Drive.DriveApi.getFile(getGoogleApiClient(), params[0]);
DriveApi.DriveContentsResult driveContentsResult = file.open(getGoogleApiClient(), DriveFile.MODE_READ_ONLY, null).await();
if (!driveContentsResult.getStatus().isSuccess()) {
return null;
}
DriveContents driveContents = driveContentsResult.getDriveContents();
BufferedReader reader = new BufferedReader(
new InputStreamReader(driveContents.getInputStream()));
StringBuilder builder = new StringBuilder();
String line;
try {
while ((line = reader.readLine()) != null) {
builder.append(line);
}
contents = builder.toString();
} catch (IOException e) {
Log.e(TAG, "IOException while reading from the stream " + e.toString());
}
driveContents.discard(getGoogleApiClient());
return contents;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Intent returnIntent = new Intent();
returnIntent.putExtra("settings",result);
if (result == null) {
Log.w(TAG, "Error");
setResult(RESULT_CANCELED,returnIntent);
} else {
Log.i(TAG, "OK");
setResult(RESULT_OK,returnIntent);
}
// if I put finish() here nothing happens, and dialog is still opened till I press "Cancel" button
}
}
}
How can I return to the main activity after onPostExecute and stop intent DriveApi ?
Thanks

I found a solution that I don't like : make it in 2 steps.
pick the file using the PickFileActivity from demo, return the driveId by declaring it public in MainActivity (public static DriveId driveId) and changing code like this :
MainActivity.driveId = data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
move the AsyncTask in my MainActivity.
If someone find another solution ?

Related

How About onActivityResult when I want to read multiple file from storage

How About onActivityResult when I want to read multiple file form storage
In this xml form I have to take multiple image file by clicking different different button from the app external storage but their is a difficulties on ActivityResult override method calling , because it call automatically and can't be call multiple time for for different different button
It's working fine for single file picking and get image URI.
So how can I fix the ActivityResult override method for different different button in a single activity
public class Application_Form extends AppCompatActivity {
ActivityApplicationBinding binding;
boolean isOnlyImageAllowed = true;
private static final int PICK_PHOTO = 1958;
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityApplicationBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
//check user storage permission
int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
binding.form4.choosePropertyFile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent;
if (isOnlyImageAllowed) {
// only image can be selected
intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
} else {
// any type of files including image can be selected
intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("file/*");
}
startActivityForResult(intent, PICK_PHOTO);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == PICK_PHOTO) {
Uri imageUri = data.getData();
binding.form4.selectedPropertyFile.setText("" + imageUri.getLastPathSegment());
}
}
}
Taking a array to pick photo then check with if else statement by array index
public class Application_Form extends AppCompatActivity {
ActivityApplicationBinding binding;
boolean isOnlyImageAllowed = true;
private static int[] PICK_PHOTO={0,1,2,3,4,5} ;
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityApplicationBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
binding.appBar.title.setText("লাইসেন্সের জন্য আবেদন করুন");
binding.appBar.back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
//check user storage permission
int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
binding.form4.choosePropertyFile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent;
if (isOnlyImageAllowed) {
// only image can be selected
intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
} else {
// any type of files including image can be selected
intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("file/*");
}
startActivityForResult(intent, 0);
}
});
binding.form4.chooseBankCertificate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent;
if (isOnlyImageAllowed) {
// only image can be selected
intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
} else {
// any type of files including image can be selected
intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("file/*");
}
startActivityForResult(intent, 1);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == PICK_PHOTO[0]) {
Uri imageUri = data.getData();
binding.form4.selectedPropertyFile.setText("" + imageUri.getLastPathSegment());
}
if (resultCode == RESULT_OK && requestCode == PICK_PHOTO[1]) {
Uri imageUri = data.getData();
binding.form4.selectedBankCertificate.setText("" + imageUri.getLastPathSegment());
}
}
}

CountDownTimer behaves weird/different the second time i open its Activity

I have been spending way too many hours on this one. And i just dont get it.
What i want: I have a main Activity (lets call it 'Activity Main') from which i am calling a second Activity ('Activity Timer') that has a CountDownTimer. Upon starting "Activity Timer" i want a Countdown to start running; it is only supposed to play a sound when it finishes. There is also a 'Pause-Button' which pauses/resumes the Countdown. 'Activity Timer' sends back results to 'Activity Main' via Intent when a button is pressed (either 'Success' or 'Fail' - well, it's a game). I am back at 'Activity Main' and all just worked perfectly fine.
That is until i start 'Activity Timer' a second time (for the secound round): The Countdown starts but cannot be paused. It just keeps ticking, even though i cancel() the Countdown and finish() the 'Activity Timer'.
Here's the code:
Activity Timer
public class GameActivity extends AppCompatActivity {
long countdown_time;
Button button_fail, button_success;
ImageButton imgbtn_pause;
boolean cd_running = false;
boolean countdown_auto = true;
TextView textView_countdown;
private static CountDownTimer;
Vibrator vibrator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game_activity);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// Preferences
prefs = getSharedPreferences("shared_preferences", Context.MODE_PRIVATE);
// Intent
Intent i = getIntent();
countdown_time = i.getLongExtra("countdown_time", 60000);
// Assigning
button_fail = (Button) findViewById(R.id.btn_fail);
button_success = (Button) findViewById(R.id.btn_success);
textView_countdown = (TextView) findViewById(R.id.tv_countdown);
imgbtn_pause = (ImageButton) findViewById(R.id.imgbtn_pause);
button_fail.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (cd_running) {
countdown.cancel();
}
cd_running = false;
countdown = null;
Intent returnIntent = new Intent();
if (risk) {
returnIntent.putExtra("result", "-3");
} else {
returnIntent.putExtra("result", "0");
}
setResult(Activity.RESULT_OK, returnIntent);
finish();
}
});
button_success.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (cd_running) {
countdown.cancel();
}
cd_running = false;
countdown = null;
Intent returnIntent = new Intent();
setResult(Activity.RESULT_OK, returnIntent);
finish();
}
});
imgbtn_pause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (cd_running) {
countdown.cancel();
cd_running = false;
imgbtn_pause.setBackgroundResource(R.drawable.play_2);
} else {
startCountDownTimer();
imgbtn_risk.setVisibility(View.INVISIBLE);
imgbtn_pause.setBackgroundResource(R.drawable.pause_2);
}
}
});
private void startCountDownTimer() {
cd_running = true;
imgbtn_pause.setBackgroundResource(R.drawable.pause_2);
countdown = new CountDownTimer(countdown_time, 1000) {
public void onTick(long millisUntilFinished) {
countdown_time = millisUntilFinished;
textView_countdown.setText("" + millisUntilFinished / 1000);
}
public void onFinish() {
countdown.cancel();
countdown = null;
cd_running = false;
if (!mute) {
vibrator = (Vibrator) GameActivity.this.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(1000);
countdown_sound.start();
}
textView_countdown.setVisibility(View.INVISIBLE);
textView_gameOver.setVisibility(View.VISIBLE);
imgbtn_pause.setVisibility(View.INVISIBLE);
}
}.start();
}
The call from 'Activity Main':
#Override
public void onClick(View view) {
Intent i = new Intent(GameMenu.this, GameActivity.class);
i.putExtra("countdown_time", countdown_time);
startActivityForResult(i, 1);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if (resultCode == Activity.RESULT_OK) {
String result_string = data.getStringExtra("result");
int result_int = Integer.parseInt(data.getStringExtra("result"));
}
if (resultCode == Activity.RESULT_CANCELED) {
// No result
}
}

DisplayAlert With changing Text xamarin forms

I have a requirement where i have to show the status of the download on a DisplayAlert. But with changing text on it asynchronously.
How to achieve this?
DisplayAlert("Download Info", "Downloading.....", "Ok");
I want to show status like...
Connected to server
Downloading
Download Complete
Here is a simple "Dynamic Alert" for Forms and iOS using UIAlertController and Android using a DialogFragment and a Xamarin.Forms dependency service:
Dependency Interface:
public interface IDynamicAlert
{
void Show(string title, string message);
void Update(string message);
void Dismiss();
}
iOS IDynamicAlert Dependency Implementation:
public class DynamicAlert : IDynamicAlert
{
UIAlertController alert;
public void Show(string title, string message)
{
if (alert != null) throw new Exception("DynamicAlert already showing");
alert = UIAlertController.Create(title, message, UIAlertControllerStyle.Alert);
var rootVC = UIApplication.SharedApplication.Windows[0].RootViewController;
rootVC.PresentViewController(alert, true, () =>
{
});
}
public void Update(string message)
{
if (alert == null) throw new Exception("DynamicAlert is not showing, call Show first");
alert.Message = message;
}
public void Dismiss()
{
if (alert == null) throw new Exception("DynamicAlert is not showing, call Show first");
alert.DismissViewController(true, () =>
{
alert.Dispose();
alert = null;
});
}
}
Example Usage:
var alert = DependencyService.Get<IDynamicAlert>();
if (alert != null)
{
alert.Show("StackOverflow", "Starting your request...");
await Task.Delay(2000); // Do some work...
alert.Update("Your request is processing...");
await Task.Delay(2000); // Do some work...
alert.Update("Your request is complete...");
await Task.Delay(750);
alert.Dismiss();
}
else
{
throw new Exception("IDynamicAlert Dependency not found");
}
Output:
Android Version:
The android version consists of a couple of parts, a DialogFragment subclass and the IDynamicAlert implementation that uses the custom DialogFragment.
Android DialogFragment Subclass:
public class DynamicAlertDialogFragment : DialogFragment
{
AlertDialog alertDialog;
readonly Context context;
public static DynamicAlertDialogFragment Instance(Context context, string title, string message)
{
var fragment = new DynamicAlertDialogFragment(context);
Bundle bundle = new Bundle();
bundle.PutString("title", title);
bundle.PutString("message", message);
fragment.Arguments = bundle;
return fragment;
}
public DynamicAlertDialogFragment(Context context)
{
this.context = context;
}
public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
var title = Arguments.GetString("title");
var message = Arguments.GetString("message");
alertDialog = new AlertDialog.Builder(context)
.SetIcon(Android.Resource.Drawable.IcDialogInfo)
.SetTitle(title)
.SetMessage(message)
.Create();
return alertDialog;
}
public void SetMessage(string message)
{
(context as Activity).RunOnUiThread(() => { alertDialog.SetMessage(message);});
}
}
Android IDynamicAlert Dependency Implementation:
public class DynamicAlert : IDynamicAlert
{
const string FRAGMENT_TAG = "DynamicAlert_Fragment";
DynamicAlertDialogFragment fragment;
static FormsAppCompatActivity currentActivity;
public static FormsAppCompatActivity CurrentActivity { set { currentActivity = value; } }
public void Show(string title, string message)
{
if (currentActivity == null) throw new Exception("DynamicAlert.CurrentActivity needs assigned");
var fragMgr = currentActivity.FragmentManager;
var fragTransaction = fragMgr.BeginTransaction();
var previous = fragMgr.FindFragmentByTag(FRAGMENT_TAG);
if (previous != null)
{
fragTransaction.Remove(previous);
}
fragTransaction.DisallowAddToBackStack();
fragment = DynamicAlertDialogFragment.Instance(currentActivity, title, message);
fragment.Show(fragMgr, FRAGMENT_TAG);
}
public void Update(string message)
{
if (fragment == null) throw new Exception("DynamicAlert is not showing, call Show first");
fragment.SetMessage(message);
}
public void Dismiss()
{
if (fragment == null) throw new Exception("DynamicAlert is not showing, call Show first");
fragment.Dismiss();
fragment.Dispose();
fragment = null;
}
}
Android Init / Usage:
When creating the AlertDialog in the DialogFragment we need access to the current Activity and when using Xamarin.Forms, that is normally the MainActivity that is a FormsAppCompatActivity subclass. Thus you will need to initialize the DynamicAlert.CurrentActivity static property with this Activity in your MainActivity.OnCreate subclass:
Example:
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
////////////
DynamicAlert.CurrentActivity = this;
////////////
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
}
Android Output:

It takes a long time to load large data in recyclerview

I have 11 text files each containing 50-60 lines. I have read all the files and showed in the recyclerview. I used asynctask to track the progress through the progress bar. I have used log too to see the read lines. I have found that reading is taking short time but after reading, it takes 5-6 seconds to show data in the recyclerview. Why is this causing? What should i do to handle this? Why should i do if there are thousands of text files?
Codes reading files and binding
AsyncTask<Void,Void,Void> task = new AsyncTask<Void, Void, Void>() {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(GrammerDetails.this,
"Loading", "Please Wait for a while");
}
#Override
protected Void doInBackground(Void... voids) {
getFromFilesbagdhara(id,realm);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("first_bagdhara",false);
editor.apply();
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
inflateData(listGrammerItem);
progressDialog.dismiss();
}
}.execute();
private void getFromFilesbagdhara(String id, Realm realm) {
String directory = "Grammer/Bagdhara";
AssetManager man = getAssets();
BufferedReader reader = null;
try {
String[] files = man.list(directory);
for (int i =0;i<files.length;i++){
String fileName = files[i];
reader = new BufferedReader(
new InputStreamReader(getAssets().open(directory+"/" + fileName),
"UTF-8"));
String line;
Log.e("File",files[i]);
while ((line = reader.readLine()) != null) {
Log.e("line",line);
// String[] text = line.split(" ");
String a = line.substring(0,line.indexOf("(")-1);
String b = line.substring(line.indexOf("(")+1,line.indexOf(")"));
String wordOne = a;
// String dummyTwo = text[1];
String wordTwo = b; //dummyTwo.substring(1,dummyTwo.length()-1);
final ClassGrammerItem classGrammerItem = new ClassGrammerItem(wordOne,wordTwo,id);
listGrammerItem.add(classGrammerItem);
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
//log the exception
}
}
}
}
private void inflateData(RealmList<ClassGrammerItem> listGrammerItem) {
AdapterGrammerItem adapter = new AdapterGrammerItem(listGrammerItem, GrammerDetails.this);
recyclerView.setAdapter(adapter);
}
Adapter:
public class AdapterGrammerItem extends RecyclerView.Adapter<AdapterGrammerItem
.ViewHolderAdapterRecycler> {
RealmList<ClassGrammerItem> activityList = new RealmList<ClassGrammerItem>();
Context context;
private LayoutInflater layoutInflater;
public AdapterGrammerItem(RealmList<ClassGrammerItem> activityList, Context context) {
this.activityList = activityList;
this.context = context;
layoutInflater = LayoutInflater.from(context);
}
#Override
public AdapterGrammerItem.ViewHolderAdapterRecycler onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.recycler_grammer_item, parent, false);
AdapterGrammerItem.ViewHolderAdapterRecycler viewHolder = new AdapterGrammerItem.ViewHolderAdapterRecycler(view);
return viewHolder;
}
#Override
public void onBindViewHolder(AdapterGrammerItem.ViewHolderAdapterRecycler holder, int position) {
ClassGrammerItem currentItem = activityList.get(position);
holder.wordOne.setText(currentItem.getWordOne());
holder.wordTwo.setText(currentItem.getWordTwo());
}
#Override
public int getItemCount() {
return activityList.size();
}
public class ViewHolderAdapterRecycler extends RecyclerView.ViewHolder {
MyTextView wordOne, wordTwo;
public ViewHolderAdapterRecycler(View itemView) {
super(itemView);
wordOne = (MyTextView) itemView.findViewById(R.id.wordOne);
wordTwo = (MyTextView) itemView.findViewById(R.id.wordTwo);
}
}
}

WP7 Developpement : How to make the program wait until the end of an EventHandler?

When my view wants the value of LogoStation, it returns null because my program has not yet executed LoadStation_Completed.
I want my program waits that LoadStation_Completed is executed before continuing.
Thx
public class Infos
{
#region propriétés
private DataServiceCollection<SyndicObject> _infosStation;
public DataServiceCollection<SyndicObject> InfosStation
{
get
{
return _infosStation;
}
set
{
_infosStation = value;
}
}
#endregion
string nameStation;
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
private ImageSource _logoStation;
public ImageSource LogoStation
{
get
{
return _logoStation;
}
set
{
_logoStation = value;
NotifyPropertyChanged("LogoStation");
}
}
public Infos(string station)
{
nameStation = station;
getInfos();
}
public void getInfos()
{
SyndicationContext service = new SyndicationContext(new Uri("http://test/817bee9d-faf4-4680-9d05-e41c2c90ae5a/"));
IQueryable<SyndicObject> requete = (from objectSki in service.Objects
where objectSki.NOMSTATION == nameStation
select objectSki);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
InfosStation = new DataServiceCollection<SyndicObject>();
InfosStation.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(InfoStation_LoadCompleted);
InfosStation.LoadAsync(requete);
}
);
}
void InfoStation_LoadCompleted(object sender, LoadCompletedEventArgs e)
{
LogoStation = new BitmapImage(new Uri(#"http://test/upload/" + InfosStation[0].LOGO, UriKind.Absolute));
}
}
By using the property setter you are using NotifyPropertyChanged (correctly) to tell the UI bound to LogoStation that it has been updated. This should mean that the UI will display nothing initially and then the image when the load has completed.
Without seeing your view code what you have here looks correct - apart from the fact that your Infos class doesn't inherit from INotifyPropertyChanged. This means that the event never gets sent.
Update your class definition and you should be good to go.

Resources