Unable to intercept ANR on all devices - android

I am trying to intercept ANR (Application Not Responding) in android devices. I am implementing FileObserver on /data/anr/traces.txt file and capture the logs.
I am able to read this file in Samsung Galaxy J7(Android 6.0.1) but not on other devices ex: Nexus 4 (Android 5) and Moto G5 plus (Android 7).
I want FileObserver to read traces.txt on all devices. Any help will be appreciated.
Following is my code:
public class MainActivity extends AppCompatActivity {
private FileObserver fileObs;
private File anrFile = new File("/data/anr/traces.txt");
private File newFile;
int count=0;
long epochTimeCurrent=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(Build.VERSION.SDK_INT >= 23){
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.INTERNET,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
100);
}
fileObs = new FileObserver("/data/anr") {
#Override
public void onEvent(int i, #Nullable String s) {
if(i == FileObserver.CLOSE_WRITE) {
if (anrFile.exists()) {
System.out.println("ANR file available");
//boolean read = anrFile.canRead();
if (count == 0) {
//Log.i("ANRTest", "Traces.text is available ? "+read);
epochTimeCurrent = System.currentTimeMillis();
Log.e("ANRTest", "System time in epoch : "+epochTimeCurrent);
readContent(anrFile);
} else if(count > 0) {
//Log.i("ANRTest", "Count increased : "+count);
}
}
else {
System.out.println("ANR file not available");
}
}
}
};
fileObs.startWatching();
//code to simulate ANR
final RelativeLayout cont = findViewById(R.id.container);
Button btn = findViewById(R.id.btn_anr);
final TextView textView = new TextView(this);
textView.setText("ANR");
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
System.out.println("Devtest : Inside onclick");
while (true) {
cont.addView(textView);
cont.removeView(textView);
}
//throw new ArrayIndexOutOfBoundsException();
//throw new RuntimeException("This is a crash");
}
});
}
public void readContent(File file) {
BufferedReader br = null;
FileReader fileReader;
String strLine = "";
try {
fileReader = new FileReader(file);
int pid = android.os.Process.myPid();
br = new BufferedReader(fileReader);
while( (strLine = br.readLine()) != null){
semusi.logger.Log.info(strLine);
//semusi.logger.Log.info("Hello there !");
//System.out.println(strLine);
if(strLine.contains("pid "+pid) && count==0) {
System.out.println("File content is : "+strLine);
long logTime = calcSubstring(strLine);
//semusi.logger.Log.info(strLine);
System.out.println("Log print time : "+logTime);
//1512364990000 and 1512364990670
if(logTime > epochTimeCurrent) {
//semusi.logger.Log.info(strLine);
if(strLine.contains("-- end")) {
}
}
count++;
}
}
fileReader.close();
br.close();
} catch (FileNotFoundException e) {
System.err.println("Unable to find the file: fileName");
} catch (IOException e) {
System.err.println("Unable to read the file: fileName");
}
}
public long calcSubstring(String rawStr) {
if(rawStr.contains("at")){
int index = rawStr.indexOf("2017");
//System.out.println("Index of 2017 is : "+index);
String dateSubs = rawStr.substring(index,index+19);
//System.out.println("Time substring : "+dateSubs);
//2017-12-04 10:42:28
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date gmt = null;
try {
gmt = formatter.parse(dateSubs);
} catch (ParseException e) {
e.printStackTrace();
}
long millisecondsSinceEpoch0 = gmt.getTime();
String asString = formatter.format(gmt);
System.out.println("Date after formatting : "+asString);
return millisecondsSinceEpoch0;
}
return 0;
}
}

Related

Android Toast did not show after open Gallery and pick image

