2019/05/10

[java][kotlin][android] 第三方開發工具推薦

java語言的繁瑣一直是開發系統的一個惡夢,尤其是作為android系統的開發,無論是多執行序、http requests、json解析...,繁瑣的工作量真的會讓人發瘋 kotlin語言雖然提供了不少好用的語法糖來改進開發的速度,但是根植於java語言上的天性,還是不免會受到java的影響。

好在天無絕人之路,世界上還是有很多大神開發了好用的語法糖工具,能大大的降低工作量,以下介紹幾個常用的github專案:

kotlinx.coroutines
Kotlin官方提供的工具,有了它操作協程、多執行緒,不再是惡夢了

Fuel
有了它,從web api取得資料,除了方便簡單外,與到問題的情況大幅減少了

Kotson
有了它,Json的解析終於可以脫離繁重的工作了

以上!如果還有發現好用的工具,會隨時更新

2019/04/20

[java][kotlin] Thread 與 Runnable 的使用時機與說明

多執行緒 Thread 與 Runnable的使用一直以來不是很得要領
許多書上或網路上的說明都無法讓我完全理解
偶然的一篇文章,讓我豁然開朗,趕緊記錄下自己的理解與心得。

對java 與 kotlin來說要給其他執行續執行的程式必須單獨用一個class包裝起來
這句話的意思是,一定得是呼叫另一個class來執行多執行緒,而不是
在目前的class呼叫fun來執行多執行緒。

在這個認知的前提下,就可以很明確的區分Thread 與 Runnable的使用時機:

Thread:
Thread的用途是,class可以繼承Thread的時候也就是,請看程式碼:
  java
   public class test extends Thread
   {
     @Override
     public void run() 
     {
        super.run();
     }
   }

  kotiln
   public class ApiBase: Thread()
   {
     override fun run() 
     {
        super.run()
     }
   }

以上要執行多執行緒的程式全都寫到 run的方法裡,使用時只需要呼叫 .start()方法就好

Runnable:
Runnable的用途是,當class無法繼承Thread的時候,也就是class已經繼承了其他類別
請看程式碼:
  java
   public class test implements Runnable
   {
     @Override
     public void run() 
     {
        super.run();
     }
   }

  kotiln
   public class ApiBase: Runnable
   {
     override fun run() 
     {
        TODO("not implemented")
     }
   }

以上要執行多執行緒的程式除了都寫到 run的方法裡之外,在使用上還要特別注意的是
Runnable 畢竟只是一個介面,所以在使用上
還是必須掀起動一個Thread,再把Runnable丟入執行。
請看範例:
  java
   public class test implements Runnable
   {
     @Override
     public void run() 
     {
        super.run();
     }
   }

   public class test2
   {
     test ts1 = new test();
     Thread thr = new Thread(ts1);
     thr.start();
   }

  kotiln
   public class ApiBase: Runnable
   {
     override fun run() 
     {
        TODO("not implemented")
     }
   }

   public class test2
   {
     val ts1: test = test()
     val thr: Thread = Thread(ts1)
     thr.start()
   }

2019/04/16

[macOS] vim 常用命令

終端機理要編輯檔案時,vim是非常好用的工具,這裡紀錄常用的命令避免忘記

vim 命令分成兩種:鍵盤命令鍵、命令列指令

vim的啟動方式:

vim
啟動vim編輯器,同時顯示空白的新編輯畫面

vim 檔案名稱
啟動vim編輯器,並開啟指定的檔案

鍵盤命令鍵:

i 進入編輯模式,編輯模式下才可以修改檔案的內容

esc 取消指令或退出編輯模式

命令列指令:

:w 
存檔

:w 新檔案名稱 
另存新檔

:q 
不存檔直接退出vim

:wq 
存檔後退出vim

[Android Studio 3] adb 常用命令

這裡單純紀錄曾經使用過的命令,避免忘記

使用adb在手機外部超作(未shell進手機)

adb shell 登入目前唯一連接的手機

adb devices 查詢目前有連接的手機

adb pull /手機目錄位置/檔案名稱 /電腦目錄位置/ 把手機的檔案複製到電腦上
這個功能用最多的地方是在檢查sqlite的檔案,sqlite檔案位置:
/data/data/專案名稱/databases/sqlite file
檔案位置範例:/data/data/com.test.test1/databases/Data1.db3
完整命令範例:adb pull /data/data/com.test.test1/databases/Data1.db3 /Users/use/