I want to show Toast (or progress bar) when clicking on the button "btnSearchImg". If before upload image, button clicked say "first pick image from gallary" and if after upload image clicked say "waiting". the toast before uploading image work fine but after uploading didn't work fine! my entire Activity code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_by_image);
Toasty.Config.getInstance().setTextSize(15).apply();
mSharedPreferences = getSharedPreferences("PREFERENCE", Context.MODE_PRIVATE);
mEditor = mSharedPreferences.edit();
mEditor.putString(PREF_SKIP,null);
if(mSharedPreferences.contains(PREF_SKIP)){
Log.i("payment", "true");
} else {
try {
}catch (Exception e){
Toast.makeText(getApplicationContext(), "ERORR", Toast.LENGTH_LONG).show();
}
}
context = getApplicationContext();
pbImgRetrvialProccess = (ProgressBar)findViewById(R.id.pbImgRetrvialProccess);
tvPermissionLoadImg = (TextView)findViewById(R.id.tvPermissionLoadImg);
tvPermissionLoadImg.setTypeface(Base.getIranSansFont());
TextView tvSearchImageToolBarText = (TextView) findViewById(R.id.tvSearchImageToolBarText);
tvSearchImageToolBarText.setTypeface(Base.getIranSansFont());
ivGalleryImgLoad = (ImageView) findViewById(R.id.ivGalleryImgLoad);
btnSearchImgLoad = (Button) findViewById(R.id.btnSearchImgLoad);
btnSearchImg = (Button) findViewById(R.id.btnSearchImg);
btnSearchImgLoad.setOnClickListener(this);
btnSearchImg.setOnClickListener(this);
}
public StringBuilder uniformQuantization( File filePath ){...}
private StringBuilder chHistogram( Mat newImage ){...}
private void CopyAssets(String filename){...}
private void copyFile(InputStream in, OutputStream out) throws IOException {...}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnSearchImgLoad:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PICK_IMAGE);}
OpenGallery();
break;
case R.id.btnSearchImg:
Toasty.success(getBaseContext(), "Waiting...", Toast.LENGTH_LONG).show();
FindSimilarRequestedImage();
break;
}
}
private void OpenGallery() {
Intent gallery = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(gallery, PICK_IMAGE);
}
private void FindSimilarRequestedImage() {
if (ivGalleryImgLoad.getDrawable() != null) {
File loadedImageFilePath = new File(getRealPathFromURI(selectedImageUri));
queryFeatureX = uniformQuantization(loadedImageFilePath);
dateiLesenStringBuilder();
} else {
Toasty.error(getBaseContext(), "first pick image from gallary", Toast.LENGTH_LONG).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == PICK_IMAGE && data != null) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PICK_IMAGE);
} else {
selectedImageUri = data.getData();
ivGalleryImgLoad.setImageURI(selectedImageUri);
tvPermissionLoadImg.setVisibility(View.INVISIBLE);
}
}
}
private String getRealPathFromURI(Uri contentURI) {
String result;
Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null) { // Source is Dropbox or other similar local file path
result = contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
result = cursor.getString(idx);
cursor.close();
}
return result;
}
private void dateiLesenStringBuilder() {
FEATURE_PATH = context.getCacheDir().getPath() + "/" + FEATURE_NAME;
try {
FileOutputStream out = new FileOutputStream(FEATURE_PATH);
InputStream in = context.getAssets().open("coins/"+FEATURE_NAME);
byte[] buffer = new byte[1024];
int ch;
while ((ch = in.read(buffer)) > 0){
out.write(buffer, 0, ch);
}
out.flush();
out.close();
in.close();
}catch (Exception e){
System.out.println(e);
}
final File featureList = new File(FEATURE_PATH);
Runnable runner = new Runnable() {
BufferedReader in = null;
#Override
public void run() {
try {
String sCurrentLine;
int lines = 0;
BufferedReader newbw = new BufferedReader(new FileReader(featureList.getAbsolutePath()));
while (newbw.readLine() != null)
lines++;
in = new BufferedReader(new FileReader(featureList.getAbsolutePath()));
ArrayList<Double> nDistVal = new ArrayList<Double>();
ArrayList<String> nImagePath = new ArrayList<String>();
int count = 0;
while ((sCurrentLine = in.readLine()) != null) {
String[] featX = sCurrentLine.split(";")[1].split(" ");
nImagePath.add(sCurrentLine.split(";")[0]);
nDistVal.add(Distance.distL2(featX, queryFeatureX.toString().split(" ")));
count++;
}
ArrayList<Double> nstore = new ArrayList<Double>(nDistVal); // may need to be new ArrayList(nfit)
double maxDistVal = Collections.max(nDistVal);
Collections.sort(nDistVal);
sortedNImagePath = new ArrayList<String>();
for (int n = 0; n < nDistVal.size(); n++) {
int index = nstore.indexOf(nDistVal.get(n));
sortedNImagePath.add(nImagePath.get(index));
sortedNImageDistanceValues.add(String.valueOf(nDistVal.get(n) / maxDistVal));
String filePath = sortedNImagePath.get(0);
String minDistanceImg = sortedNImageDistanceValues.get(n);
FileNameFromPath = filePath.substring(filePath.lastIndexOf("/") + 1);
System.out.println("Distance values -> " + FileNameFromPath.toString());
System.out.println("Distance values -> " + minDistanceImg.toString());
}
} catch (Exception ex) {
String x = ex.getMessage();
System.out.println("ERORR" + x);
}
if (in != null) try {
in.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
Intent imgSearchedCoinNameIntent = new Intent(SearchByImageActivity.this, ImageSearchedCoinActivity.class);
imgSearchedCoinNameIntent.putExtra("imgSearchedCoinName", FileNameFromPath);
startActivity(imgSearchedCoinNameIntent);
}
}
};
Thread t = new Thread(runner, "Code Executer");
t.start();
}
}
If I put the "Waiting..." Toast after the FindSimilarRequestedImage() the toast will show up, but I need the toast show immediately after clicking on the btnSearchImg.
NOTE: Also in the dateiLesenStringBuilder() I removed the thread t that this part of code runs in normal flow and serial, but nothing changes!
Instead of toast use logcat to see if they run sequentially or not, maybe toast takes time to run
I solved this problem by putting the part of code in delay like below:
private void FindSimilarRequestedImage() {
if (ivGalleryImgLoad.getDrawable() != null) {
pbImgRetrvialProccess.setVisibility(View.VISIBLE);
Toasty.success(getBaseContext(), "Waiting ...", Toast.LENGTH_LONG).show();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
File loadedImageFilePath = new File(getRealPathFromURI(selectedImageUri));
queryFeatureX = uniformQuantization(loadedImageFilePath);
dateiLesenStringBuilder();
}
}, 5000);
} else {
Toasty.error(getBaseContext(), "first pick image from gallary", Toast.LENGTH_LONG).show();
}
}
Now before destroying activity throw functions, I first show the toast, then run other functions!

Save android logcat in a file on Android device

I want to write Android logcat in a file on my device.
To do that, I used the following code
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if(isExternalStorageWritable()){
File appDirectory = new File(Environment.getExternalStorageDirectory()+ "/MyAppfolder");
File logDirectory = new File(appDirectory + "/log");
File logFile = new File(logDirectory, "logcat"+System.currentTimeMillis()+".txt");
if(!appDirectory.exists()){
appDirectory.mkdir();
}
if(!logDirectory.exists()){
logDirectory.mkdir();
}
if(!logFile.exists()){
try {
logFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
Process process = Runtime.getRuntime().exec("logcat -f "+logFile);
}
}
}
catch (IOException e){
e.printStackTrace();
}
}
else if (isExternalStorageReadable()){
Log.i(TAG, "ONLY READABLE");
}
else{
Log.i(TAG, "NOT ACCESSIBLE");
}}
public boolean isExternalStorageReadable(){
String state = Environment.getExternalStorageState();
if(Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)){
return true;
}
return false;
}
public boolean isExternalStorageWritable(){
String state = Environment.getExternalStorageState();
if(Environment.MEDIA_MOUNTED.equals(state)){
return true;
}
return false;
}
And I added the permissions in AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
The folders and the file were created, but the file is always empty.
How can I improve the code so the logcat will be written in the file.
if(checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
else{
Process process = Runtime.getRuntime().exec("logcat -f "+logFile);
}
Your code is working perfectly may be, by mistake, You had written ask for permission & make log file both together
Maybe you are not writing the log to the file. You are missing this method.
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if ( Environment.MEDIA_MOUNTED.equals( state ) ) {
return true;
}
return false;
}
Your took code from the solution of this question Stack overflow question. Check it out.
It's my pleasure to answer your question.
In my project,I use this to solve the problem.
1.add this class
public class LogcatHelper {
private static LogcatHelper INSTANCE = null;
private static String PATH_LOGCAT;
private LogDumper mLogDumper = null;
private int mPId;
/**
* init data
*/
public void init(Context context) {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {// sd first
PATH_LOGCAT = Environment.getExternalStorageDirectory()
.getAbsolutePath() + File.separator + "logcat";
} else {
PATH_LOGCAT = context.getFilesDir().getAbsolutePath()
+ File.separator + "logcat";
}
File file = new File(PATH_LOGCAT);
if (!file.exists()) {
file.mkdirs();
}
}
public static LogcatHelper getInstance(Context context) {
if (INSTANCE == null) {
INSTANCE = new LogcatHelper(context);
}
return INSTANCE;
}
private LogcatHelper(Context context) {
init(context);
mPId = android.os.Process.myPid();
}
public void start() {
if (mLogDumper == null)
mLogDumper = new LogDumper(String.valueOf(mPId), PATH_LOGCAT);
mLogDumper.start();
}
public void stop() {
if (mLogDumper != null) {
mLogDumper.stopLogs();
mLogDumper = null;
}
}
private class LogDumper extends Thread {
private Process logcatProc;
private BufferedReader mReader = null;
private boolean mRunning = true;
String cmds = null;
private String mPID;
private FileOutputStream out = null;
public LogDumper(String pid, String dir) {
mPID = pid;
try {
out = new FileOutputStream(new File(dir, "logcat"
+ getFileName() + ".log"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
/**
*
* Level:*:v , *:d , *:w , *:e , *:f , *:s
*
*
* */
// cmds = "logcat *:e *:w | grep \"(" + mPID + ")\""; // print e level and ilevel info
// cmds = "logcat | grep \"(" + mPID + ")\"";// print all
// cmds = "logcat -s way";// print filter info
cmds = "logcat *:e *:i | grep \"(" + mPID + ")\"";
}
public void stopLogs() {
mRunning = false;
}
#Override
public void run() {
try {
logcatProc = Runtime.getRuntime().exec(cmds);
mReader = new BufferedReader(new InputStreamReader(
logcatProc.getInputStream()), 1024);
String line = null;
while (mRunning && (line = mReader.readLine()) != null) {
if (!mRunning) {
break;
}
if (line.length() == 0) {
continue;
}
if (out != null && line.contains(mPID)) {
out.write((getDateEN() + " " + line + "\n")
.getBytes());
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (logcatProc != null) {
logcatProc.destroy();
logcatProc = null;
}
if (mReader != null) {
try {
mReader.close();
mReader = null;
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
out = null;
}
}
}
}
public static String getFileName() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String date = format.format(new Date(System.currentTimeMillis()));
return date;
}
public static String getDateEN() {
SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1 = format1.format(new Date(System.currentTimeMillis()));
return date1;
}
}
add code in the Application class
LogcatHelper.getInstance((getApplicationContext())).start();
3.add permissions in the Application class
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
Process process = Runtime.getRuntime().exec("logcat -f "+logFile);
}
}
I hope I can help you.

Activity Memory Leak reported by LeakCanary - WindowManagerGlobal

There is a memory leak reported by LeakCanary in my Android App. I have Googled and studied for days and cannot find any solution. The leaked object is an instance of Activity called "MakeFire". It seems to be related to android.view.WindowManagerGlobal. Can anyone point out how the leak happened, and how to fix it?
Here is the LeakCanary ScreenCap
Here is the source code of the MakeFire Activity
public class MakeFire extends SharedMethod implements StatusBarFragment.OnFragmentInteractionListener,
DayTimeFragment.OnFragmentInteractionListener, BackButtonFragment.OnFragmentInteractionListener {
private Button firePlough;
private Button bowDrill;
private TextView makeFireWithBowDrillTime;
private TextView requirementTextview;
private Button performButton;
private String selectedButton;
private boolean firePloughOn;
private boolean bowDrillOn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_make_fire);
firePlough = (Button) findViewById(R.id.firePlough);
bowDrill = (Button) findViewById(R.id.bowDrill);
makeFireWithBowDrillTime = (TextView) findViewById(R.id.makeFireWithBowDrillTime);
requirementTextview = (TextView) findViewById(R.id.requirementTextview);
performButton = (Button) findViewById(R.id.performButton);
}
#Override
public void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = MyApplication.getRefWatcher(this);
refWatcher.watch(this);
}
#Override
public void onBackPressed() {
Bundle extra = new Bundle();
extra.putString("classToGoBack", getClass().getName());
Intent intent = new Intent(this, InGameMenu.class);
intent.putExtras(extra);
startActivity(intent);
}
#Override
public void onResume() {
super.onResume();
GameData.useImmersiveModeSticky(this);
}
#Override
public void onStop() {
super.onStop();
try {
//save on the latest save file
FileOutputStream latestSavedGame = openFileOutput("latestSavedGame", Context.MODE_PRIVATE);
ObjectOutputStream latestGameData = new ObjectOutputStream(latestSavedGame);
latestGameData.writeObject(GameData.GDI);
latestSavedGame.close();
} catch (Exception e) {
//TODO - delete it before uploading the app
GameData.GDI.showPlainMsg("sharedMethodProblem!", this);
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw, true);
e.printStackTrace(pw);
GameData.GDI.showPlainMsg(sw.getBuffer().toString(), this);
}
boolean savedGameIsFine;
try {
FileInputStream latestSavedGame = openFileInput("latestSavedGame");
ObjectInputStream latestGameData = new ObjectInputStream(latestSavedGame);
savedGameIsFine = (latestGameData.readObject() != null);
latestSavedGame.close();
} catch (Exception e) {
savedGameIsFine = false;
}
if (savedGameIsFine) {
try {
//save on the latest save file
FileOutputStream latestSavedGame = openFileOutput("latestSavedGameBackup", Context.MODE_PRIVATE);
ObjectOutputStream latestGameData = new ObjectOutputStream(latestSavedGame);
latestGameData.writeObject(GameData.GDI);
latestSavedGame.close();
} catch (Exception e) {
}
} else {
}
}
#Override
protected void onStart() {
super.onStart();
updateAllViews();
requirementTextview.setVisibility(View.INVISIBLE);
performButton.setVisibility(View.INVISIBLE);
}
//method for updating all amendable views in the page
private void updateAllViews() {
//visibility of fire plough button
if (GameData.GDI.anyThisInventoryAvailable(GameData.FIRE_PLOUGH) &&
GameData.GDI.anyThisInventoryAvailable(GameData.TINDER) &&
(!GameData.GDI.stormOn || GameData.GDI.currentLocation.campfireWindBlock)
) {
firePlough.setCompoundDrawablesWithIntrinsicBounds(0,R.drawable.ic_fireplow_3_f,0,0);
firePlough.setTextColor(ContextCompat.getColor(this, R.color.buttonOnColour));
firePloughOn = true;
}
else {
firePlough.setCompoundDrawablesWithIntrinsicBounds(0,R.drawable.ic_fireplow_3_f_o,0,0);
firePlough.setTextColor(ContextCompat.getColor(this, R.color.buttonOffColour));
firePloughOn = false;
}
//visibility of bow drill button
if (GameData.GDI.bowDrillUnlocked) {
bowDrill.setVisibility(View.VISIBLE);
makeFireWithBowDrillTime.setVisibility(View.VISIBLE);
if (GameData.GDI.anyThisInventoryAvailable(GameData.BOW_DRILL) &&
GameData.GDI.anyThisInventoryAvailable(GameData.TINDER) &&
(!GameData.GDI.stormOn || GameData.GDI.currentLocation.campfireWindBlock)
) {
bowDrill.setCompoundDrawablesWithIntrinsicBounds(0,R.drawable.ic_bow_drill_3_f,0,0);
bowDrill.setTextColor(ContextCompat.getColor(this, R.color.buttonOnColour));
bowDrillOn = true;
}
else {
bowDrill.setCompoundDrawablesWithIntrinsicBounds(0,R.drawable.ic_bow_drill_3_f_o,0,0);
bowDrill.setTextColor(ContextCompat.getColor(this, R.color.buttonOffColour));
bowDrillOn = false;
}
}
updateStatusBarFragment();
updateDayTimeFragment();
}
public void makeFireWithFirePlough(View view) {
if (firePloughOn) {
performButton.setVisibility(View.VISIBLE);
}
else {
performButton.setVisibility(View.INVISIBLE);
}
requirementTextview.setVisibility(View.VISIBLE);
requirementTextview.setText(R.string.makeFireWithFirePloughRqm);
selectedButton = "fire plough";
}
public void makeFireWithBowDrill(View view) {
if (bowDrillOn) {
performButton.setVisibility(View.VISIBLE);
}
else {
performButton.setVisibility(View.INVISIBLE);
}
requirementTextview.setVisibility(View.VISIBLE);
requirementTextview.setText(R.string.makeFireWithBowDrillRqm);
selectedButton = "bow drill";
}
public void perform(View view){
if (!GameData.GDI.stormOn || GameData.GDI.currentLocation.campfireWindBlock){
switch (selectedButton){
case "fire plough":
String msgToShow = "";
String extraInfo = "";
String[] timePassMsg;
Bundle extras = new Bundle();
//timepass method must run before the fireToLast method
timePassMsg = GameData.GDI.timePass(30, 1, 1, 1, this);
if (GameData.GDI.anyThisInventoryInBackpack(GameData.TINDER)) {
GameData.GDI.setInventoryAmount(GameData.TINDER, true, -1);
}
else {
GameData.GDI.setInventoryAmount(GameData.TINDER, false, -1);
}
extras.putString("toolUsed", getString(R.string.usedTinderMsg));
//update tool durability
GameData.GDI.firePloughDurability = GameData.GDI.updateInventoryDurability(GameData.FIRE_PLOUGH, GameData.GDI.firePloughDurability, GameData.FIRE_PLOUGH_MAX_DURABILITY);
//Because in GameCamp.updateInventoryDurability, if the tool broke, it will reset the durability to its maxDurability;
//so if these 2 numbers equal, the tool just broke
if (GameData.GDI.firePloughDurability == GameData.FIRE_PLOUGH_MAX_DURABILITY) {
extraInfo += getString(R.string.firePloughBreakMsg) + "\n\n";
}
GameData.GDI.bowDrillUnlockCounter += 1;
if (Math.random() < 0.75) {
GameData.GDI.currentLocation.fireOn = true;
GameData.GDI.currentLocation.fireToLast += 10;
msgToShow += getString(R.string.success) + "\n";
extras.putString("className", "Fire");
}
else {
msgToShow += getString(R.string.fail) + "\n";
if (!GameData.GDI.bowDrillUnlocked) {
if (GameData.GDI.bowDrillUnlockCounter >= 3) {
extraInfo += getString(R.string.bowDrillUnlockMsg) + "\n\n";
GameData.GDI.bowDrillUnlocked = true;
GameData.GDI.setCraftingAlertIcon(3);
}
}
extras.putString("className", "Make Fire");
}
Intent intent = new Intent(this, LoadingPage.class);
extras.putString("actionName", getString(R.string.makingFireWithFirePlough));
extras.putInt("timeNeeded", 30);
extras.putString("msgToShow", msgToShow);
extras.putString("extraInfo", extraInfo);
extras.putString("timePassMsg", timePassMsg[0]);
extras.putString("deathReason", timePassMsg[1]);
intent.putExtras(extras);
startActivity(intent);
break;
case "bow drill":
String msgToShow1 = "";
String extraInfo1 = "";
String[] timePassMsg1;
Bundle extras1 = new Bundle();
//timepass method must run before the fireToLast method
timePassMsg1 = GameData.GDI.timePass(10, 1, 1, 1, this);
if (GameData.GDI.anyThisInventoryInBackpack(GameData.TINDER)) {
GameData.GDI.setInventoryAmount(GameData.TINDER, true, -1);
}
else {
GameData.GDI.setInventoryAmount(GameData.TINDER, false, -1);
}
extras1.putString("toolUsed", getString(R.string.usedTinderMsg));
//update tool durability
GameData.GDI.bowDrillDurability = GameData.GDI.updateInventoryDurability(GameData.BOW_DRILL, GameData.GDI.bowDrillDurability, GameData.BOW_DRILL_MAX_DURABILITY);
//Because in GameCamp.updateInventoryDurability, if the tool broke, it will reset the durability to its maxDurability;
//so if these 2 numbers equal, the tool just broke
if (GameData.GDI.bowDrillDurability == GameData.BOW_DRILL_MAX_DURABILITY) {
extraInfo1 += getString(R.string.bowDrillBreakMsg) + "\n\n";
}
if (Math.random() < 0.95) {
GameData.GDI.currentLocation.fireOn = true;
GameData.GDI.currentLocation.fireToLast += 10;
msgToShow1 += getString(R.string.success) + "\n";
extras1.putString("className", "Fire");
}
else {
msgToShow1 += getString(R.string.fail) + "\n";
extras1.putString("className", "Make Fire");
}
Intent intent1 = new Intent(this, LoadingPage.class);
extras1.putString("actionName", getString(R.string.makingFireWithBowDrill));
extras1.putString("className", "Fire");
extras1.putInt("timeNeeded", 10);
extras1.putString("msgToShow", msgToShow1);
extras1.putString("extraInfo", extraInfo1);
extras1.putString("timePassMsg", timePassMsg1[0]);
extras1.putString("deathReason", timePassMsg1[1]);
intent1.putExtras(extras1);
startActivity(intent1);
break;
}
}
else {
GameData.GDI.showPlainMsg(getString(R.string.cannotMakeFireInStormMsg), this);
}
}
//fragment method
public void updateStatusBarFragment() {
StatusBarFragment statusBarFragment = (StatusBarFragment)getSupportFragmentManager().findFragmentById(R.id.statusBarFragment);
statusBarFragment.updateStatusBar();
}
public void updateDayTimeFragment() {
DayTimeFragment dayTimeFragment = (DayTimeFragment)getSupportFragmentManager().findFragmentById(R.id.dayTimeFragment);
dayTimeFragment.updateDayTimeView();
}
public void backButton(View view){
Intent intent = new Intent(this, Fire.class);
startActivity(intent);
}
}