手機內部操作(已shell進手機)

cd 目錄名稱 切換目錄

ls 顯示目前所在目錄的所有資料

exit 離開手機

2019/04/15

[Android Studio 3] ADB 登入emulator 模擬器 取得 ROOT權限

第一步
這是最重要的一步,建立模擬機時必須選擇不支援Play Stone的系統

 這個就不支援play stone可以放心的使用

 這個有支援play stone是沒辦法取得root權限的

第二步
模擬機開啟開發人員模式,並開啟USB偵錯

第三步
使用adb工具輸入命令開啟root權限
adb工具不必連線進入模擬器,只要確保當下只有模擬器啟動,沒有其他真實手機接入電腦就可以了

開啟root命令
先輸入 adb root
如果回傳 restarting adbd as root 代表成功
接者輸入 adb remount
就可以取得root權限登入模擬機了

2018/01/11

[C#] DateGridView 使用 ComboBox 與 DateTimePicker

這一篇主要是針對 https://nonfu.blogspot.tw/2017/12/c-dategridview-datetimepicker.html 所併發出來的想法與程式碼改進 主要就是讓 DataGridView 能使用 DateTimePicker 與 ComboBox 並改進不足之處。

最終完成的成果如下方的圖

程式碼如下:

public partial class DataGridViewEx:System.Windows.Forms.DataGridView
{
 private Point MyPoint;
 private Control parentCTL;
 private ComboBox dtCombo;
 private DateTimePicker dtPicker;

 /// 紀錄可編輯的欄位名稱
 private StringDictionary ColmmEdit;

 /// 紀錄要使用日期資料的欄位名稱
 private StringDictionary ColmmDate;

 /// 紀錄要使用的下拉欄位名稱
 private StringDictionary ColmmCombo;

 public DataGridViewEx() : base()
 {
  this.EditMode = DataGridViewEditMode.EditProgrammatically;
  if (!DesignMode)
  {
   MyPoint = new Point();
   ColmmEdit = new StringDictionary();
   ColmmDate = new StringDictionary();
   ColmmCombo = new StringDictionary();

   this.Disposed += DataGridViewEx_Disposed;
   this.CellClick += DataGridViewEx_CellClick;
   this.CellEnter += DataGridViewEx_CellClick;
   this.EditingControlShowing += DataGridViewEx_EditingControlShowing;

   FirstSetDataTimePicker();
   FirstSetComboBox();

   this.AllowUserToAddRows = true;
   this.AllowUserToDeleteRows = true;
   this.AllowUserToOrderColumns = false;
   this.AllowUserToResizeColumns = false;
   this.AllowUserToResizeRows = false;
  }
 }

 private void DataGridViewEx_Disposed(object sender, EventArgs e)
 {
  if (!DesignMode)
  {
   dtPicker.Dispose();
   dtCombo.Dispose();
  }
 }
       
 /// 設定可編輯的欄位
 public void SetColmmEditName(string NameValue)
 {
  if(!ColmmEdit.ContainsKey(NameValue))
  {
   ColmmEdit.Add(NameValue, NameValue); 
  }
 }

 /// 設定要使用DateTimePicker的欄位
 public void SetColmmDateName(string NameValue)
 {
  if (!ColmmDate.ContainsKey(NameValue))
  {
   ColmmDate.Add(NameValue, NameValue);
  }
 }

 /// 設定要使用ComboBox的欄位
 public void SetColmmComboName(string NameValue)
 {
  if (!ColmmCombo. ContainsKey(NameValue))
  {
   ColmmCombo.Add(NameValue, NameValue);
  }
 }

 /// 檢查欄位是否可以編輯
 private void DataGridViewEx_CellClick(object sender, DataGridViewCellEventArgs e)
 {
  if(this.Rows.Count>0)
  {
   if ((e.RowIndex> -1) && (e.ColumnIndex > -1))
   {
     if (ColmmEdit.ContainsKey(this.Columns[e.ColumnIndex].Name))
     {
      this.BeginEdit(true);
     }
     else
     {
      this.EndEdit();
     }
    }
    else
    {
     this.EndEdit();
    }
   }
  }

 /// 判斷是否使用DateTimePicker、ComboBox
 private void DataGridViewEx_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
 {
  if (this.Rows.Count > 0)
  {
   if (this.CurrentCell.RowIndex > -1 && this.CurrentCell.ColumnIndex > -1)
   {
    if (parentCTL == null)
    {
     parentCTL = e.Control.Parent;
     parentCTL.Controls.Add(dtPicker);
     parentCTL.Controls.Add(dtCombo);
    }
    MyPoint.X = e.Control.Location.X - e.Control.Margin.Left < 0 ? 0 : e.Control.Location.X - e.Control.Margin.Left;
    MyPoint.Y = e.Control.Location.Y - e.Control.Margin.Top < 0 ? 0 : e.Control.Location.Y - e.Control.Margin.Top;
                    
    if (ColmmDate.ContainsKey(this.Columns[this.CurrentCell.ColumnIndex].Name))
    {
     SetDataTimePickerView(ref e);
    }
    else
    {
     MyPoint.X = 0;
     MyPoint.Y = 0;
     dtPicker.Location = MyPoint;
     dtPicker.Visible = false;
    }

    if (ColmmCombo.ContainsKey(this.Columns[this.CurrentCell.ColumnIndex].Name))
    {
     SetComboBoxView(ref e);
    }
    else
    {
     MyPoint.X = 0;
     MyPoint.Y = 0;
     dtCombo.Location = MyPoint;
     dtCombo.Visible = false;
    }
   }
  }
 }

 private void FirstSetComboBox()
 {
  dtCombo = new ComboBox();
  dtCombo.Name = "ComboBox1";
  dtCombo.FlatStyle = FlatStyle.Flat;

  dtCombo.Font = this.AlternatingRowsDefaultCellStyle.Font;
  dtCombo.Visible = false;
  dtCombo.SelectedIndexChanged += new EventHandler(ComboBox1_SelectedIndexChanged);
 }

 private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
 {
  this.CurrentCell.Value = ((ComboBox)sender).SelectedItem;
 }

 /// 設定下拉選單內容
 public void SetComboData(string[] Value)
 {
  dtCombo.Items.Clear();
  dtCombo.Items.AddRange(Value);
 }

 private void SetComboBoxView(ref DataGridViewEditingControlShowingEventArgs e)
 {
  dtCombo.Size = this.CurrentCell.Size;
  dtCombo.Location = MyPoint;
  if (e.Control.Text != "")
  {
   dtCombo.SelectedItem = e.Control.Text;
  }
  else
  {
   dtCombo.SelectedIndex = -1;
  }          
  
  e.Control.Visible = false;
  dtCombo.Visible = true;
 }

 /// DateTimePicker的日期資料回寫欄位
 private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
 {
   this.CurrentCell.Value = ((DateTimePicker)sender).Value.ToString("yyyy/MM/dd");
 }

 private void FirstSetDataTimePicker()
 {
  dtPicker = new DateTimePicker();
  dtPicker.Name = "dateTimePicker1";
  dtPicker.Format = DateTimePickerFormat.Custom;
  dtPicker.CustomFormat = "yyyy/MM/dd";
  dtPicker.MinDate = DateTime.Parse("1920/01/01");
  dtPicker.CalendarFont = this.AlternatingRowsDefaultCellStyle.Font;
  dtPicker.Visible = false;
  dtPicker.ValueChanged += new EventHandler(dateTimePicker1_ValueChanged);
 }

 private void SetDataTimePickerView(ref DataGridViewEditingControlShowingEventArgs e)
 {
  dtPicker.Size = this.CurrentCell.Size;
  dtPicker.Location = MyPoint;
  dtPicker.MaxDate = DateTime.Now;
  if (e.Control.Text != "")
  {
   dtPicker.Value = DateTime.ParseExact(e.Control.Text, dtPicker.CustomFormat, null);
  }
  else
  {
   dtPicker.Value = DateTime.Now;
   this.CurrentCell.Value = dtPicker.Value.ToString("yyyy/MM/dd");
  }
  
   e.Control.Visible = false;
   dtPicker.Visible = true;
 }

}

2017/12/17

[C#] DateGridView 使用 DateTimePicker 輸入日期

使用DateGridView常常遇到需要輸入日期的情境,對使用者來說DateTimePicker是很直覺的輸入方式
但是原始的DateGridView並不支援DateTimePicker的使用,以往為了解決這個問題,我都是參考微軟
的這一篇 https://msdn.microsoft.com/zh-tw/library/7tas5c80.aspx 進行修改
最近看到這一篇 https://dotblogs.com.tw/danking/2014/11/13/147294 讓我興起改寫
DateGridView的想法。

對於改寫控制項還不是很了解要如何使用在專案的人,可以參考我的另一篇文https://nonfu.blogspot.tw/2017/11/c-checkbox.html

public partial class DataGridViewEx:System.Windows.Forms.DataGridView
{
  // 紀錄可編輯的欄位名稱
  private StringDictionary ColmmEdit;

  // 紀錄要使用日期資料的欄位名稱
  private StringDictionary ColmmDate;

  public DataGridViewEx() : base()
  {
    this.EditMode = DataGridViewEditMode.EditProgrammatically;
    if (!DesignMode)
    {
      ColmmEdit = new StringDictionary();
      ColmmDate = new StringDictionary();
      this.Disposed += DataGridViewEx_Disposed;
      this.CellClick += DataGridViewEx_CellClick;
      this.EditingControlShowing += DataGridViewEx_EditingControlShowing;          
     }
  }

  // 刪除資料清單
  private void DataGridViewEx_Disposed(object sender, EventArgs e)
  {
    if (!DesignMode)
    {
      ColmmEdit.Clear();
      ColmmDate.Clear();
    }
  }
       
  // 設定可編輯的欄位
  public void SetColmmEditName(string NameValue)
  {
    if(!ColmmEdit.ContainsKey(NameValue))
    {
      ColmmEdit.Add(NameValue, NameValue); 
    }
  }

  // 設定要使用DateTimePicker的欄位
  public void SetColmmDateName(string NameValue)
  {
    if (!ColmmDate.ContainsKey(NameValue))
    {
      ColmmDate.Add(NameValue, NameValue);
    }
  }

  // 檢查欄位是否可以編輯
  private void DataGridViewEx_CellClick(object sender, DataGridViewCellEventArgs e)
  {
    if ((e.RowIndex > -1) || (e.ColumnIndex > -1))
    {

      if (ColmmEdit.ContainsKey(this.Columns[e.ColumnIndex].Name))
      {
        this.BeginEdit(true);
      }
      else
      {
        this.EndEdit();
      }

    }
  }

  // DateTimePicker的日期資料回寫欄位
  private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
  {
    this .CurrentCell.Value = ((DateTimePicker)sender).Value.ToString("yyyy/MM/dd");
  }

  // 判斷是否適用DateTimePicker的欄位
  private void DataGridViewEx_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
  {
    if (this.CurrentCell.ColumnIndex > -1)
    {
      Control parentCTL = e.Control.Parent;

      if(ColmmDate.ContainsKey(this.Columns[this.CurrentCell.ColumnIndex].Name))
      {
        DateTimePicker dtPicker = new DateTimePicker();
        dtPicker.Name = "dateTimePicker1";
        dtPicker.Size = this .CurrentCell.Size;
        dtPicker.Format = DateTimePickerFormat.Custom;
        dtPicker.CustomFormat = "yyyy/MM/dd";

        dtPicker.Location = new Point(
                                      e.Control.Location.X - e.Control.Margin.Left < 0 ? 0 : e.Control.Location.X - e.Control.Margin.Left,
                                      e.Control.Location.Y - e.Control.Margin.Top < 0 ? 0 : e.Control.Location.Y - e.Control.Margin.Top);

        if (e.Control.Text != "")
        {
          dtPicker.Value = DateTime.ParseExact(e.Control.Text, dtPicker.CustomFormat, null);
        }
        else
        {
          dtPicker.Value = DateTime.Now;
          this.CurrentCell.Value = dtPicker.Value.ToString("yyyy/MM/dd");
        }

        e.Control.Visible = false;

        foreach (Control tmpCTL in parentCTL.Controls)
        {
          if (tmpCTL.Name == dtPicker.Name) parentCTL.Controls.Remove(tmpCTL);
        }

        parentCTL.Controls.Add(dtPicker);
        dtPicker.ValueChanged += new EventHandler(dateTimePicker1_ValueChanged);              
      }
      else
      {
        foreach (Control tmpCTL in parentCTL.Controls)
        {
          if (tmpCTL.Name == "dateTimePicker1")
          {
           parentCTL.Controls.Remove(tmpCTL);
          }
        }
      }
    }
  }
}