For background download should i use service?

i'm developing my first Android app and i created a class (not Activity) that downloads a JSON file and writes content to SQLite database at every start-up of the application.
I then use an instance of this class in the main activity class.
If the download takes few seconds the home page of my app hangs on a blank screen.
Do you think i should use service instead of a class to handle download and writing of the db?
Could it be a good idea? If it could, what are the advantages?
If you are writing to a database I would recommend using an IntentService
The intent service runs in it's own thread.
When the download is complete you can use LocalBroadcastManager to notify the activity.
It could also work with ContentProvider and Loaders.
I also wanted to download the list of images in background so I used Services with SharedPreferences and I also Used AQuery With the Service.Here the ConnectionDetector is my Java class which checks the Internet Connection is available or not. It works for me. I hope it will give u some help.
public class MyService extends Service {
String f;
String path;
File file;
Bitmap bm;
String url1;
ArrayList<String> url_img;
AQuery aq;
int count = 1;
String val;
ArrayList<String> completed_url_list;
ArrayList<Integer> _index;
FileOutputStream out;
static ArrayList<String> list;
private Thread updateTask = new Thread(new Runnable() {
#Override
public void run() {
while (count < url_img.size()) {
try {
Log.e("Counter", "" + count);
val = url_img.get(count).toString();
final AjaxCallback<Bitmap> cb = new AjaxCallback<Bitmap>() {
#Override
public void callback(String url, Bitmap bm,
AjaxStatus status) {
try {
System.out.println("url is" + url);
String urll = url.substring(url
.lastIndexOf("/") + 1);
Log.e("Image name", "" + urll);
System.out.println("url111" + urll);
File f = new File(path + urll);
f.createNewFile();
System.out.println(f.getAbsolutePath());
try {
out = new FileOutputStream(f);
bm.compress(Bitmap.CompressFormat.JPEG, 40,
out);
if (out != null) {
out.flush();
out.close();
Log.e("download", "Complete");
completed_url_list.add(url);
System.out
.println("Completed Dowmload Image"
+ completed_url_list);
}
} catch (Exception e) {
boolean del_file = f.delete();
if (del_file == true){
Log.e("File", "deleted");
System.out.println("exception");
}
else{
System.out.println("file not deleted");
}
} finally {
out.close();
if (bm != null) {
bm.recycle();
bm = null;
}
System.gc();
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
} catch (Exception e) {
}
}
};
final AQuery aq = new AQuery(getApplicationContext());
aq.ajax(val, Bitmap.class, 0, cb);
} catch (Exception e) {
}
count++;
}
}
});
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
url_img = getArrayList();
completed_url_list = new ArrayList<String>();
_index = new ArrayList<Integer>();
aq = new AQuery(MyService.this);
System.out.println("I am in super");
if (url_img.size() > 0) {
updateTask.start();
}
} catch (Exception e) {
e.printStackTrace();
}
return START_STICKY;
}
#Override
public void onCreate() {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
super.onCreate();
try {
System.out.println("Service Creating");
f = Environment.getExternalStorageDirectory().getAbsolutePath();
path = f + "/HRI3mages/";
file = new File(path);
if (!file.exists()) {
file.mkdir();
}
} catch (Exception e) {
}
}
#Override
public void onDestroy() {
try {
for (int index = 0; index < completed_url_list.size(); index++) {
for (int index1 = 0; index1 < url_img.size(); index1++) {
if (completed_url_list.get(index).equals(
url_img.get(index1))) {
_index.add(index1);
}
}
}
Collections.sort(_index, new MyIntComparable());
System.out.println("next_download" + _index);
for(int index=0;index<_index.size();index++){
url_img.remove(index);
}
System.out.println("After_Deletion_of_Image"+url_img);
_addArray(url_img);
updateTask.interrupt();
} catch (Exception e) {
}
System.out.println("Service destroy");
super.onDestroy();
}
public class MyIntComparable implements Comparator<Integer>{
#Override
public int compare(Integer o1, Integer o2) {
return (o1>o2 ? -1 : (o1==o2 ? 0 : 1));
}
}
public ArrayList<String> getArrayList() {
ArrayList<String> list_url = new ArrayList<String>();
SharedPreferences SharedPref = getSharedPreferences("SSO", MODE_PRIVATE);
int size = SharedPref.getInt("list_size", 0);
for (int i = 0; i < size; i++) {
list_url.add(SharedPref.getString("list_" + i, ""));
}
System.out.println(list_url);
return list_url;
}
public void _addArray(ArrayList<String> list) {
SharedPreferences SharedPref = getSharedPreferences("SSO", 0);
SharedPreferences.Editor editor = SharedPref.edit();
int size = list.size();
editor.putInt("list_size", size);
for (int i = 0; i < size; i++) {
editor.putString("list_" + i, list.get(i));
}
editor.commit();
}
}
You might want to use an AsyncTask.
This will do the work in a background thread, so if it takes long your screen won't hang.
While the work is in progress, you can show a ProgressDialog (optional) to inform the user. You can also add a button to that ProgressDialog to cancel the task if needed.
See this: http://developer.android.com/intl/es/reference/android/os/AsyncTask.html
In this case I prefer an AsyncTask and not a Service so it seems easier and simpler to do what you want.
Good luck =)

android multithreading: thread.join() does not work as expected

I have trouble using thread.join in my code below. It should wait for the thread to finish before executing the codes after it, right? It was behaving differently on different occasions.
I have three cases to check if my code goes well
App is used for the first time - works as expected but the loading page don't appear while downloading
App is used the second time (db is up to date) - works okay
App is used the third time (db is outdated, must update) - won't update, screen blacks out, then crashes
I think I have problems with this code on onCreate method:
dropOldSchedule();
dropThread.join();
triggerDownload();
Based on the logs, the code works until before this part... What can be the problem?
MainActivity.java
public class MainActivity extends Activity {
final static int INDEX_ACCTTYPE = 0;
final static int INDEX_ECN = 1;
final static int INDEX_TLN = 2;
final static int INDEX_SIN = 3;
final static int INDEX_MOBILE = 4;
final static int INDEX_CITY = 5;
final static int INDEX_START_DATE = 6;
final static int INDEX_START_TIME = 7;
final static int INDEX_END_DATE = 8;
final static int INDEX_END_TIME = 9;
final static int INDEX_REASON = 10;
final static int INDEX_DETAILS = 11;
DatabaseHandler db;
String str;
ProgressDialog pd;
TextView homeText1, homeText2, homeText3, homeText4;
final private String csvFile = "http://www.meralco.com.ph/pdf/pms/pms_test.csv";
final private String uploadDateFile = "http://www.meralco.com.ph/pdf/pms/UploadDate_test.txt";
Thread dropThread = new Thread(new Runnable() {
public void run() {
db = new DatabaseHandler(MainActivity.this);
db.dropOldSchedule();
runOnUiThread(new Runnable() {
public void run() {
while (!pd.isShowing());
db.close();
pd.dismiss();
}
});
}
});
Thread getUploadDateThread = new Thread(new Runnable() {
public void run() {
try {
URL myURL = new URL(uploadDateFile);
BufferedReader so = new BufferedReader(new InputStreamReader(myURL.openStream()));
while (true) {
String output = so.readLine();
if (output != null) {
str = output;
}
else {
break;
}
}
so.close();
}
catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
while (!pd.isShowing());
pd.dismiss();
}
});
}
});
Thread downloadThread = new Thread(new Runnable() {
public void run() {
db = new DatabaseHandler(MainActivity.this);
db.beginTransaction();
try {
URL url = new URL(csvFile);
Log.i("dl", "start");
InputStream input = url.openStream();
CSVReader reader = new CSVReader(new InputStreamReader(input));
Log.i("dl", "after reading");
String [] sched;
while ((sched = reader.readNext()) != null) {
if(sched[INDEX_CITY].equals("")) sched[INDEX_CITY]="OTHERS";
try {
db.addRow(sched[INDEX_SIN], sched[INDEX_CITY],
sched[INDEX_START_DATE], sched[INDEX_START_TIME],
sched[INDEX_END_DATE], sched[INDEX_END_TIME],
sched[INDEX_DETAILS], sched[INDEX_REASON]);
} catch (IndexOutOfBoundsException e) {
db.addRow(sched[INDEX_SIN], sched[INDEX_CITY],
sched[INDEX_START_DATE], sched[INDEX_START_TIME],
sched[INDEX_END_DATE], sched[INDEX_END_TIME],
"", sched[INDEX_REASON]);
//e.printStackTrace();
}
}
input.close();
Log.i("dl", "finished");
} catch (MalformedURLException e) {
e.printStackTrace();
db.endTransaction();
} catch (IOException e) {
e.printStackTrace();
db.endTransaction();
}
Log.d("Count", ""+db.count());
db.setTransactionSuccessful();
db.endTransaction();
writeUploadDateInTextFile();
}
});
#SuppressWarnings("unqualified-field-access")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pms_main);
Button home = (Button) findViewById(R.id.home);
home.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MeralcoSuite_TabletActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
});
homeText1 = (TextView) findViewById(R.id.home_text1);
homeText2 = (TextView) findViewById(R.id.home_text2);
homeText3 = (TextView) findViewById(R.id.home_text3);
homeText4 = (TextView) findViewById(R.id.home_text4);
homeText1.setVisibility(View.INVISIBLE);
homeText2.setVisibility(View.INVISIBLE);
homeText3.setVisibility(View.INVISIBLE);
homeText4.setVisibility(View.INVISIBLE);
getUploadDate();
try {
getUploadDateThread.join(); //wait for upload date
Log.d("getUploadDate","thread died, upload date=" + str);
if(dbExists()){
db = new DatabaseHandler(MainActivity.this);
Log.d("Count", "" + db.count());
db.close();
if(!uploadDateEqualsDateInFile()){
dropOldSchedule();
dropThread.join();
triggerDownload();
}
showDisclaimer();
Log.i("oncreate", "finished!");
return;
}
triggerDownload();
showDisclaimer();
Log.i("oncreate", "finished!");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void dropOldSchedule(){
if(pd!=null && pd.isShowing())
pd.setTitle("Getting upload date...");
else
pd = ProgressDialog.show(this, "Getting upload date",
"This may take a few minutes...", true, false);
dropThread.start();
}
public void triggerDownload() {
if (!checkInternet()) {
showAlert("An internet connection is required to perform an update, please check that you are connected to the internet");
return;
}
if(pd!=null && pd.isShowing())
pd.setTitle("Getting upload date...");
else
pd = ProgressDialog.show(this, "Getting upload date",
"This may take a few minutes...", true, false);
downloadThread.start();
}
public void getUploadDate() {
Log.d("getUploadDate", "getting upload date of schedule");
if(pd!=null && pd.isShowing())
pd.setTitle("Getting upload date...");
else
pd = ProgressDialog.show(this, "Getting upload date",
"This may take a few minutes...", true, false);
getUploadDateThread.start();
}
public void writeUploadDateInTextFile() {
Log.d("writeUploadDateTextFile", "writing:"+str);
try {
OutputStreamWriter out = new OutputStreamWriter(openFileOutput(
"update.txt", 0));
out.write(str);
out.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
public void showDisclaimer() {
Log.d("ShowDisclaimer", "showing disclaimer");
homeText3
.setText("..." + str
+ "...");
homeText1.setVisibility(View.VISIBLE);
homeText2.setVisibility(View.VISIBLE);
homeText3.setVisibility(View.VISIBLE);
homeText4.setVisibility(View.VISIBLE);
Log.d("showDisclaimer", "finished showing disclaimer");
}
public boolean uploadDateEqualsDateInFile() {
Log.d("uploadDateEqualsDateInFile","comparing schedule upload dates");
try {
String recordedDate = "";
InputStream instream = openFileInput("update.txt");
if (instream != null) { // if file the available for reading
Log.d("uploadDateEqualsDateInFile","update.txt found!");
InputStreamReader inputreader = new InputStreamReader(instream);
BufferedReader buffreader = new BufferedReader(inputreader);
String line = null;
while ((line = buffreader.readLine()) != null) {
recordedDate = line;
Log.d("uploadDateEqualsDateInFile","recorded:"+recordedDate);
}
Log.d("uploadDateEqualsDateInFile","last upload date: " + str + ", recorded:" +recordedDate);
if(str.equals(recordedDate)) return true;
return false;
}
Log.d("uploadDateEqualsDateInFile","update.txt is null!");
return false;
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
public boolean checkInternet() {
ConnectivityManager cm = (ConnectivityManager) this
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo infos[] = cm.getAllNetworkInfo();
for (NetworkInfo info : infos)
if (info.getState() == NetworkInfo.State.CONNECTED
|| info.getState() == NetworkInfo.State.CONNECTING) {
return true;
}
return false;
}
public boolean dbExists() {
File database=getApplicationContext().getDatabasePath(DatabaseHandler.DATABASE_NAME);
if (!database.exists()) {
Log.i("Database", "Not Found");
return false;
}
Log.i("Database", "Found");
return true;
}
#Override
protected void onDestroy() {
super.onDestroy();
if (db != null) {
db.close();
}
}
#Override
protected void onPause() {
super.onPause();
if (db != null) {
db.close();
}
}
}
Sorry but I couldn't find mistakes or problems in your code. But I would strongly recommend you to use AsyncTask for doing something in different thread. AsyncTask is very easy to use and I would say that it is one of the biggest advantages of java. I really miss it in obj-c.
http://labs.makemachine.net/2010/05/android-asynctask-example/
http://marakana.com/s/video_tutorial_android_application_development_asynctask_preferences_and_options_menu,257/index.html
check those links hope that will help you.
It was already mentioned that AsyncTask is the better alternative. However, it may be the case, that your call to join will throw InterruptedException. Try to use it like this:
while(getUploadDateThread.isRunning()){
try{
getUploadDateThread.join();
} catch (InterruptedException ie){}
}
// code after join
I think the problem that your facing is that you are blocking the UI thread when you call join in the onCreate() method. You should move this code into another thread which should execute in the background and once its done you can update the UI.
Here is a sample code:
final Thread t1 = new Thread();
final Thread t2 = new Thread();
t1.start();
t2.start();
new Thread(new Runnable() {
#Override
public void run() {
// Perform all your thread joins here.
try {
t1.join();
t2.join();
} catch (Exception e) {
// TODO: handle exception
}
// This thread wont move forward unless all your threads
// mentioned above are executed or timed out.
// ------ Update UI using this method
runOnUiThread(new Runnable() {
#Override
public void run() {
// Update UI code goes here
}
});
}
}).start();

Categories

Resources